@procrastivity/clast 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -9
- package/bin/clast +13 -2
- package/bin/clast-plumbing +7 -0
- package/examples/workflows/morning-briefing.md +6 -6
- package/lib/clast/clast-classify-lib.bash +68 -0
- package/lib/clast/clast-dismissed-lib.bash +70 -0
- package/lib/clast/clast-lib.bash +88 -6
- package/lib/clast/clast-manifest-lib.bash +35 -5
- package/lib/clast/clast-porcelain-lib.bash +29 -16
- package/lib/clast/clast-porcelain-subcommands/brief.bash +90 -21
- package/lib/clast/clast-porcelain-subcommands/retro.bash +317 -0
- package/lib/clast/clast-porcelain-subcommands/undismiss.bash +27 -0
- package/lib/clast/clast-porcelain-subcommands/wake.bash +78 -13
- package/lib/clast/clast-registry-lib.bash +132 -27
- package/lib/clast/clast-retro-lib.bash +397 -0
- package/lib/clast/clast-subcommands/doctor.bash +29 -13
- package/lib/clast/clast-subcommands/entries.bash +40 -50
- package/lib/clast/clast-subcommands/projects.bash +9 -19
- package/lib/clast/clast-subcommands/registry.bash +26 -11
- package/lib/clast/clast-subcommands/retro.bash +217 -0
- package/lib/clast/clast-subcommands/sessions.bash +104 -4
- package/lib/clast/clast-subcommands/show.bash +54 -8
- package/lib/clast/clast-subcommands/snapshot.bash +18 -10
- package/lib/clast/prompts/brief-system.md +11 -5
- package/lib/clast/prompts/brief-user.md +4 -1
- package/lib/clast/prompts/retro-summary-system.md +14 -0
- package/lib/clast/prompts/retro-summary-user.md +7 -0
- package/lib/clast/prompts/{day-wakeup-draft-system.md → wake-draft-system.md} +1 -1
- package/package.json +2 -1
- package/{.claude-plugin/skills/wakeup → skills/brief}/SKILL.md +9 -9
- package/{.claude-plugin/skills/day-wakeup → skills/wake}/SKILL.md +35 -12
- /package/lib/clast/prompts/{day-wakeup-draft-user.md → wake-draft-user.md} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# clast wake — LLM-powered interactive day curation.
|
|
2
2
|
#
|
|
3
|
-
# Replicates the /
|
|
3
|
+
# Replicates the /wake plugin skill using an OpenAI-compatible chat
|
|
4
4
|
# completions endpoint. Calls clast-plumbing for data, assembles prompts,
|
|
5
5
|
# calls the LLM via curl, presents drafts interactively.
|
|
6
6
|
#
|
|
@@ -43,7 +43,7 @@ _clast_wake_build_user_prompt() {
|
|
|
43
43
|
local first_turns="$6" last_turns="$7" breadcrumbs="$8"
|
|
44
44
|
|
|
45
45
|
local template_file template
|
|
46
|
-
template_file="$(clast_porcelain_user_prompt_file
|
|
46
|
+
template_file="$(clast_porcelain_user_prompt_file wake-draft-user)"
|
|
47
47
|
|
|
48
48
|
if [[ -n "$template_file" ]]; then
|
|
49
49
|
template="$(cat "$template_file")"
|
|
@@ -57,7 +57,7 @@ _clast_wake_build_user_prompt() {
|
|
|
57
57
|
template="${template//\{\{breadcrumbs\}\}/${breadcrumbs:-None.}}"
|
|
58
58
|
printf '%s' "$template"
|
|
59
59
|
else
|
|
60
|
-
clast_porcelain_warn "user prompt template not found:
|
|
60
|
+
clast_porcelain_warn "user prompt template not found: wake-draft-user.md — using inline fallback"
|
|
61
61
|
cat <<EOF
|
|
62
62
|
Session metadata:
|
|
63
63
|
- Project: ${project}
|
|
@@ -255,6 +255,34 @@ clast_cmd_wake() {
|
|
|
255
255
|
clast_porcelain_die "failed to list sessions"
|
|
256
256
|
}
|
|
257
257
|
|
|
258
|
+
# Auto-dismiss no-op sessions before any LLM work: sessions where Claude
|
|
259
|
+
# never replied (substantive == false) — empty sessions, slash-command-only
|
|
260
|
+
# sessions (/clear, /model, /config), and sessions abandoned before any
|
|
261
|
+
# response. This is a deterministic pre-filter — the LLM is never called for
|
|
262
|
+
# them. Sessions driven by a custom slash command still have assistant
|
|
263
|
+
# replies, so they are kept. Reversible via `clast undismiss <id>`. Opt out
|
|
264
|
+
# by setting CLAST_WAKE_AUTODISMISS_NOOP=0.
|
|
265
|
+
local auto_dismissed_count=0
|
|
266
|
+
if [[ "${CLAST_WAKE_AUTODISMISS_NOOP:-1}" != "0" ]]; then
|
|
267
|
+
local noop_ids noop_id
|
|
268
|
+
noop_ids="$(jq -r '
|
|
269
|
+
.[] | select(.substantive == false and .curated == false and .dismissed == false)
|
|
270
|
+
| .session_id
|
|
271
|
+
' <<<"$sessions_json")"
|
|
272
|
+
while IFS= read -r noop_id; do
|
|
273
|
+
[[ -z "$noop_id" ]] && continue
|
|
274
|
+
if clast-plumbing sessions dismiss "$noop_id" \
|
|
275
|
+
--reason "auto: no substantive content (empty / slash-command-only)" >/dev/null 2>&1; then
|
|
276
|
+
auto_dismissed_count=$(( auto_dismissed_count + 1 ))
|
|
277
|
+
fi
|
|
278
|
+
done <<<"$noop_ids"
|
|
279
|
+
if (( auto_dismissed_count > 0 )); then
|
|
280
|
+
clast_porcelain_info "Auto-dismissed $auto_dismissed_count no-op session(s) (empty / slash-command-only)."
|
|
281
|
+
# Drop the just-dismissed rows from the working set so they don't reappear.
|
|
282
|
+
sessions_json="$(jq -c '[.[] | select(.substantive != false or .curated == true)]' <<<"$sessions_json")"
|
|
283
|
+
fi
|
|
284
|
+
fi
|
|
285
|
+
|
|
258
286
|
local uncurated
|
|
259
287
|
uncurated="$(jq -c '[.[] | select(.curated == false or .stale == true)]' <<<"$sessions_json")"
|
|
260
288
|
local total
|
|
@@ -301,37 +329,71 @@ clast_cmd_wake() {
|
|
|
301
329
|
msg_count="$(jq -r '.msg_count_approx' <<<"$session")"
|
|
302
330
|
snapshot_path="$(jq -r '.snapshot_path' <<<"$session")"
|
|
303
331
|
|
|
304
|
-
|
|
305
|
-
|
|
332
|
+
# Recorded date + time range so the reviewer can tell which day's work
|
|
333
|
+
# this is (BDS-54). Render the session's own start/end instant in the
|
|
334
|
+
# local timezone. Deliberately NOT day_bucket: that is clast's
|
|
335
|
+
# cutoff-adjusted *filing* day, which differs from the instant's calendar
|
|
336
|
+
# date for pre-cutoff sessions — pairing it with a clock time (and a "UTC"
|
|
337
|
+
# label) yielded a timestamp wrong by a day. Fall back to the raw UTC
|
|
338
|
+
# substrings if `date` can't parse the timestamp.
|
|
339
|
+
local rec_date start_short end_short tz
|
|
340
|
+
rec_date="$(date -d "$start_ts" +%Y-%m-%d 2>/dev/null)" || rec_date=""
|
|
341
|
+
[[ -z "$rec_date" ]] && rec_date="${start_ts:0:10}"
|
|
342
|
+
start_short="$(date -d "$start_ts" +%H:%M 2>/dev/null)" || start_short=""
|
|
343
|
+
[[ -z "$start_short" ]] && start_short="${start_ts:11:5}"
|
|
344
|
+
end_short="$(date -d "$end_ts" +%H:%M 2>/dev/null)" || end_short=""
|
|
345
|
+
[[ -z "$end_short" ]] && end_short="${end_ts:11:5}"
|
|
346
|
+
tz="$(date -d "$start_ts" +%Z 2>/dev/null)" || tz="UTC"
|
|
347
|
+
[[ -z "$tz" ]] && tz="UTC"
|
|
348
|
+
|
|
349
|
+
local recorded="$rec_date"
|
|
350
|
+
if [[ -n "$start_short" ]]; then
|
|
351
|
+
recorded="$recorded $start_short"
|
|
352
|
+
[[ -n "$end_short" && "$end_short" != "$start_short" ]] && recorded="$recorded–$end_short"
|
|
353
|
+
recorded="$recorded $tz"
|
|
354
|
+
fi
|
|
306
355
|
|
|
307
356
|
local is_stale
|
|
308
357
|
is_stale="$(jq -r '.stale // false' <<<"$session")"
|
|
309
358
|
local label="Session $((i+1))/$total: $project"
|
|
310
359
|
[[ "$is_stale" == "true" ]] && label="$label [STALE]"
|
|
311
|
-
[[ -n "$
|
|
360
|
+
[[ -n "$rec_date" ]] && label="$label ($rec_date $start_short"
|
|
312
361
|
[[ -n "$branch" && "$branch" != "null" ]] && label="$label, $branch"
|
|
313
362
|
label="$label)"
|
|
314
363
|
|
|
315
364
|
_clast_wake_separator "$label"
|
|
365
|
+
# Full session ID + recorded window: identifies exactly which session is
|
|
366
|
+
# being reviewed (e.g. for `clast-plumbing sessions dismiss/undismiss <id>`).
|
|
367
|
+
clast_porcelain_info " id: $sid"
|
|
368
|
+
clast_porcelain_info " recorded: $recorded"
|
|
316
369
|
clast_porcelain_info "Gathering context..."
|
|
317
370
|
|
|
318
371
|
local show_json
|
|
319
372
|
show_json="$(clast-plumbing --json show "$sid" --full --turns 8 2>/dev/null)" || {
|
|
320
|
-
|
|
373
|
+
local rc=$? reason
|
|
374
|
+
reason="$(jq -r '.error // empty' <<<"$show_json" 2>/dev/null || true)"
|
|
375
|
+
[[ -z "$reason" ]] && reason="exit $rc"
|
|
376
|
+
clast_porcelain_warn "failed to read session $sid ($reason) — skipping"
|
|
321
377
|
skipped_count=$(( skipped_count + 1 ))
|
|
322
378
|
i=$(( i + 1 ))
|
|
323
379
|
continue
|
|
324
380
|
}
|
|
325
381
|
|
|
326
|
-
|
|
327
|
-
|
|
382
|
+
# Cap each turn's text: a single pathological turn (e.g. a huge pasted
|
|
383
|
+
# blob or tool dump) would otherwise bloat the prompt — costly and liable
|
|
384
|
+
# to exceed the model's context. show --full keeps the full text; only the
|
|
385
|
+
# LLM-bound copy is bounded.
|
|
386
|
+
local first_turns last_turns turn_cap=2000
|
|
387
|
+
first_turns="$(jq -r --argjson cap "$turn_cap" '
|
|
328
388
|
.first_turns // [] | .[] |
|
|
329
|
-
|
|
389
|
+
(.text // "") as $t | ($t | length) as $n |
|
|
390
|
+
"[\(.role)] \(if $n > $cap then $t[0:$cap] + "… [\($n - $cap) more chars truncated]" else $t end)"
|
|
330
391
|
' <<<"$show_json" 2>/dev/null)" || true
|
|
331
392
|
|
|
332
|
-
last_turns="$(jq -r '
|
|
393
|
+
last_turns="$(jq -r --argjson cap "$turn_cap" '
|
|
333
394
|
.last_turns // [] | .[] |
|
|
334
|
-
|
|
395
|
+
(.text // "") as $t | ($t | length) as $n |
|
|
396
|
+
"[\(.role)] \(if $n > $cap then $t[0:$cap] + "… [\($n - $cap) more chars truncated]" else $t end)"
|
|
335
397
|
' <<<"$show_json" 2>/dev/null)" || true
|
|
336
398
|
|
|
337
399
|
local breadcrumbs=""
|
|
@@ -342,7 +404,7 @@ clast_cmd_wake() {
|
|
|
342
404
|
"$first_turns" "$last_turns" "$breadcrumbs")"
|
|
343
405
|
|
|
344
406
|
local system_prompt
|
|
345
|
-
system_prompt="$(clast_porcelain_load_system_prompt
|
|
407
|
+
system_prompt="$(clast_porcelain_load_system_prompt wake-draft-system)"
|
|
346
408
|
|
|
347
409
|
local draft="" edit_extra=""
|
|
348
410
|
local drafting=1
|
|
@@ -439,6 +501,9 @@ Revisions requested by user: ${edit_extra}"
|
|
|
439
501
|
printf '\n'
|
|
440
502
|
_clast_wake_separator "Summary"
|
|
441
503
|
clast_porcelain_info " Curated: $curated_count session(s) across $unique_projects project(s)"
|
|
504
|
+
if (( auto_dismissed_count > 0 )); then
|
|
505
|
+
clast_porcelain_info " Auto-dismissed (no-op): $auto_dismissed_count session(s)"
|
|
506
|
+
fi
|
|
442
507
|
if (( dismissed_count > 0 )); then
|
|
443
508
|
clast_porcelain_info " Dismissed: $dismissed_count session(s)"
|
|
444
509
|
fi
|
|
@@ -95,6 +95,58 @@ clast_registry_resolve() {
|
|
|
95
95
|
printf '%s\n' "$slug"
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
# clast_registry_line_for_path <path-or-segment>
|
|
99
|
+
# Like clast_registry_resolve, but prints the FULL matching registry line
|
|
100
|
+
# (the JSON object) instead of just the slug; empty + return 1 on miss.
|
|
101
|
+
# Use this to recover the per-directory path/label/remote for a specific
|
|
102
|
+
# session — slug-first-match collapses a multi-directory project onto its
|
|
103
|
+
# first line, which is wrong once a slug spans several directories.
|
|
104
|
+
clast_registry_line_for_path() {
|
|
105
|
+
local input="${1:-}"
|
|
106
|
+
if [[ -z "$input" ]]; then
|
|
107
|
+
return 1
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
local arr
|
|
111
|
+
arr="$(clast_registry_list_json)"
|
|
112
|
+
|
|
113
|
+
local -a candidates=()
|
|
114
|
+
if [[ "$input" == -* ]]; then
|
|
115
|
+
candidates=("$input")
|
|
116
|
+
local -a decoded=()
|
|
117
|
+
mapfile -t decoded < <(clast_decode_candidates "$input")
|
|
118
|
+
candidates+=("${decoded[@]}")
|
|
119
|
+
else
|
|
120
|
+
local canon
|
|
121
|
+
canon="$(realpath -m "$input" 2>/dev/null || printf '%s' "$input")"
|
|
122
|
+
candidates=("$canon")
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
local cands_json line
|
|
126
|
+
cands_json="$(printf '%s\n' "${candidates[@]}" | jq -Rn '[inputs]')"
|
|
127
|
+
line="$(_clast_registry_lookup_line "$cands_json" "$arr" 2>/dev/null)" || true
|
|
128
|
+
if [[ -z "$line" ]]; then
|
|
129
|
+
return 1
|
|
130
|
+
fi
|
|
131
|
+
printf '%s\n' "$line"
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
# _clast_registry_lookup_line <candidates-json-array> <registry-json-array>
|
|
135
|
+
# Like _clast_registry_lookup_paths but returns the FIRST matching line's
|
|
136
|
+
# whole object (path before alias). Print the compact JSON object or empty.
|
|
137
|
+
_clast_registry_lookup_line() {
|
|
138
|
+
local cands_json="$1" arr="$2"
|
|
139
|
+
jq -c --argjson cands "$cands_json" '
|
|
140
|
+
. as $arr
|
|
141
|
+
| first(
|
|
142
|
+
$cands[] as $c
|
|
143
|
+
| ( ($arr | map(select(.path == $c)) | .[0])
|
|
144
|
+
// ($arr | map(select((.aliases? // []) | index($c) != null)) | .[0]) )
|
|
145
|
+
| select(. != null)
|
|
146
|
+
) // empty
|
|
147
|
+
' <<<"$arr"
|
|
148
|
+
}
|
|
149
|
+
|
|
98
150
|
# _clast_registry_lookup_path <path> <registry-json-array>
|
|
99
151
|
# First match wins: scan .path, then .aliases[]. Print slug or empty.
|
|
100
152
|
_clast_registry_lookup_path() {
|
|
@@ -125,14 +177,30 @@ _clast_registry_lookup_paths() {
|
|
|
125
177
|
' <<<"$arr"
|
|
126
178
|
}
|
|
127
179
|
|
|
128
|
-
#
|
|
129
|
-
#
|
|
130
|
-
#
|
|
131
|
-
|
|
132
|
-
|
|
180
|
+
# _clast_registry_slugify <string>
|
|
181
|
+
# Lowercase, map non-[a-z0-9] runs to single dashes, trim, cap at 32.
|
|
182
|
+
# Used for auto-derived labels (e.g. a parent-directory basename).
|
|
183
|
+
_clast_registry_slugify() {
|
|
184
|
+
local s
|
|
185
|
+
s="$(printf '%s' "${1,,}" | sed 's/[^a-z0-9]/-/g; s/--*/-/g; s/^-//; s/-$//')"
|
|
186
|
+
s="${s:0:32}"
|
|
187
|
+
s="${s%-}"
|
|
188
|
+
printf '%s' "$s"
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
# clast_registry_add <path> [--slug NAME] [--label NAME] [--remote URL]
|
|
192
|
+
# Append a single JSONL line. The remote is a *grouping hint*, not an
|
|
193
|
+
# identity: when it matches an existing entry's remote, an absent --slug
|
|
194
|
+
# adopts that entry's slug (so clones of one repo share a project), but an
|
|
195
|
+
# explicit --slug always wins (a divergent one warns). Default slug =
|
|
196
|
+
# basename(path). Default label = basename(dirname(path)). Default remote
|
|
197
|
+
# = `git -C <path> remote get-url origin` (or absent). New lines carry
|
|
198
|
+
# `aliases: []` — sibling paths are no longer rolled up; a shared slug
|
|
199
|
+
# across distinct .path lines is the supported multi-directory shape.
|
|
133
200
|
# Print the appended JSON on stdout. Exit 2 on bad args, 1 on write fail.
|
|
134
201
|
clast_registry_add() {
|
|
135
|
-
local path="" slug=""
|
|
202
|
+
local path="" slug="" slug_explicit=0 label_raw="" label_explicit=0
|
|
203
|
+
local remote="" remote_explicit=0
|
|
136
204
|
while [[ $# -gt 0 ]]; do
|
|
137
205
|
case "$1" in
|
|
138
206
|
--slug)
|
|
@@ -140,8 +208,25 @@ clast_registry_add() {
|
|
|
140
208
|
clast_log_error "clast_registry_add: --slug requires a value"
|
|
141
209
|
return 2
|
|
142
210
|
fi
|
|
143
|
-
|
|
144
|
-
|
|
211
|
+
if [[ -z "$2" ]]; then
|
|
212
|
+
clast_log_error "clast_registry_add: --slug requires a non-empty value"
|
|
213
|
+
return 2
|
|
214
|
+
fi
|
|
215
|
+
slug="$2"; slug_explicit=1; shift 2 ;;
|
|
216
|
+
--slug=*)
|
|
217
|
+
slug="${1#*=}"
|
|
218
|
+
if [[ -z "$slug" ]]; then
|
|
219
|
+
clast_log_error "clast_registry_add: --slug requires a non-empty value"
|
|
220
|
+
return 2
|
|
221
|
+
fi
|
|
222
|
+
slug_explicit=1; shift ;;
|
|
223
|
+
--label)
|
|
224
|
+
if [[ $# -lt 2 ]]; then
|
|
225
|
+
clast_log_error "clast_registry_add: --label requires a value"
|
|
226
|
+
return 2
|
|
227
|
+
fi
|
|
228
|
+
label_raw="$2"; label_explicit=1; shift 2 ;;
|
|
229
|
+
--label=*) label_raw="${1#*=}"; label_explicit=1; shift ;;
|
|
145
230
|
--remote)
|
|
146
231
|
if [[ $# -lt 2 ]]; then
|
|
147
232
|
clast_log_error "clast_registry_add: --remote requires a value"
|
|
@@ -196,30 +281,49 @@ clast_registry_add() {
|
|
|
196
281
|
fi
|
|
197
282
|
fi
|
|
198
283
|
|
|
199
|
-
#
|
|
200
|
-
|
|
284
|
+
# Resolve the slug against any existing entry sharing this remote. The
|
|
285
|
+
# remote groups clones of one repo under a single logical project, but it
|
|
286
|
+
# is only a hint: an explicit --slug always wins. A divergent explicit
|
|
287
|
+
# slug warns (you are splitting the remote into two projects on purpose);
|
|
288
|
+
# the default slug silently adopts the match.
|
|
289
|
+
local matched_slug=""
|
|
290
|
+
if [[ -n "$remote" ]]; then
|
|
291
|
+
matched_slug="$(clast_registry_match_remote "$remote" 2>/dev/null || true)"
|
|
292
|
+
fi
|
|
293
|
+
|
|
294
|
+
if (( slug_explicit == 1 )); then
|
|
295
|
+
if [[ -n "$matched_slug" && "$matched_slug" != "$slug" ]]; then
|
|
296
|
+
clast_log_warn "registry: remote '$remote' is already registered under slug '$matched_slug'; registering '$canon' under requested slug '$slug' as a separate project (pass --slug '$matched_slug' to group them)"
|
|
297
|
+
fi
|
|
298
|
+
elif [[ -n "$matched_slug" ]]; then
|
|
299
|
+
slug="$matched_slug"
|
|
300
|
+
clast_log_info "registry: grouping '$canon' under existing slug '$slug' (shared remote; pass --slug to override)"
|
|
301
|
+
else
|
|
201
302
|
slug="$(basename "$canon")"
|
|
202
303
|
fi
|
|
203
304
|
|
|
204
|
-
#
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
[ .[] | select(.slug == $s) | [.path] + (.aliases // []) ]
|
|
216
|
-
| add // []
|
|
217
|
-
| map(select(. != $p))
|
|
218
|
-
| unique
|
|
219
|
-
' <<<"$arr")"
|
|
305
|
+
# Per-directory label. An explicit --label is lowercased and validated;
|
|
306
|
+
# otherwise derive from the parent directory's basename (e.g.
|
|
307
|
+
# ~/Workspaces/performance/xesapps → "performance"). The label only
|
|
308
|
+
# distinguishes clones of one slug; a single-directory project never
|
|
309
|
+
# surfaces it, so a default like "code" is harmless.
|
|
310
|
+
local label=""
|
|
311
|
+
if (( label_explicit == 1 )); then
|
|
312
|
+
label="${label_raw,,}"
|
|
313
|
+
if [[ ! "$label" =~ ^[a-z0-9][a-z0-9-]{0,31}$ ]]; then
|
|
314
|
+
clast_log_error "clast_registry_add: invalid --label '$label_raw' (expected [a-z0-9][a-z0-9-]{0,31})"
|
|
315
|
+
return 2
|
|
220
316
|
fi
|
|
317
|
+
else
|
|
318
|
+
label="$(_clast_registry_slugify "$(basename "$(dirname "$canon")")")"
|
|
221
319
|
fi
|
|
222
320
|
|
|
321
|
+
# Sibling paths are no longer rolled into aliases: each directory is its
|
|
322
|
+
# own line keyed by .path, and a shared slug is the supported way to span
|
|
323
|
+
# directories. `aliases` stays present (reserved for genuine alternate
|
|
324
|
+
# paths of the same checkout) but empty.
|
|
325
|
+
local aliases_json='[]'
|
|
326
|
+
|
|
223
327
|
local journal_dir
|
|
224
328
|
journal_dir="$(clast_journal_dir)"
|
|
225
329
|
if ! mkdir -p "$journal_dir"; then
|
|
@@ -234,10 +338,11 @@ clast_registry_add() {
|
|
|
234
338
|
line="$(jq -c -n \
|
|
235
339
|
--arg path "$canon" \
|
|
236
340
|
--arg slug "$slug" \
|
|
341
|
+
--arg label "$label" \
|
|
237
342
|
--arg remote "$remote" \
|
|
238
343
|
--arg first_seen "$first_seen" \
|
|
239
344
|
--argjson aliases "$aliases_json" \
|
|
240
|
-
'{path: $path, slug: $slug, remote: $remote, first_seen: $first_seen}
|
|
345
|
+
'{path: $path, slug: $slug, label: $label, remote: $remote, first_seen: $first_seen}
|
|
241
346
|
| with_entries(select(.value != null and .value != ""))
|
|
242
347
|
| . + {aliases: $aliases}')" || {
|
|
243
348
|
clast_log_error "clast_registry_add: jq failed to build registry line"
|