tangled
alpha
login
or
join now
dunkirk.sh
/
dots
3
fork
atom
Kieran's opinionated (and probably slightly dumb) nix config
3
fork
atom
overview
issues
pulls
pipelines
chore: use flake
dunkirk.sh
2 months ago
6cb12136
18cbb1fc
verified
This commit was signed with the committer's
known signature
.
dunkirk.sh
SSH Key Fingerprint:
SHA256:DqcG0RXYExE26KiWo3VxJnsxswN1QNfTBvB+bdSpk80=
+443
-443
1 changed file
expand all
collapse all
unified
split
modules
home
system
shell.nix
+443
-443
modules/home/system/shell.nix
···
10
10
tangled = cfg.tangled;
11
11
12
12
tangled-setup = pkgs.writeShellScriptBin "tangled-setup" ''
13
13
-
set -euo pipefail
13
13
+
set -euo pipefail
14
14
15
15
-
# Defaults (configured by Nix)
16
16
-
PLC_ID="${tangled.plcId}"
17
17
-
GITHUB_USER="${tangled.githubUser}"
18
18
-
KNOT_HOST="${tangled.knotHost}"
19
19
-
BRANCH="${tangled.defaultBranch}"
20
20
-
FORCE=false
15
15
+
# Defaults (configured by Nix)
16
16
+
PLC_ID="${tangled.plcId}"
17
17
+
GITHUB_USER="${tangled.githubUser}"
18
18
+
KNOT_HOST="${tangled.knotHost}"
19
19
+
BRANCH="${tangled.defaultBranch}"
20
20
+
FORCE=false
21
21
22
22
-
usage() {
23
23
-
cat <<EOF
24
24
-
Usage: tangled-setup [OPTIONS]
22
22
+
usage() {
23
23
+
cat <<EOF
24
24
+
Usage: tangled-setup [OPTIONS]
25
25
26
26
-
Configure git remotes for tangled workflow.
27
27
-
Sets: origin → knot, github → GitHub
26
26
+
Configure git remotes for tangled workflow.
27
27
+
Sets: origin → knot, github → GitHub
28
28
29
29
-
Options:
30
30
-
--plc ID PLC ID (default: $PLC_ID)
31
31
-
--github-user USER GitHub username (default: $GITHUB_USER)
32
32
-
--knot HOST Knot host (default: $KNOT_HOST)
33
33
-
--branch BRANCH Default branch (default: $BRANCH)
34
34
-
-f, --force Overwrite existing remotes without checking
35
35
-
-h, --help Show this help
36
36
-
EOF
37
37
-
exit 0
38
38
-
}
29
29
+
Options:
30
30
+
--plc ID PLC ID (default: $PLC_ID)
31
31
+
--github-user USER GitHub username (default: $GITHUB_USER)
32
32
+
--knot HOST Knot host (default: $KNOT_HOST)
33
33
+
--branch BRANCH Default branch (default: $BRANCH)
34
34
+
-f, --force Overwrite existing remotes without checking
35
35
+
-h, --help Show this help
36
36
+
EOF
37
37
+
exit 0
38
38
+
}
39
39
40
40
-
while [[ $# -gt 0 ]]; do
41
41
-
case "$1" in
42
42
-
-h|--help) usage ;;
43
43
-
--plc) PLC_ID="$2"; shift 2 ;;
44
44
-
--github-user) GITHUB_USER="$2"; shift 2 ;;
45
45
-
--knot) KNOT_HOST="$2"; shift 2 ;;
46
46
-
--branch) BRANCH="$2"; shift 2 ;;
47
47
-
-f|--force) FORCE=true; shift ;;
48
48
-
-*) echo "Unknown option: $1" >&2; exit 1 ;;
49
49
-
*) shift ;;
50
50
-
esac
51
51
-
done
40
40
+
while [[ $# -gt 0 ]]; do
41
41
+
case "$1" in
42
42
+
-h|--help) usage ;;
43
43
+
--plc) PLC_ID="$2"; shift 2 ;;
44
44
+
--github-user) GITHUB_USER="$2"; shift 2 ;;
45
45
+
--knot) KNOT_HOST="$2"; shift 2 ;;
46
46
+
--branch) BRANCH="$2"; shift 2 ;;
47
47
+
-f|--force) FORCE=true; shift ;;
48
48
+
-*) echo "Unknown option: $1" >&2; exit 1 ;;
49
49
+
*) shift ;;
50
50
+
esac
51
51
+
done
52
52
53
53
-
if ! ${pkgs.git}/bin/git rev-parse --is-inside-work-tree &>/dev/null; then
54
54
-
echo "Error: Not a git repository" >&2
55
55
-
exit 1
56
56
-
fi
53
53
+
if ! ${pkgs.git}/bin/git rev-parse --is-inside-work-tree &>/dev/null; then
54
54
+
echo "Error: Not a git repository" >&2
55
55
+
exit 1
56
56
+
fi
57
57
58
58
-
repo_name=$(basename "$(${pkgs.git}/bin/git rev-parse --show-toplevel)")
59
59
-
knot_url="git@$KNOT_HOST:$PLC_ID/$repo_name"
60
60
-
github_url="git@github.com:$GITHUB_USER/$repo_name.git"
58
58
+
repo_name=$(basename "$(${pkgs.git}/bin/git rev-parse --show-toplevel)")
59
59
+
knot_url="git@$KNOT_HOST:$PLC_ID/$repo_name"
60
60
+
github_url="git@github.com:$GITHUB_USER/$repo_name.git"
61
61
62
62
-
echo "Configuring remotes for: $repo_name"
62
62
+
echo "Configuring remotes for: $repo_name"
63
63
64
64
-
# Configure origin → knot
65
65
-
current_origin=$(${pkgs.git}/bin/git remote get-url origin 2>/dev/null || true)
66
66
-
if [[ -z "$current_origin" ]]; then
67
67
-
${pkgs.git}/bin/git remote add origin "$knot_url"
68
68
-
echo "✓ origin → $knot_url"
69
69
-
elif [[ "$current_origin" == *"$KNOT_HOST"* ]]; then
70
70
-
echo "✓ origin → $current_origin (already knot)"
71
71
-
elif [[ "$FORCE" == true ]]; then
72
72
-
${pkgs.git}/bin/git remote set-url origin "$knot_url"
73
73
-
echo "✓ origin → $knot_url (was: $current_origin)"
74
74
-
else
75
75
-
echo "! origin → $current_origin (use -f to override)"
76
76
-
fi
64
64
+
# Configure origin → knot
65
65
+
current_origin=$(${pkgs.git}/bin/git remote get-url origin 2>/dev/null || true)
66
66
+
if [[ -z "$current_origin" ]]; then
67
67
+
${pkgs.git}/bin/git remote add origin "$knot_url"
68
68
+
echo "✓ origin → $knot_url"
69
69
+
elif [[ "$current_origin" == *"$KNOT_HOST"* ]]; then
70
70
+
echo "✓ origin → $current_origin (already knot)"
71
71
+
elif [[ "$FORCE" == true ]]; then
72
72
+
${pkgs.git}/bin/git remote set-url origin "$knot_url"
73
73
+
echo "✓ origin → $knot_url (was: $current_origin)"
74
74
+
else
75
75
+
echo "! origin → $current_origin (use -f to override)"
76
76
+
fi
77
77
78
78
-
# Configure github remote
79
79
-
current_github=$(${pkgs.git}/bin/git remote get-url github 2>/dev/null || true)
80
80
-
if [[ -z "$current_github" ]]; then
81
81
-
${pkgs.git}/bin/git remote add github "$github_url"
82
82
-
echo "✓ github → $github_url"
83
83
-
elif [[ "$FORCE" == true ]]; then
84
84
-
${pkgs.git}/bin/git remote set-url github "$github_url"
85
85
-
echo "✓ github → $github_url (was: $current_github)"
86
86
-
else
87
87
-
echo "✓ github → $current_github"
88
88
-
fi
78
78
+
# Configure github remote
79
79
+
current_github=$(${pkgs.git}/bin/git remote get-url github 2>/dev/null || true)
80
80
+
if [[ -z "$current_github" ]]; then
81
81
+
${pkgs.git}/bin/git remote add github "$github_url"
82
82
+
echo "✓ github → $github_url"
83
83
+
elif [[ "$FORCE" == true ]]; then
84
84
+
${pkgs.git}/bin/git remote set-url github "$github_url"
85
85
+
echo "✓ github → $github_url (was: $current_github)"
86
86
+
else
87
87
+
echo "✓ github → $current_github"
88
88
+
fi
89
89
90
90
-
# Set default push to origin
91
91
-
${pkgs.git}/bin/git config branch.$BRANCH.remote origin 2>/dev/null || true
90
90
+
# Set default push to origin
91
91
+
${pkgs.git}/bin/git config branch.$BRANCH.remote origin 2>/dev/null || true
92
92
93
93
-
echo
94
94
-
${pkgs.git}/bin/git remote -v
93
93
+
echo
94
94
+
${pkgs.git}/bin/git remote -v
95
95
'';
96
96
97
97
assh = pkgs.writeShellScriptBin "assh" ''
···
105
105
fi
106
106
107
107
${pkgs.gum}/bin/gum style --foreground 212 "Connecting to $host:$port (auto-reconnect enabled)..."
108
108
-
108
108
+
109
109
while true; do
110
110
${pkgs.openssh}/bin/ssh -p "$port" -o "BatchMode yes" "$host" || {
111
111
${pkgs.gum}/bin/gum style --foreground 214 "Connection lost. Reconnecting in 1s..."
···
207
207
'';
208
208
209
209
now = pkgs.writeShellScriptBin "now" ''
210
210
-
# Post AtProto status updates
211
211
-
message=""
212
212
-
prompt_message=true
210
210
+
# Post AtProto status updates
211
211
+
message=""
212
212
+
prompt_message=true
213
213
214
214
-
# Parse arguments
215
215
-
while [[ $# -gt 0 ]]; do
216
216
-
case "$1" in
217
217
-
-m|--message)
218
218
-
message="$2"
219
219
-
prompt_message=false
220
220
-
shift 2
221
221
-
;;
222
222
-
*)
223
223
-
${pkgs.gum}/bin/gum style --foreground 196 "Usage: now [-m|--message \"your message\"]"
214
214
+
# Parse arguments
215
215
+
while [[ $# -gt 0 ]]; do
216
216
+
case "$1" in
217
217
+
-m|--message)
218
218
+
message="$2"
219
219
+
prompt_message=false
220
220
+
shift 2
221
221
+
;;
222
222
+
*)
223
223
+
${pkgs.gum}/bin/gum style --foreground 196 "Usage: now [-m|--message \"your message\"]"
224
224
+
exit 1
225
225
+
;;
226
226
+
esac
227
227
+
done
228
228
+
229
229
+
# Load account information from agenix secrets
230
230
+
if [[ -f "/run/agenix/bluesky" ]]; then
231
231
+
source "/run/agenix/bluesky"
232
232
+
else
233
233
+
${pkgs.gum}/bin/gum style --foreground 196 "Error: Bluesky credentials file not found at /run/agenix/bluesky"
224
234
exit 1
225
225
-
;;
226
226
-
esac
227
227
-
done
235
235
+
fi
228
236
229
229
-
# Load account information from agenix secrets
230
230
-
if [[ -f "/run/agenix/bluesky" ]]; then
231
231
-
source "/run/agenix/bluesky"
232
232
-
else
233
233
-
${pkgs.gum}/bin/gum style --foreground 196 "Error: Bluesky credentials file not found at /run/agenix/bluesky"
234
234
-
exit 1
235
235
-
fi
237
237
+
# Prompt for message if none provided
238
238
+
if [[ "$prompt_message" = true ]]; then
239
239
+
message=$(${pkgs.gum}/bin/gum input --placeholder "What's happening?" --prompt "$ACCOUNT1 is: ")
240
240
+
if [[ -z "$message" ]]; then
241
241
+
${pkgs.gum}/bin/gum style --foreground 214 "No message provided. Aborting."
242
242
+
exit 1
243
243
+
fi
244
244
+
fi
236
245
237
237
-
# Prompt for message if none provided
238
238
-
if [[ "$prompt_message" = true ]]; then
239
239
-
message=$(${pkgs.gum}/bin/gum input --placeholder "What's happening?" --prompt "$ACCOUNT1 is: ")
240
240
-
if [[ -z "$message" ]]; then
241
241
-
${pkgs.gum}/bin/gum style --foreground 214 "No message provided. Aborting."
242
242
-
exit 1
243
243
-
fi
244
244
-
fi
246
246
+
${pkgs.gum}/bin/gum spin --spinner dot --title "Posting to Bluesky..." -- /bin/bash <<EOF
247
247
+
# Function to resolve DID to PDS endpoint
248
248
+
resolve_pds() {
249
249
+
local identifier="\$1"
250
250
+
local did=""
245
251
246
246
-
${pkgs.gum}/bin/gum spin --spinner dot --title "Posting to Bluesky..." -- /bin/bash <<EOF
247
247
-
# Function to resolve DID to PDS endpoint
248
248
-
resolve_pds() {
249
249
-
local identifier="\$1"
250
250
-
local did=""
252
252
+
# If identifier is a handle, resolve to DID first
253
253
+
if [[ ! "\$identifier" =~ ^did: ]]; then
254
254
+
# Try to resolve handle via DNS first, fallback to bsky.social
255
255
+
did=\$(${pkgs.curl}/bin/curl -sf "https://bsky.social/xrpc/com.atproto.identity.resolveHandle?handle=\$identifier" | ${pkgs.jq}/bin/jq -r '.did // empty')
256
256
+
if [[ -z "\$did" ]]; then
257
257
+
echo "Failed to resolve handle: \$identifier" >&2
258
258
+
return 1
259
259
+
fi
260
260
+
else
261
261
+
did="\$identifier"
262
262
+
fi
251
263
252
252
-
# If identifier is a handle, resolve to DID first
253
253
-
if [[ ! "\$identifier" =~ ^did: ]]; then
254
254
-
# Try to resolve handle via DNS first, fallback to bsky.social
255
255
-
did=\$(${pkgs.curl}/bin/curl -sf "https://bsky.social/xrpc/com.atproto.identity.resolveHandle?handle=\$identifier" | ${pkgs.jq}/bin/jq -r '.did // empty')
256
256
-
if [[ -z "\$did" ]]; then
257
257
-
echo "Failed to resolve handle: \$identifier" >&2
258
258
-
return 1
259
259
-
fi
260
260
-
else
261
261
-
did="\$identifier"
262
262
-
fi
264
264
+
# Resolve DID document
265
265
+
local pds_endpoint=""
266
266
+
if [[ "\$did" =~ ^did:plc: ]]; then
267
267
+
# Resolve via PLC directory
268
268
+
pds_endpoint=\$(${pkgs.curl}/bin/curl -sf "https://plc.directory/\$did" | ${pkgs.jq}/bin/jq -r '.service[] | select(.type == "AtprotoPersonalDataServer") | .serviceEndpoint' | head -n1)
269
269
+
elif [[ "\$did" =~ ^did:web: ]]; then
270
270
+
# Resolve via did:web
271
271
+
local domain="\''${did#did:web:}"
272
272
+
pds_endpoint=\$(${pkgs.curl}/bin/curl -sf "https://\$domain/.well-known/did.json" | ${pkgs.jq}/bin/jq -r '.service[] | select(.type == "AtprotoPersonalDataServer") | .serviceEndpoint' | head -n1)
273
273
+
else
274
274
+
echo "Unsupported DID method: \$did" >&2
275
275
+
return 1
276
276
+
fi
263
277
264
264
-
# Resolve DID document
265
265
-
local pds_endpoint=""
266
266
-
if [[ "\$did" =~ ^did:plc: ]]; then
267
267
-
# Resolve via PLC directory
268
268
-
pds_endpoint=\$(${pkgs.curl}/bin/curl -sf "https://plc.directory/\$did" | ${pkgs.jq}/bin/jq -r '.service[] | select(.type == "AtprotoPersonalDataServer") | .serviceEndpoint' | head -n1)
269
269
-
elif [[ "\$did" =~ ^did:web: ]]; then
270
270
-
# Resolve via did:web
271
271
-
local domain="\''${did#did:web:}"
272
272
-
pds_endpoint=\$(${pkgs.curl}/bin/curl -sf "https://\$domain/.well-known/did.json" | ${pkgs.jq}/bin/jq -r '.service[] | select(.type == "AtprotoPersonalDataServer") | .serviceEndpoint' | head -n1)
273
273
-
else
274
274
-
echo "Unsupported DID method: \$did" >&2
275
275
-
return 1
276
276
-
fi
278
278
+
if [[ -z "\$pds_endpoint" ]]; then
279
279
+
echo "Failed to resolve PDS endpoint for: \$did" >&2
280
280
+
return 1
281
281
+
fi
277
282
278
278
-
if [[ -z "\$pds_endpoint" ]]; then
279
279
-
echo "Failed to resolve PDS endpoint for: \$did" >&2
280
280
-
return 1
281
281
-
fi
283
283
+
echo "\$pds_endpoint"
284
284
+
}
282
285
283
283
-
echo "\$pds_endpoint"
284
284
-
}
286
286
+
# Resolve PDS endpoints for both accounts
287
287
+
account1_pds=\$(resolve_pds "$ACCOUNT1")
288
288
+
if [[ -z "\$account1_pds" ]]; then
289
289
+
echo "Failed to resolve PDS for $ACCOUNT1" >&2
290
290
+
exit 1
291
291
+
fi
285
292
286
286
-
# Resolve PDS endpoints for both accounts
287
287
-
account1_pds=\$(resolve_pds "$ACCOUNT1")
288
288
-
if [[ -z "\$account1_pds" ]]; then
289
289
-
echo "Failed to resolve PDS for $ACCOUNT1" >&2
290
290
-
exit 1
291
291
-
fi
293
293
+
account2_pds=\$(resolve_pds "$ACCOUNT2")
294
294
+
if [[ -z "\$account2_pds" ]]; then
295
295
+
echo "Failed to resolve PDS for $ACCOUNT2" >&2
296
296
+
exit 1
297
297
+
fi
292
298
293
293
-
account2_pds=\$(resolve_pds "$ACCOUNT2")
294
294
-
if [[ -z "\$account2_pds" ]]; then
295
295
-
echo "Failed to resolve PDS for $ACCOUNT2" >&2
296
296
-
exit 1
297
297
-
fi
299
299
+
# Generate JWT for ACCOUNT1
300
300
+
account1_response=\$(${pkgs.curl}/bin/curl -s -X POST \
301
301
+
-H "Content-Type: application/json" \
302
302
+
-d '{
303
303
+
"identifier": "'$ACCOUNT1'",
304
304
+
"password": "'$ACCOUNT1_PASSWORD'"
305
305
+
}' \
306
306
+
"\$account1_pds/xrpc/com.atproto.server.createSession")
298
307
299
299
-
# Generate JWT for ACCOUNT1
300
300
-
account1_response=\$(${pkgs.curl}/bin/curl -s -X POST \
301
301
-
-H "Content-Type: application/json" \
302
302
-
-d '{
303
303
-
"identifier": "'$ACCOUNT1'",
304
304
-
"password": "'$ACCOUNT1_PASSWORD'"
305
305
-
}' \
306
306
-
"\$account1_pds/xrpc/com.atproto.server.createSession")
308
308
+
account1_jwt=\$(echo "\$account1_response" | ${pkgs.jq}/bin/jq -r '.accessJwt')
309
309
+
account1_did=\$(echo "\$account1_response" | ${pkgs.jq}/bin/jq -r '.did')
307
310
308
308
-
account1_jwt=\$(echo "\$account1_response" | ${pkgs.jq}/bin/jq -r '.accessJwt')
309
309
-
account1_did=\$(echo "\$account1_response" | ${pkgs.jq}/bin/jq -r '.did')
311
311
+
if [[ -z "\$account1_jwt" || "\$account1_jwt" == "null" ]]; then
312
312
+
echo "Failed to authenticate account $ACCOUNT1" >&2
313
313
+
echo "Response: \$account1_response" >&2
314
314
+
exit 1
315
315
+
fi
310
316
311
311
-
if [[ -z "\$account1_jwt" || "\$account1_jwt" == "null" ]]; then
312
312
-
echo "Failed to authenticate account $ACCOUNT1" >&2
313
313
-
echo "Response: \$account1_response" >&2
314
314
-
exit 1
315
315
-
fi
317
317
+
# Generate JWT for ACCOUNT2
318
318
+
account2_response=\$(${pkgs.curl}/bin/curl -s -X POST \
319
319
+
-H "Content-Type: application/json" \
320
320
+
-d '{
321
321
+
"identifier": "'$ACCOUNT2'",
322
322
+
"password": "'$ACCOUNT2_PASSWORD'"
323
323
+
}' \
324
324
+
"\$account2_pds/xrpc/com.atproto.server.createSession")
316
325
317
317
-
# Generate JWT for ACCOUNT2
318
318
-
account2_response=\$(${pkgs.curl}/bin/curl -s -X POST \
319
319
-
-H "Content-Type: application/json" \
320
320
-
-d '{
321
321
-
"identifier": "'$ACCOUNT2'",
322
322
-
"password": "'$ACCOUNT2_PASSWORD'"
323
323
-
}' \
324
324
-
"\$account2_pds/xrpc/com.atproto.server.createSession")
326
326
+
account2_jwt=\$(echo "\$account2_response" | ${pkgs.jq}/bin/jq -r '.accessJwt')
327
327
+
account2_did=\$(echo "\$account2_response" | ${pkgs.jq}/bin/jq -r '.did')
325
328
326
326
-
account2_jwt=\$(echo "\$account2_response" | ${pkgs.jq}/bin/jq -r '.accessJwt')
327
327
-
account2_did=\$(echo "\$account2_response" | ${pkgs.jq}/bin/jq -r '.did')
329
329
+
if [[ -z "\$account2_jwt" || "\$account2_jwt" == "null" ]]; then
330
330
+
echo "Failed to authenticate account $ACCOUNT2" >&2
331
331
+
echo "Response: \$account2_response" >&2
332
332
+
exit 1
333
333
+
fi
328
334
329
329
-
if [[ -z "\$account2_jwt" || "\$account2_jwt" == "null" ]]; then
330
330
-
echo "Failed to authenticate account $ACCOUNT2" >&2
331
331
-
echo "Response: \$account2_response" >&2
332
332
-
exit 1
333
333
-
fi
335
335
+
# Post to ACCOUNT1 as a.status.updates
336
336
+
account1_post_response=\$(${pkgs.curl}/bin/curl -s -X POST \
337
337
+
-H "Content-Type: application/json" \
338
338
+
-H "Authorization: Bearer \$account1_jwt" \
339
339
+
-d '{
340
340
+
"collection": "a.status.update",
341
341
+
"repo": "'\$account1_did'",
342
342
+
"record": {
343
343
+
"\$type": "a.status.update",
344
344
+
"text": "'"$message"'",
345
345
+
"createdAt": "'\$(date -u +"%Y-%m-%dT%H:%M:%SZ")'"
346
346
+
}
347
347
+
}' \
348
348
+
"\$account1_pds/xrpc/com.atproto.repo.createRecord")
334
349
335
335
-
# Post to ACCOUNT1 as a.status.updates
336
336
-
account1_post_response=\$(${pkgs.curl}/bin/curl -s -X POST \
337
337
-
-H "Content-Type: application/json" \
338
338
-
-H "Authorization: Bearer \$account1_jwt" \
339
339
-
-d '{
340
340
-
"collection": "a.status.update",
341
341
-
"repo": "'\$account1_did'",
342
342
-
"record": {
343
343
-
"\$type": "a.status.update",
344
344
-
"text": "'"$message"'",
345
345
-
"createdAt": "'\$(date -u +"%Y-%m-%dT%H:%M:%SZ")'"
346
346
-
}
347
347
-
}' \
348
348
-
"\$account1_pds/xrpc/com.atproto.repo.createRecord")
349
349
-
350
350
-
if [[ \$(echo "\$account1_post_response" | ${pkgs.jq}/bin/jq -r 'has("error")') == "true" ]]; then
351
351
-
echo "Error posting to $ACCOUNT1:" >&2
352
352
-
echo "\$account1_post_response" | ${pkgs.jq}/bin/jq >&2
353
353
-
exit 1
354
354
-
fi
350
350
+
if [[ \$(echo "\$account1_post_response" | ${pkgs.jq}/bin/jq -r 'has("error")') == "true" ]]; then
351
351
+
echo "Error posting to $ACCOUNT1:" >&2
352
352
+
echo "\$account1_post_response" | ${pkgs.jq}/bin/jq >&2
353
353
+
exit 1
354
354
+
fi
355
355
356
356
-
# Post to ACCOUNT2 as normal post
357
357
-
account2_post_response=\$(${pkgs.curl}/bin/curl -s -X POST \
358
358
-
-H "Content-Type: application/json" \
359
359
-
-H "Authorization: Bearer \$account2_jwt" \
360
360
-
-d '{
361
361
-
"collection": "app.bsky.feed.post",
362
362
-
"repo": "'\$account2_did'",
363
363
-
"record": {
364
364
-
"\$type": "app.bsky.feed.post",
365
365
-
"text": "'"$message"'",
366
366
-
"createdAt": "'\$(date -u +"%Y-%m-%dT%H:%M:%SZ")'"
367
367
-
}
368
368
-
}' \
369
369
-
"\$account2_pds/xrpc/com.atproto.repo.createRecord")
356
356
+
# Post to ACCOUNT2 as normal post
357
357
+
account2_post_response=\$(${pkgs.curl}/bin/curl -s -X POST \
358
358
+
-H "Content-Type: application/json" \
359
359
+
-H "Authorization: Bearer \$account2_jwt" \
360
360
+
-d '{
361
361
+
"collection": "app.bsky.feed.post",
362
362
+
"repo": "'\$account2_did'",
363
363
+
"record": {
364
364
+
"\$type": "app.bsky.feed.post",
365
365
+
"text": "'"$message"'",
366
366
+
"createdAt": "'\$(date -u +"%Y-%m-%dT%H:%M:%SZ")'"
367
367
+
}
368
368
+
}' \
369
369
+
"\$account2_pds/xrpc/com.atproto.repo.createRecord")
370
370
371
371
-
if [[ \$(echo "\$account2_post_response" | ${pkgs.jq}/bin/jq -r 'has("error")') == "true" ]]; then
372
372
-
echo "Error posting to $ACCOUNT2:" >&2
373
373
-
echo "\$account2_post_response" | ${pkgs.jq}/bin/jq >&2
374
374
-
exit 1
375
375
-
fi
376
376
-
EOF
371
371
+
if [[ \$(echo "\$account2_post_response" | ${pkgs.jq}/bin/jq -r 'has("error")') == "true" ]]; then
372
372
+
echo "Error posting to $ACCOUNT2:" >&2
373
373
+
echo "\$account2_post_response" | ${pkgs.jq}/bin/jq >&2
374
374
+
exit 1
375
375
+
fi
376
376
+
EOF
377
377
378
378
-
if [[ $? -eq 0 ]]; then
379
379
-
${pkgs.gum}/bin/gum style --foreground 35 "✓ Posted successfully!"
380
380
-
else
381
381
-
${pkgs.gum}/bin/gum style --foreground 196 "✗ Failed to post"
382
382
-
exit 1
383
383
-
fi
378
378
+
if [[ $? -eq 0 ]]; then
379
379
+
${pkgs.gum}/bin/gum style --foreground 35 "✓ Posted successfully!"
380
380
+
else
381
381
+
${pkgs.gum}/bin/gum style --foreground 196 "✗ Failed to post"
382
382
+
exit 1
383
383
+
fi
384
384
'';
385
385
386
386
ghostty-setup = pkgs.writeShellScriptBin "ghostty-setup" ''
···
422
422
'';
423
423
424
424
ghrpc = pkgs.writeShellScriptBin "ghrpc" ''
425
425
-
set -euo pipefail
425
425
+
set -euo pipefail
426
426
427
427
-
# Defaults (configured by Nix)
428
428
-
PLC_ID="${tangled.plcId}"
429
429
-
GITHUB_USER="${tangled.githubUser}"
430
430
-
KNOT_HOST="${tangled.knotHost}"
431
431
-
TANGLED_DOMAIN="${tangled.domain}"
432
432
-
BRANCH="${tangled.defaultBranch}"
433
433
-
VISIBILITY="public"
434
434
-
DESCRIPTION=""
435
435
-
GITHUB=true
436
436
-
TANGLED=true
437
437
-
NAME=""
427
427
+
# Defaults (configured by Nix)
428
428
+
PLC_ID="${tangled.plcId}"
429
429
+
GITHUB_USER="${tangled.githubUser}"
430
430
+
KNOT_HOST="${tangled.knotHost}"
431
431
+
TANGLED_DOMAIN="${tangled.domain}"
432
432
+
BRANCH="${tangled.defaultBranch}"
433
433
+
VISIBILITY="public"
434
434
+
DESCRIPTION=""
435
435
+
GITHUB=true
436
436
+
TANGLED=true
437
437
+
NAME=""
438
438
439
439
-
usage() {
440
440
-
cat <<EOF
441
441
-
Usage: ghrpc [OPTIONS] [NAME]
439
439
+
usage() {
440
440
+
cat <<EOF
441
441
+
Usage: ghrpc [OPTIONS] [NAME]
442
442
443
443
-
Create repositories on GitHub and/or Tangled.
444
444
-
Remotes: origin → knot (tangled), github → GitHub
443
443
+
Create repositories on GitHub and/or Tangled.
444
444
+
Remotes: origin → knot (tangled), github → GitHub
445
445
446
446
-
Arguments:
447
447
-
NAME Repository name (defaults to current directory name)
446
446
+
Arguments:
447
447
+
NAME Repository name (defaults to current directory name)
448
448
449
449
-
Options:
450
450
-
-d, --description STR Repository description
451
451
-
-p, --public Make repository public (default)
452
452
-
--private Make repository private
453
453
-
-g, --github-only Only create on GitHub
454
454
-
-t, --tangled-only Only create on Tangled
455
455
-
--no-github Skip GitHub
456
456
-
--no-tangled Skip Tangled
457
457
-
--plc ID PLC ID (default: $PLC_ID)
458
458
-
--domain DOMAIN Tangled domain (default: $TANGLED_DOMAIN)
459
459
-
-h, --help Show this help
460
460
-
EOF
461
461
-
exit 0
462
462
-
}
449
449
+
Options:
450
450
+
-d, --description STR Repository description
451
451
+
-p, --public Make repository public (default)
452
452
+
--private Make repository private
453
453
+
-g, --github-only Only create on GitHub
454
454
+
-t, --tangled-only Only create on Tangled
455
455
+
--no-github Skip GitHub
456
456
+
--no-tangled Skip Tangled
457
457
+
--plc ID PLC ID (default: $PLC_ID)
458
458
+
--domain DOMAIN Tangled domain (default: $TANGLED_DOMAIN)
459
459
+
-h, --help Show this help
460
460
+
EOF
461
461
+
exit 0
462
462
+
}
463
463
464
464
-
while [[ $# -gt 0 ]]; do
465
465
-
case "$1" in
466
466
-
-h|--help) usage ;;
467
467
-
-d|--description) DESCRIPTION="$2"; shift 2 ;;
468
468
-
-p|--public) VISIBILITY="public"; shift ;;
469
469
-
--private) VISIBILITY="private"; shift ;;
470
470
-
-g|--github-only) TANGLED=false; shift ;;
471
471
-
-t|--tangled-only) GITHUB=false; shift ;;
472
472
-
--no-github) GITHUB=false; shift ;;
473
473
-
--no-tangled) TANGLED=false; shift ;;
474
474
-
--plc) PLC_ID="$2"; shift 2 ;;
475
475
-
--domain) TANGLED_DOMAIN="$2"; shift 2 ;;
476
476
-
-*) echo "Unknown option: $1" >&2; exit 1 ;;
477
477
-
*) NAME="$1"; shift ;;
478
478
-
esac
479
479
-
done
464
464
+
while [[ $# -gt 0 ]]; do
465
465
+
case "$1" in
466
466
+
-h|--help) usage ;;
467
467
+
-d|--description) DESCRIPTION="$2"; shift 2 ;;
468
468
+
-p|--public) VISIBILITY="public"; shift ;;
469
469
+
--private) VISIBILITY="private"; shift ;;
470
470
+
-g|--github-only) TANGLED=false; shift ;;
471
471
+
-t|--tangled-only) GITHUB=false; shift ;;
472
472
+
--no-github) GITHUB=false; shift ;;
473
473
+
--no-tangled) TANGLED=false; shift ;;
474
474
+
--plc) PLC_ID="$2"; shift 2 ;;
475
475
+
--domain) TANGLED_DOMAIN="$2"; shift 2 ;;
476
476
+
-*) echo "Unknown option: $1" >&2; exit 1 ;;
477
477
+
*) NAME="$1"; shift ;;
478
478
+
esac
479
479
+
done
480
480
481
481
-
# Determine repo name
482
482
-
if [[ -z "$NAME" ]]; then
483
483
-
if ${pkgs.git}/bin/git rev-parse --is-inside-work-tree &>/dev/null; then
484
484
-
NAME=$(basename "$(${pkgs.git}/bin/git rev-parse --show-toplevel)")
485
485
-
else
486
486
-
read -p "Repository name: " NAME
481
481
+
# Determine repo name
487
482
if [[ -z "$NAME" ]]; then
488
488
-
echo "Error: Repository name is required" >&2
489
489
-
exit 1
483
483
+
if ${pkgs.git}/bin/git rev-parse --is-inside-work-tree &>/dev/null; then
484
484
+
NAME=$(basename "$(${pkgs.git}/bin/git rev-parse --show-toplevel)")
485
485
+
else
486
486
+
read -p "Repository name: " NAME
487
487
+
if [[ -z "$NAME" ]]; then
488
488
+
echo "Error: Repository name is required" >&2
489
489
+
exit 1
490
490
+
fi
491
491
+
fi
490
492
fi
491
491
-
fi
492
492
-
fi
493
493
494
494
-
# Prompt for description if not provided
495
495
-
if [[ -z "$DESCRIPTION" ]]; then
496
496
-
read -p "Description (optional): " DESCRIPTION
497
497
-
fi
494
494
+
# Prompt for description if not provided
495
495
+
if [[ -z "$DESCRIPTION" ]]; then
496
496
+
read -p "Description (optional): " DESCRIPTION
497
497
+
fi
498
498
499
499
-
echo "Creating repository: $NAME"
499
499
+
echo "Creating repository: $NAME"
500
500
501
501
-
# Create on Tangled
502
502
-
if [[ "$TANGLED" == true ]]; then
503
503
-
tangled_cookie=""
504
504
-
if [[ -f "/run/agenix/tangled-session" ]]; then
505
505
-
tangled_cookie=$(cat /run/agenix/tangled-session)
506
506
-
fi
501
501
+
# Create on Tangled
502
502
+
if [[ "$TANGLED" == true ]]; then
503
503
+
tangled_cookie=""
504
504
+
if [[ -f "/run/agenix/tangled-session" ]]; then
505
505
+
tangled_cookie=$(cat /run/agenix/tangled-session)
506
506
+
fi
507
507
508
508
-
if [[ -z "$tangled_cookie" ]]; then
509
509
-
echo "Warning: No tangled session cookie found at /run/agenix/tangled-session" >&2
510
510
-
else
511
511
-
encoded_desc=$(printf '%s' "$DESCRIPTION" | ${pkgs.gnused}/bin/sed 's/ /%20/g; s/!/%21/g; s/"/%22/g; s/#/%23/g; s/\$/%24/g; s/&/%26/g; s/'"'"'/%27/g; s/(/%28/g; s/)/%29/g; s/\*/%2A/g; s/+/%2B/g; s/,/%2C/g; s/\//%2F/g; s/:/%3A/g; s/;/%3B/g; s/=/%3D/g; s/?/%3F/g; s/@/%40/g; s/\[/%5B/g; s/\]/%5D/g')
508
508
+
if [[ -z "$tangled_cookie" ]]; then
509
509
+
echo "Warning: No tangled session cookie found at /run/agenix/tangled-session" >&2
510
510
+
else
511
511
+
encoded_desc=$(printf '%s' "$DESCRIPTION" | ${pkgs.gnused}/bin/sed 's/ /%20/g; s/!/%21/g; s/"/%22/g; s/#/%23/g; s/\$/%24/g; s/&/%26/g; s/'"'"'/%27/g; s/(/%28/g; s/)/%29/g; s/\*/%2A/g; s/+/%2B/g; s/,/%2C/g; s/\//%2F/g; s/:/%3A/g; s/;/%3B/g; s/=/%3D/g; s/?/%3F/g; s/@/%40/g; s/\[/%5B/g; s/\]/%5D/g')
512
512
513
513
-
response=$(${pkgs.curl}/bin/curl -s 'https://tangled.org/repo/new' \
514
514
-
-H 'Accept: */*' \
515
515
-
-H 'Content-Type: application/x-www-form-urlencoded' \
516
516
-
-b "appview-session-v2=$tangled_cookie" \
517
517
-
-H 'HX-Request: true' \
518
518
-
-H 'Origin: https://tangled.org' \
519
519
-
--data-raw "name=$NAME&description=$encoded_desc&branch=$BRANCH&domain=$TANGLED_DOMAIN")
513
513
+
response=$(${pkgs.curl}/bin/curl -s 'https://tangled.org/repo/new' \
514
514
+
-H 'Accept: */*' \
515
515
+
-H 'Content-Type: application/x-www-form-urlencoded' \
516
516
+
-b "appview-session-v2=$tangled_cookie" \
517
517
+
-H 'HX-Request: true' \
518
518
+
-H 'Origin: https://tangled.org' \
519
519
+
--data-raw "name=$NAME&description=$encoded_desc&branch=$BRANCH&domain=$TANGLED_DOMAIN")
520
520
521
521
-
if echo "$response" | grep -qi "error\|failed"; then
522
522
-
echo "✗ Failed to create Tangled repository" >&2
523
523
-
else
524
524
-
echo "✓ Tangled: https://tangled.org/$TANGLED_DOMAIN/$NAME"
521
521
+
if echo "$response" | grep -qi "error\|failed"; then
522
522
+
echo "✗ Failed to create Tangled repository" >&2
523
523
+
else
524
524
+
echo "✓ Tangled: https://tangled.org/$TANGLED_DOMAIN/$NAME"
525
525
+
fi
526
526
+
fi
525
527
fi
526
526
-
fi
527
527
-
fi
528
528
529
529
-
# Create on GitHub
530
530
-
if [[ "$GITHUB" == true ]]; then
531
531
-
gh_flags="--$VISIBILITY"
532
532
-
[[ -n "$DESCRIPTION" ]] && gh_flags="$gh_flags --description \"$DESCRIPTION\""
529
529
+
# Create on GitHub
530
530
+
if [[ "$GITHUB" == true ]]; then
531
531
+
gh_flags="--$VISIBILITY"
532
532
+
[[ -n "$DESCRIPTION" ]] && gh_flags="$gh_flags --description \"$DESCRIPTION\""
533
533
534
534
-
if ${pkgs.git}/bin/git rev-parse --is-inside-work-tree &>/dev/null; then
535
535
-
if eval "${pkgs.gh}/bin/gh repo create \"$NAME\" $gh_flags --source=. --push --remote=github 2>/dev/null"; then
536
536
-
echo "✓ GitHub: https://github.com/$GITHUB_USER/$NAME"
537
537
-
else
538
538
-
echo "✗ Failed to create GitHub repository" >&2
534
534
+
if ${pkgs.git}/bin/git rev-parse --is-inside-work-tree &>/dev/null; then
535
535
+
if eval "${pkgs.gh}/bin/gh repo create \"$NAME\" $gh_flags --source=. --push --remote=github 2>/dev/null"; then
536
536
+
echo "✓ GitHub: https://github.com/$GITHUB_USER/$NAME"
537
537
+
else
538
538
+
echo "✗ Failed to create GitHub repository" >&2
539
539
+
fi
540
540
+
else
541
541
+
if eval "${pkgs.gh}/bin/gh repo create \"$NAME\" $gh_flags --clone 2>/dev/null"; then
542
542
+
echo "✓ GitHub: created and cloned $NAME"
543
543
+
cd "$NAME"
544
544
+
else
545
545
+
echo "✗ Failed to create GitHub repository" >&2
546
546
+
fi
547
547
+
fi
539
548
fi
540
540
-
else
541
541
-
if eval "${pkgs.gh}/bin/gh repo create \"$NAME\" $gh_flags --clone 2>/dev/null"; then
542
542
-
echo "✓ GitHub: created and cloned $NAME"
543
543
-
cd "$NAME"
544
544
-
else
545
545
-
echo "✗ Failed to create GitHub repository" >&2
546
546
-
fi
547
547
-
fi
548
548
-
fi
549
549
550
550
-
# Configure remotes: origin → knot, github → GitHub
551
551
-
if ${pkgs.git}/bin/git rev-parse --is-inside-work-tree &>/dev/null; then
552
552
-
knot_url="git@$KNOT_HOST:$PLC_ID/$NAME"
553
553
-
github_url="git@github.com:$GITHUB_USER/$NAME.git"
550
550
+
# Configure remotes: origin → knot, github → GitHub
551
551
+
if ${pkgs.git}/bin/git rev-parse --is-inside-work-tree &>/dev/null; then
552
552
+
knot_url="git@$KNOT_HOST:$PLC_ID/$NAME"
553
553
+
github_url="git@github.com:$GITHUB_USER/$NAME.git"
554
554
555
555
-
# Set origin to knot
556
556
-
if [[ "$TANGLED" == true ]]; then
557
557
-
if ${pkgs.git}/bin/git remote get-url origin &>/dev/null; then
558
558
-
current_origin=$(${pkgs.git}/bin/git remote get-url origin)
559
559
-
if [[ "$current_origin" != *"$KNOT_HOST"* ]]; then
560
560
-
${pkgs.git}/bin/git remote set-url origin "$knot_url"
555
555
+
# Set origin to knot
556
556
+
if [[ "$TANGLED" == true ]]; then
557
557
+
if ${pkgs.git}/bin/git remote get-url origin &>/dev/null; then
558
558
+
current_origin=$(${pkgs.git}/bin/git remote get-url origin)
559
559
+
if [[ "$current_origin" != *"$KNOT_HOST"* ]]; then
560
560
+
${pkgs.git}/bin/git remote set-url origin "$knot_url"
561
561
+
fi
562
562
+
else
563
563
+
${pkgs.git}/bin/git remote add origin "$knot_url"
564
564
+
fi
561
565
fi
562
562
-
else
563
563
-
${pkgs.git}/bin/git remote add origin "$knot_url"
564
564
-
fi
565
565
-
fi
566
566
567
567
-
# Set github remote
568
568
-
if [[ "$GITHUB" == true ]]; then
569
569
-
${pkgs.git}/bin/git remote add github "$github_url" 2>/dev/null || \
570
570
-
${pkgs.git}/bin/git remote set-url github "$github_url"
571
571
-
fi
567
567
+
# Set github remote
568
568
+
if [[ "$GITHUB" == true ]]; then
569
569
+
${pkgs.git}/bin/git remote add github "$github_url" 2>/dev/null || \
570
570
+
${pkgs.git}/bin/git remote set-url github "$github_url"
571
571
+
fi
572
572
573
573
-
# Set default push to origin (knot)
574
574
-
${pkgs.git}/bin/git config branch.$BRANCH.remote origin 2>/dev/null || true
573
573
+
# Set default push to origin (knot)
574
574
+
${pkgs.git}/bin/git config branch.$BRANCH.remote origin 2>/dev/null || true
575
575
576
576
-
echo
577
577
-
${pkgs.git}/bin/git remote -v
578
578
-
fi
576
576
+
echo
577
577
+
${pkgs.git}/bin/git remote -v
578
578
+
fi
579
579
'';
580
580
581
581
in
···
754
754
vim = "nvim";
755
755
};
756
756
initContent = ''
757
757
-
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Za-z}'
758
758
-
zstyle ':completion:*' list-colors "''${(s.:.)LS_COLORS}"
759
759
-
zstyle ':completion:*' menu no
760
760
-
zstyle ':fzf-tab:complete:cd:*' fzf-preview 'ls --color $realpath'
761
761
-
zstyle ':fzf-tab:complete:__zoxide_z:*' fzf-preview 'ls --color $realpath'
757
757
+
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Za-z}'
758
758
+
zstyle ':completion:*' list-colors "''${(s.:.)LS_COLORS}"
759
759
+
zstyle ':completion:*' menu no
760
760
+
zstyle ':fzf-tab:complete:cd:*' fzf-preview 'ls --color $realpath'
761
761
+
zstyle ':fzf-tab:complete:__zoxide_z:*' fzf-preview 'ls --color $realpath'
762
762
763
763
-
eval "$(terminal-wakatime init)"
763
763
+
eval "$(terminal-wakatime init)"
764
764
765
765
-
# Edit command buffer in $EDITOR (Ctrl+X, Ctrl+E)
766
766
-
autoload -Uz edit-command-line
767
767
-
zle -N edit-command-line
768
768
-
bindkey '^X^E' edit-command-line
765
765
+
# Edit command buffer in $EDITOR (Ctrl+X, Ctrl+E)
766
766
+
autoload -Uz edit-command-line
767
767
+
zle -N edit-command-line
768
768
+
bindkey '^X^E' edit-command-line
769
769
770
770
-
# Magic space - expand history expressions like !! or !$
771
771
-
bindkey ' ' magic-space
770
770
+
# Magic space - expand history expressions like !! or !$
771
771
+
bindkey ' ' magic-space
772
772
773
773
-
# Suffix aliases - open files by extension
774
774
-
alias -s json=jless
775
775
-
alias -s md=bat
776
776
-
alias -s go='$EDITOR'
777
777
-
alias -s rs='$EDITOR'
778
778
-
alias -s txt=bat
779
779
-
alias -s log=bat
780
780
-
alias -s py='$EDITOR'
781
781
-
alias -s js='$EDITOR'
782
782
-
alias -s ts='$EDITOR'
783
783
-
${if pkgs.stdenv.isDarwin then "alias -s html=open" else ""}
773
773
+
# Suffix aliases - open files by extension
774
774
+
alias -s json=jless
775
775
+
alias -s md=bat
776
776
+
alias -s go='$EDITOR'
777
777
+
alias -s rs='$EDITOR'
778
778
+
alias -s txt=bat
779
779
+
alias -s log=bat
780
780
+
alias -s py='$EDITOR'
781
781
+
alias -s js='$EDITOR'
782
782
+
alias -s ts='$EDITOR'
783
783
+
${if pkgs.stdenv.isDarwin then "alias -s html=open" else ""}
784
784
785
785
-
# Global aliases
786
786
-
alias -g NE='2>/dev/null'
787
787
-
alias -g NO='>/dev/null'
788
788
-
alias -g NUL='>/dev/null 2>&1'
789
789
-
alias -g J='| jq'
785
785
+
# Global aliases
786
786
+
alias -g NE='2>/dev/null'
787
787
+
alias -g NO='>/dev/null'
788
788
+
alias -g NUL='>/dev/null 2>&1'
789
789
+
alias -g J='| jq'
790
790
791
791
-
# OSC 52 clipboard (works over SSH)
792
792
-
function osc52copy() {
793
793
-
local data=$(cat "$@" | base64 | tr -d '\n')
794
794
-
printf "\033]52;c;%s\a" "$data"
795
795
-
}
796
796
-
alias -g C='| osc52copy'
791
791
+
# OSC 52 clipboard (works over SSH)
792
792
+
function osc52copy() {
793
793
+
local data=$(cat "$@" | base64 | tr -d '\n')
794
794
+
printf "\033]52;c;%s\a" "$data"
795
795
+
}
796
796
+
alias -g C='| osc52copy'
797
797
798
798
-
# zmv - advanced batch rename/move
799
799
-
autoload -Uz zmv
800
800
-
alias zcp='zmv -C'
801
801
-
alias zln='zmv -L'
798
798
+
# zmv - advanced batch rename/move
799
799
+
autoload -Uz zmv
800
800
+
alias zcp='zmv -C'
801
801
+
alias zln='zmv -L'
802
802
803
803
-
# Clear screen but keep current command buffer (Ctrl+X, Ctrl+L)
804
804
-
function clear-screen-and-scrollback() {
805
805
-
echoti civis >"$TTY"
806
806
-
printf '%b' '\e[H\e[2J\e[3J' >"$TTY"
807
807
-
echoti cnorm >"$TTY"
808
808
-
zle redisplay
809
809
-
}
810
810
-
zle -N clear-screen-and-scrollback
811
811
-
bindkey '^X^L' clear-screen-and-scrollback
803
803
+
# Clear screen but keep current command buffer (Ctrl+X, Ctrl+L)
804
804
+
function clear-screen-and-scrollback() {
805
805
+
echoti civis >"$TTY"
806
806
+
printf '%b' '\e[H\e[2J\e[3J' >"$TTY"
807
807
+
echoti cnorm >"$TTY"
808
808
+
zle redisplay
809
809
+
}
810
810
+
zle -N clear-screen-and-scrollback
811
811
+
bindkey '^X^L' clear-screen-and-scrollback
812
812
813
813
-
# Copy current command buffer to clipboard (Ctrl+X, Ctrl+C) - OSC 52 for SSH support
814
814
-
function copy-buffer-to-clipboard() {
815
815
-
local data=$(echo -n "$BUFFER" | base64 | tr -d '\n')
816
816
-
printf "\033]52;c;%s\a" "$data"
817
817
-
zle -M "Copied to clipboard"
818
818
-
}
819
819
-
zle -N copy-buffer-to-clipboard
820
820
-
bindkey '^X^C' copy-buffer-to-clipboard
813
813
+
# Copy current command buffer to clipboard (Ctrl+X, Ctrl+C) - OSC 52 for SSH support
814
814
+
function copy-buffer-to-clipboard() {
815
815
+
local data=$(echo -n "$BUFFER" | base64 | tr -d '\n')
816
816
+
printf "\033]52;c;%s\a" "$data"
817
817
+
zle -M "Copied to clipboard"
818
818
+
}
819
819
+
zle -N copy-buffer-to-clipboard
820
820
+
bindkey '^X^C' copy-buffer-to-clipboard
821
821
822
822
-
# chpwd hooks
823
823
-
autoload -Uz add-zsh-hook
822
822
+
# chpwd hooks
823
823
+
autoload -Uz add-zsh-hook
824
824
825
825
-
function auto_venv() {
826
826
-
if [[ -n "$VIRTUAL_ENV" && ! -f "$VIRTUAL_ENV/bin/activate" ]]; then
827
827
-
deactivate
828
828
-
fi
829
829
-
[[ -n "$VIRTUAL_ENV" ]] && return
830
830
-
local dir="$PWD"
831
831
-
while [[ "$dir" != "/" ]]; do
832
832
-
if [[ -f "$dir/.venv/bin/activate" ]]; then
833
833
-
source "$dir/.venv/bin/activate"
834
834
-
return
835
835
-
fi
836
836
-
dir="''${dir:h}"
837
837
-
done
838
838
-
}
825
825
+
function auto_venv() {
826
826
+
if [[ -n "$VIRTUAL_ENV" && ! -f "$VIRTUAL_ENV/bin/activate" ]]; then
827
827
+
deactivate
828
828
+
fi
829
829
+
[[ -n "$VIRTUAL_ENV" ]] && return
830
830
+
local dir="$PWD"
831
831
+
while [[ "$dir" != "/" ]]; do
832
832
+
if [[ -f "$dir/.venv/bin/activate" ]]; then
833
833
+
source "$dir/.venv/bin/activate"
834
834
+
return
835
835
+
fi
836
836
+
dir="''${dir:h}"
837
837
+
done
838
838
+
}
839
839
840
840
-
function auto_nix() {
841
841
-
[[ -n "$IN_NIX_SHELL" ]] && return
842
842
-
local dir="$PWD"
843
843
-
while [[ "$dir" != "/" ]]; do
844
844
-
if [[ -f "$dir/flake.nix" ]]; then
845
845
-
if [[ ! -f "$dir/.envrc" ]]; then
846
846
-
cat > "$dir/.envrc" <<'EOF'
847
847
-
eval "$(nix print-dev-env)"
848
848
-
EOF
849
849
-
command direnv allow "$dir" >/dev/null 2>&1
850
850
-
fi
851
851
-
command direnv reload >/dev/null 2>&1
852
852
-
return
853
853
-
fi
854
854
-
dir="''${dir:h}"
855
855
-
done
856
856
-
}
840
840
+
function auto_nix() {
841
841
+
[[ -n "$IN_NIX_SHELL" ]] && return
842
842
+
local dir="$PWD"
843
843
+
while [[ "$dir" != "/" ]]; do
844
844
+
if [[ -f "$dir/flake.nix" ]]; then
845
845
+
if [[ ! -f "$dir/.envrc" ]]; then
846
846
+
cat > "$dir/.envrc" <<'EOF'
847
847
+
use flake
848
848
+
EOF
849
849
+
command direnv allow "$dir" >/dev/null 2>&1
850
850
+
fi
851
851
+
command direnv reload >/dev/null 2>&1
852
852
+
return
853
853
+
fi
854
854
+
dir="''${dir:h}"
855
855
+
done
856
856
+
}
857
857
858
858
-
add-zsh-hook chpwd auto_venv
859
859
-
add-zsh-hook chpwd auto_nix
858
858
+
add-zsh-hook chpwd auto_venv
859
859
+
add-zsh-hook chpwd auto_nix
860
860
'';
861
861
history = {
862
862
size = 10000;