@onlooker-community/ecosystem 0.34.0 → 0.43.0
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/.claude/skills/writing-tests/SKILL.md +27 -0
- package/.claude-plugin/plugin.json +1 -1
- package/.github/workflows/release.yml +14 -14
- package/.release-please-manifest.json +7 -7
- package/AGENTS.md +116 -0
- package/CHANGELOG.md +175 -0
- package/CLAUDE.md +5 -0
- package/docs/lesson-promotion-pipeline.md +6 -6
- package/docs/superpowers/plans/2026-08-10-lesson-confirmation.md +1273 -0
- package/docs/superpowers/plans/2026-08-11-lesson-judging.md +1232 -0
- package/docs/superpowers/plans/2026-08-11-lesson-unconfirm.md +458 -0
- package/docs/superpowers/plans/2026-08-12-author-key.md +567 -0
- package/docs/superpowers/plans/2026-08-13-approved-pool.md +747 -0
- package/docs/superpowers/plans/2026-08-13-librarian-cluster.md +392 -0
- package/docs/superpowers/plans/2026-08-14-criterion-scores-consumers.md +1374 -0
- package/docs/superpowers/plans/2026-08-14-criterion-scores-schema.md +277 -0
- package/docs/superpowers/plans/2026-08-16-cartographer-undocumented-entity.md +741 -0
- package/docs/superpowers/specs/2026-08-10-lesson-confirmation-design.md +213 -0
- package/docs/superpowers/specs/2026-08-11-lesson-judging-design.md +267 -0
- package/docs/superpowers/specs/2026-08-11-lesson-unconfirm-design.md +152 -0
- package/docs/superpowers/specs/2026-08-12-author-key-design.md +317 -0
- package/docs/superpowers/specs/2026-08-13-approved-pool-design.md +232 -0
- package/docs/superpowers/specs/2026-08-14-criterion-scores-design.md +254 -0
- package/docs/superpowers/specs/2026-08-16-cartographer-undocumented-entity-design.md +249 -0
- package/package.json +2 -2
- package/plugins/assayer/.claude-plugin/plugin.json +1 -1
- package/plugins/assayer/CHANGELOG.md +7 -0
- package/plugins/assayer/scripts/lib/assayer-config.sh +6 -0
- package/plugins/cartographer/.claude-plugin/plugin.json +1 -1
- package/plugins/cartographer/CHANGELOG.md +54 -0
- package/plugins/cartographer/README.md +56 -1
- package/plugins/cartographer/config.json +7 -1
- package/plugins/cartographer/scripts/hooks/cartographer-post-write.sh +4 -4
- package/plugins/cartographer/scripts/hooks/cartographer-session-start.sh +7 -4
- package/plugins/cartographer/scripts/lib/cartographer-collect.sh +8 -1
- package/plugins/cartographer/scripts/lib/cartographer-config.sh +26 -0
- package/plugins/cartographer/scripts/lib/cartographer-events.sh +90 -0
- package/plugins/cartographer/scripts/lib/cartographer-filter.sh +105 -0
- package/plugins/cartographer/scripts/lib/cartographer-omission.sh +130 -0
- package/plugins/cartographer/scripts/lib/cartographer-resolve.sh +132 -0
- package/plugins/cartographer/scripts/run-audit.sh +136 -53
- package/plugins/cartographer/skills/cartographer/SKILL.md +33 -9
- package/plugins/curator/.claude-plugin/plugin.json +1 -1
- package/plugins/curator/CHANGELOG.md +7 -0
- package/plugins/curator/scripts/lib/curator-emit.sh +2 -1
- package/plugins/historian/.claude-plugin/plugin.json +1 -1
- package/plugins/historian/CHANGELOG.md +7 -0
- package/plugins/historian/scripts/lib/historian-emit.sh +2 -1
- package/plugins/librarian/.claude-plugin/plugin.json +1 -1
- package/plugins/librarian/CHANGELOG.md +71 -0
- package/plugins/librarian/config.json +30 -1
- package/plugins/librarian/docs/adr/002-agent-definitions-are-shared-assets.md +82 -0
- package/plugins/librarian/scripts/hooks/librarian-session-end.sh +28 -0
- package/plugins/librarian/scripts/hooks/librarian-session-start.sh +42 -12
- package/plugins/librarian/scripts/lib/librarian-author-key.sh +279 -0
- package/plugins/librarian/scripts/lib/librarian-cli.sh +346 -2
- package/plugins/librarian/scripts/lib/librarian-emit.sh +2 -1
- package/plugins/librarian/scripts/lib/librarian-lesson-judge.sh +349 -0
- package/plugins/librarian/scripts/lib/librarian-lesson-promote.sh +225 -0
- package/plugins/librarian/scripts/lib/librarian-lesson-review.sh +312 -0
- package/plugins/librarian/scripts/lib/librarian-lesson-rubric.sh +56 -0
- package/plugins/librarian/scripts/lib/librarian-lesson-storage.sh +82 -13
- package/plugins/librarian/scripts/lib/librarian-lesson-transform.sh +6 -1
- package/plugins/librarian/scripts/lib/librarian-lesson-validate.sh +131 -62
- package/plugins/librarian/skills/librarian/SKILL.md +98 -1
- package/plugins/tribunal/.claude-plugin/plugin.json +1 -1
- package/plugins/tribunal/CHANGELOG.md +63 -0
- package/plugins/tribunal/agents/tribunal-judge-adversarial.md +34 -0
- package/plugins/tribunal/agents/tribunal-judge-security.md +33 -0
- package/plugins/tribunal/agents/tribunal-judge-standard.md +12 -0
- package/plugins/tribunal/config.json +1 -0
- package/plugins/tribunal/scripts/lib/tribunal-aggregate.sh +154 -9
- package/plugins/tribunal/scripts/lib/tribunal-gate.sh +195 -16
- package/plugins/tribunal/skills/tribunal/SKILL.md +5 -3
- package/scripts/lib/prompt-rules.sh +6 -1
- package/test/bats/archivist-inject.bats +1 -1
- package/test/bats/assayer-extract.bats +2 -2
- package/test/bats/bursar-session-start.bats +3 -3
- package/test/bats/cartographer-config.bats +43 -0
- package/test/bats/cartographer-events.bats +267 -0
- package/test/bats/cartographer-filter.bats +169 -0
- package/test/bats/cartographer-lock.bats +3 -3
- package/test/bats/cartographer-omission.bats +202 -0
- package/test/bats/cartographer-resolve.bats +287 -0
- package/test/bats/cartographer-run-audit.bats +325 -0
- package/test/bats/compass-sanitizer.bats +11 -11
- package/test/bats/compass-transcript.bats +2 -2
- package/test/bats/config.bats +15 -15
- package/test/bats/curator-session-start.bats +10 -3
- package/test/bats/emit-payload-default.bats +52 -0
- package/test/bats/governor-ledger.bats +1 -1
- package/test/bats/historian-prompt-submit.bats +1 -1
- package/test/bats/inspector-post-write-hook.bats +4 -4
- package/test/bats/librarian-author-key.bats +477 -0
- package/test/bats/librarian-cli.bats +16 -16
- package/test/bats/librarian-lesson-judge.bats +884 -0
- package/test/bats/librarian-lesson-promote.bats +552 -0
- package/test/bats/librarian-lesson-review.bats +900 -0
- package/test/bats/librarian-lesson-transform.bats +17 -3
- package/test/bats/librarian-session-end.bats +161 -0
- package/test/bats/librarian-session-start.bats +36 -2
- package/test/bats/lineage-config.bats +1 -1
- package/test/bats/lineage-redact.bats +5 -5
- package/test/bats/session-tracker.bats +4 -4
- package/test/bats/tribunal-aggregate.bats +354 -1
- package/test/bats/tribunal-gate.bats +631 -0
- package/test/bats/tribunal-judge-agents.bats +119 -0
- package/test/bats/tribunal-jury.bats +1 -1
- package/test/bats/turn-tracker.bats +1 -1
- package/test/bats/warden-sanitizer.bats +3 -3
- package/test/bats/worktree-tracker.bats +2 -2
- package/test/node/lesson-validate-agreement.test.mjs +35 -6
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
#
|
|
4
4
|
# Exposes:
|
|
5
5
|
# librarian_cli list # one-line summary + table of pending proposals
|
|
6
|
+
# librarian_cli lessons list [--confirmed] # pending lesson queue, or the confirmed ones
|
|
6
7
|
# librarian_cli show <proposal_id> # full proposal body + provenance + conflict state
|
|
7
8
|
# librarian_cli accept <proposal_id> # write to typed memory store, mark accepted
|
|
8
9
|
# librarian_cli reject <proposal_id> [reason] # tombstone + mark rejected
|
|
@@ -18,7 +19,11 @@
|
|
|
18
19
|
# bullet line, and the file is created if it doesn't exist.
|
|
19
20
|
#
|
|
20
21
|
# Depends on (sourced by the caller): librarian-config.sh,
|
|
21
|
-
# librarian-project-key.sh, librarian-storage.sh, librarian-emit.sh
|
|
22
|
+
# librarian-project-key.sh, librarian-storage.sh, librarian-emit.sh,
|
|
23
|
+
# librarian-lesson-storage.sh, librarian-lesson-validate.sh,
|
|
24
|
+
# librarian-lesson-review.sh, librarian-lesson-judge.sh,
|
|
25
|
+
# librarian-lesson-rubric.sh, librarian-author-key.sh,
|
|
26
|
+
# librarian-lesson-promote.sh
|
|
22
27
|
|
|
23
28
|
# ----------------------------------------------------------------------------
|
|
24
29
|
# Project key + memory store path resolution
|
|
@@ -117,7 +122,8 @@ _librarian_cli_set_proposal_status() {
|
|
|
117
122
|
local key="$1"
|
|
118
123
|
local proposal_id="$2"
|
|
119
124
|
local new_status="$3"
|
|
120
|
-
local extra_json="${4:-
|
|
125
|
+
local extra_json="${4:-}"
|
|
126
|
+
[ -z "$extra_json" ] && extra_json='{}'
|
|
121
127
|
[[ -z "$key" || -z "$proposal_id" || -z "$new_status" ]] && return 1
|
|
122
128
|
|
|
123
129
|
local path
|
|
@@ -324,6 +330,343 @@ librarian_cli_status() {
|
|
|
324
330
|
printf 'pending: %s, accepted: %s, rejected: %s\n' "$pending" "$accepted" "$rejected"
|
|
325
331
|
}
|
|
326
332
|
|
|
333
|
+
# ----------------------------------------------------------------------------
|
|
334
|
+
# Lesson confirmation surface
|
|
335
|
+
#
|
|
336
|
+
# Namespaced under `lessons` and kept apart from the memory verbs on purpose.
|
|
337
|
+
# Accepting a memory writes a file on this machine; confirming a lesson commits
|
|
338
|
+
# it toward leaving this machine, irreversibly once synced. Those two decisions
|
|
339
|
+
# should not sit one keystroke apart.
|
|
340
|
+
# ----------------------------------------------------------------------------
|
|
341
|
+
|
|
342
|
+
# Usage: librarian_cli_lessons_list [--confirmed] [cwd]
|
|
343
|
+
#
|
|
344
|
+
# Bare `list` shows the pending queue the review walk drives. `--confirmed`
|
|
345
|
+
# shows lessons already confirmed and not yet judged, which is otherwise
|
|
346
|
+
# undiscoverable: unconfirm operates only on a `confirmed` lesson, and the
|
|
347
|
+
# pending list by definition never contains one. Without this view a human who
|
|
348
|
+
# confirmed at the wrong visibility last session has no way back to the id.
|
|
349
|
+
librarian_cli_lessons_list() {
|
|
350
|
+
local status="pending" cwd="" json=0
|
|
351
|
+
while [[ $# -gt 0 ]]; do
|
|
352
|
+
case "$1" in
|
|
353
|
+
--confirmed) status="confirmed"; shift ;;
|
|
354
|
+
--json) json=1; shift ;;
|
|
355
|
+
--*)
|
|
356
|
+
# Same contract as the sibling verbs: an unrecognized flag is
|
|
357
|
+
# refused rather than falling through to the cwd bucket, where
|
|
358
|
+
# it would resolve no project key and report a path problem the
|
|
359
|
+
# caller does not have.
|
|
360
|
+
printf 'unknown option: %s\n' "$1" >&2
|
|
361
|
+
return 1
|
|
362
|
+
;;
|
|
363
|
+
*) cwd="$1"; shift ;;
|
|
364
|
+
esac
|
|
365
|
+
done
|
|
366
|
+
|
|
367
|
+
local key rows
|
|
368
|
+
key=$(_librarian_cli_project_key "$cwd")
|
|
369
|
+
[[ -z "$key" ]] && { printf 'No project key resolvable from this directory.\n'; return 1; }
|
|
370
|
+
rows=$(librarian_lesson_list_by_status "$key" "$status")
|
|
371
|
+
|
|
372
|
+
# Checked before the empty-set branch below: the skill parses this output,
|
|
373
|
+
# and an empty result must still emit `[]`, not the prose empty-state
|
|
374
|
+
# message that follows.
|
|
375
|
+
if [[ "$json" -eq 1 ]]; then
|
|
376
|
+
printf '%s' "$rows"
|
|
377
|
+
return 0
|
|
378
|
+
fi
|
|
379
|
+
|
|
380
|
+
if [[ "$(printf '%s' "$rows" | jq 'length')" -eq 0 ]]; then
|
|
381
|
+
printf 'No %s lessons.\n' "$status"
|
|
382
|
+
return 0
|
|
383
|
+
fi
|
|
384
|
+
printf '%s' "$rows" | jq -r '.[] | "\(.id) \(.candidate.claim)"'
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
librarian_cli_lessons_show() {
|
|
388
|
+
local lesson_id="${1:-}"
|
|
389
|
+
local cwd="${2:-}"
|
|
390
|
+
[[ -z "$lesson_id" ]] && { printf 'usage: librarian_cli lessons show <lesson_id>\n'; return 1; }
|
|
391
|
+
|
|
392
|
+
local key path
|
|
393
|
+
key=$(_librarian_cli_project_key "$cwd")
|
|
394
|
+
[[ -z "$key" ]] && { printf 'No project key resolvable from this directory.\n'; return 1; }
|
|
395
|
+
path="$(librarian_lessons_dir "$key")/proposals/${lesson_id}.json"
|
|
396
|
+
[[ -f "$path" ]] || { printf 'Lesson %s not found.\n' "$lesson_id"; return 1; }
|
|
397
|
+
|
|
398
|
+
# visibility sits next to status because the two are read together: it is
|
|
399
|
+
# the field a human needs to check before deciding whether to unconfirm,
|
|
400
|
+
# and it is only set on a confirmed lesson. A pending one renders `—`
|
|
401
|
+
# rather than a jq `null`, so the absence reads as "not decided yet".
|
|
402
|
+
jq -r '
|
|
403
|
+
"id: \(.id)",
|
|
404
|
+
"status: \(.status)",
|
|
405
|
+
"visibility: \(.visibility // "—")",
|
|
406
|
+
"artifact: \(.artifact_id)",
|
|
407
|
+
"claim: \(.candidate.claim)",
|
|
408
|
+
"rationale: \(.candidate.rationale)",
|
|
409
|
+
"resolution: \(.candidate.evidence.resolution)",
|
|
410
|
+
"stack: \(.candidate.applies_to.stack | join(", "))",
|
|
411
|
+
"scope: \(.candidate.applies_to.scope | tojson)"
|
|
412
|
+
' "$path"
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
librarian_cli_lessons_confirm() {
|
|
416
|
+
local lesson_id="${1:-}"
|
|
417
|
+
local visibility="${2:-}"
|
|
418
|
+
[[ -z "$lesson_id" || -z "$visibility" ]] && {
|
|
419
|
+
printf 'usage: librarian_cli lessons confirm <lesson_id> <private|org|public> [--justification TEXT] [cwd]\n'
|
|
420
|
+
return 1
|
|
421
|
+
}
|
|
422
|
+
shift 2
|
|
423
|
+
|
|
424
|
+
# --justification is a named flag, not a position. This is the verb that
|
|
425
|
+
# commits a lesson toward leaving this machine, so a caller who supplies
|
|
426
|
+
# cwd but omits justification must never have cwd silently misread as the
|
|
427
|
+
# justification that flips scope to version_independent.
|
|
428
|
+
local justification="" justification_given=0 cwd=""
|
|
429
|
+
while [[ $# -gt 0 ]]; do
|
|
430
|
+
case "$1" in
|
|
431
|
+
--justification)
|
|
432
|
+
justification="${2:-}"
|
|
433
|
+
justification_given=1
|
|
434
|
+
if [[ $# -ge 2 ]]; then
|
|
435
|
+
shift 2
|
|
436
|
+
else
|
|
437
|
+
shift 1
|
|
438
|
+
fi
|
|
439
|
+
;;
|
|
440
|
+
--*)
|
|
441
|
+
# An unrecognized flag must never fall through to the cwd
|
|
442
|
+
# bucket below: a typo'd --justifcation would otherwise be
|
|
443
|
+
# swallowed here, its value would land as a plain positional
|
|
444
|
+
# (misread as cwd, then overwritten by the real trailing
|
|
445
|
+
# path), and the lesson would confirm with an empty
|
|
446
|
+
# justification and no diagnostic — a persisted wrong state
|
|
447
|
+
# this CLI has no verb to undo.
|
|
448
|
+
printf 'unknown option: %s\n' "$1" >&2
|
|
449
|
+
return 1
|
|
450
|
+
;;
|
|
451
|
+
*)
|
|
452
|
+
cwd="$1"
|
|
453
|
+
shift
|
|
454
|
+
;;
|
|
455
|
+
esac
|
|
456
|
+
done
|
|
457
|
+
|
|
458
|
+
# A justification that is blank after trimming whitespace is refused
|
|
459
|
+
# outright rather than silently treated as "no justification supplied" —
|
|
460
|
+
# the validator's minLength: 1 counts whitespace, so passing it through
|
|
461
|
+
# would flip scope to version_independent on content nobody actually
|
|
462
|
+
# wrote.
|
|
463
|
+
if [[ "$justification_given" -eq 1 ]] && [[ "$justification" =~ ^[[:space:]]*$ ]]; then
|
|
464
|
+
printf 'justification is blank after trimming whitespace; omit --justification instead of passing an empty value.\n' >&2
|
|
465
|
+
return 1
|
|
466
|
+
fi
|
|
467
|
+
|
|
468
|
+
local key
|
|
469
|
+
key=$(_librarian_cli_project_key "$cwd")
|
|
470
|
+
[[ -z "$key" ]] && { printf 'No project key resolvable from this directory.\n'; return 1; }
|
|
471
|
+
|
|
472
|
+
librarian_lesson_confirm "$key" "$lesson_id" "$visibility" "$justification" || return 1
|
|
473
|
+
printf 'Confirmed %s at %s visibility.\n' "$lesson_id" "$visibility"
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
librarian_cli_lessons_pass() {
|
|
477
|
+
local lesson_id="${1:-}"
|
|
478
|
+
local reason="${2:-}"
|
|
479
|
+
local cwd="${3:-}"
|
|
480
|
+
[[ -z "$lesson_id" ]] && { printf 'usage: librarian_cli lessons pass <lesson_id> [reason]\n'; return 1; }
|
|
481
|
+
|
|
482
|
+
# reason and cwd are positional, not flags — but a flag-shaped token here
|
|
483
|
+
# is almost always a typo for confirm's `--justification` (the likeliest
|
|
484
|
+
# guess is `--reason`). Reject it rather than silently accepting it as
|
|
485
|
+
# the literal reason: librarian_lesson_pass writes to the append-only
|
|
486
|
+
# passed.jsonl ledger with no CLI verb to correct a bad line afterward.
|
|
487
|
+
case "$reason" in
|
|
488
|
+
--*) printf 'unknown option: %s\n' "$reason" >&2; return 1 ;;
|
|
489
|
+
esac
|
|
490
|
+
case "$cwd" in
|
|
491
|
+
--*) printf 'unknown option: %s\n' "$cwd" >&2; return 1 ;;
|
|
492
|
+
esac
|
|
493
|
+
|
|
494
|
+
local key
|
|
495
|
+
key=$(_librarian_cli_project_key "$cwd")
|
|
496
|
+
[[ -z "$key" ]] && { printf 'No project key resolvable from this directory.\n'; return 1; }
|
|
497
|
+
|
|
498
|
+
librarian_lesson_pass "$key" "$lesson_id" "$reason" || return 1
|
|
499
|
+
printf 'Passed on %s.\n' "$lesson_id"
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
librarian_cli_lessons_unconfirm() {
|
|
503
|
+
local lesson_id="${1:-}"
|
|
504
|
+
local cwd="${2:-}"
|
|
505
|
+
[[ -z "$lesson_id" ]] && { printf 'usage: librarian_cli lessons unconfirm <lesson_id>\n'; return 1; }
|
|
506
|
+
|
|
507
|
+
# Reject a flag-shaped token rather than treating it as cwd. The sibling
|
|
508
|
+
# verbs already do this; a stray flag absorbed as a path resolves to the
|
|
509
|
+
# wrong project key and the verb then reports success against a lesson it
|
|
510
|
+
# never touched. Here that write-safety case can't actually arise — cwd
|
|
511
|
+
# is the last positional, so an invalid one (e.g. "--force") already
|
|
512
|
+
# fails project-key resolution below and returns 1 with no write. This
|
|
513
|
+
# guard is a diagnostic, not a write guard: it swaps that generic "No
|
|
514
|
+
# project key resolvable" for "unknown option: --force" so the caller
|
|
515
|
+
# isn't sent hunting a path problem they don't have. Keep it for that
|
|
516
|
+
# reason even though it looks redundant next to confirm's and pass's.
|
|
517
|
+
case "$cwd" in
|
|
518
|
+
--*) printf 'unknown option: %s\n' "$cwd" >&2; return 1 ;;
|
|
519
|
+
esac
|
|
520
|
+
|
|
521
|
+
local key
|
|
522
|
+
key=$(_librarian_cli_project_key "$cwd")
|
|
523
|
+
[[ -z "$key" ]] && { printf 'No project key resolvable from this directory.\n'; return 1; }
|
|
524
|
+
|
|
525
|
+
# Read the status before the call so the message can tell "took back a
|
|
526
|
+
# confirmation" apart from "it was already pending". librarian_lesson_unconfirm
|
|
527
|
+
# returns 0 for both by design — 0 means "the lesson is pending now" — and
|
|
528
|
+
# keeping that contract single-valued is what lets callers stay simple, so
|
|
529
|
+
# the distinction is made here rather than by widening the return.
|
|
530
|
+
#
|
|
531
|
+
# A status changing between this read and the call can only misword the
|
|
532
|
+
# message; the write itself is guarded inside librarian_lesson_unconfirm,
|
|
533
|
+
# which re-reads the file and refuses anything that is not `confirmed`.
|
|
534
|
+
local prior_status
|
|
535
|
+
prior_status=$(jq -r '.status // ""' \
|
|
536
|
+
"$(librarian_lessons_dir "$key")/proposals/${lesson_id}.json" 2>/dev/null)
|
|
537
|
+
|
|
538
|
+
librarian_lesson_unconfirm "$key" "$lesson_id" || return 1
|
|
539
|
+
if [[ "$prior_status" == "pending" ]]; then
|
|
540
|
+
printf 'Lesson %s was already pending; nothing to take back.\n' "$lesson_id"
|
|
541
|
+
else
|
|
542
|
+
printf 'Unconfirmed %s; it is pending again.\n' "$lesson_id"
|
|
543
|
+
fi
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
# Usage: librarian_cli_lessons_judge <lesson_id> <verdicts-json> [cwd]
|
|
547
|
+
#
|
|
548
|
+
# Verdicts come from the judge subagents the skill dispatched. Exit 2 means the
|
|
549
|
+
# candidate could not be judged and stays confirmed — distinct from a rejection,
|
|
550
|
+
# which is a real verdict and exits 0.
|
|
551
|
+
librarian_cli_lessons_judge() {
|
|
552
|
+
local lesson_id="" verdicts="" cwd=""
|
|
553
|
+
local positional=0
|
|
554
|
+
while [[ $# -gt 0 ]]; do
|
|
555
|
+
case "$1" in
|
|
556
|
+
--*)
|
|
557
|
+
printf 'unknown option: %s\n' "$1" >&2
|
|
558
|
+
return 1
|
|
559
|
+
;;
|
|
560
|
+
*)
|
|
561
|
+
case "$positional" in
|
|
562
|
+
0) lesson_id="$1" ;;
|
|
563
|
+
1) verdicts="$1" ;;
|
|
564
|
+
*) cwd="$1" ;;
|
|
565
|
+
esac
|
|
566
|
+
positional=$((positional + 1))
|
|
567
|
+
shift
|
|
568
|
+
;;
|
|
569
|
+
esac
|
|
570
|
+
done
|
|
571
|
+
|
|
572
|
+
if [[ -z "$lesson_id" || -z "$verdicts" ]]; then
|
|
573
|
+
printf 'usage: librarian_cli lessons judge <lesson_id> <verdicts-json> [cwd]\n'
|
|
574
|
+
return 1
|
|
575
|
+
fi
|
|
576
|
+
|
|
577
|
+
local key
|
|
578
|
+
key=$(_librarian_cli_project_key "$cwd")
|
|
579
|
+
[[ -z "$key" ]] && { printf 'No project key resolvable from this directory.\n'; return 1; }
|
|
580
|
+
|
|
581
|
+
librarian_lesson_judge "$key" "$lesson_id" "$verdicts"
|
|
582
|
+
local rc=$?
|
|
583
|
+
case "$rc" in
|
|
584
|
+
0)
|
|
585
|
+
printf 'Lesson %s is now %s.\n' "$lesson_id" \
|
|
586
|
+
"$(jq -r '.status' "$(librarian_lessons_dir "$key")/proposals/${lesson_id}.json")"
|
|
587
|
+
# Promotion failing does not undo a correct verdict: report it and
|
|
588
|
+
# leave the lesson promotable by a standalone `lessons promote`.
|
|
589
|
+
librarian_lesson_promote "$key" "$lesson_id" \
|
|
590
|
+
|| printf 'Lesson %s was judged but not promoted; run `lessons promote %s` to retry.\n' \
|
|
591
|
+
"$lesson_id" "$lesson_id"
|
|
592
|
+
;;
|
|
593
|
+
2)
|
|
594
|
+
printf 'Lesson %s could not be judged; it stays confirmed. Re-run to retry.\n' "$lesson_id"
|
|
595
|
+
;;
|
|
596
|
+
*)
|
|
597
|
+
printf 'Lesson %s could not be judged (exit %d); see above.\n' "$lesson_id" "$rc"
|
|
598
|
+
;;
|
|
599
|
+
esac
|
|
600
|
+
return $rc
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
# Usage: librarian_cli_lessons_promote <lesson_id> [cwd]
|
|
604
|
+
#
|
|
605
|
+
# Runnable standalone on purpose: promotion fails for reasons judging does not
|
|
606
|
+
# — a malformed author secret, absent node, a full disk — and a standalone run
|
|
607
|
+
# is how a correctly-judged, not-yet-promoted lesson gets reconciled.
|
|
608
|
+
librarian_cli_lessons_promote() {
|
|
609
|
+
local lesson_id="" cwd=""
|
|
610
|
+
local positional=0
|
|
611
|
+
while [[ $# -gt 0 ]]; do
|
|
612
|
+
case "$1" in
|
|
613
|
+
--*)
|
|
614
|
+
printf 'unknown option: %s\n' "$1" >&2
|
|
615
|
+
return 1
|
|
616
|
+
;;
|
|
617
|
+
*)
|
|
618
|
+
case "$positional" in
|
|
619
|
+
0) lesson_id="$1" ;;
|
|
620
|
+
*) cwd="$1" ;;
|
|
621
|
+
esac
|
|
622
|
+
positional=$((positional + 1))
|
|
623
|
+
shift
|
|
624
|
+
;;
|
|
625
|
+
esac
|
|
626
|
+
done
|
|
627
|
+
|
|
628
|
+
[[ -z "$lesson_id" ]] && { printf 'usage: librarian_cli lessons promote <lesson_id> [cwd]\n'; return 1; }
|
|
629
|
+
|
|
630
|
+
local key
|
|
631
|
+
key=$(_librarian_cli_project_key "$cwd")
|
|
632
|
+
[[ -z "$key" ]] && { printf 'No project key resolvable from this directory.\n'; return 1; }
|
|
633
|
+
|
|
634
|
+
librarian_lesson_promote "$key" "$lesson_id" || return 1
|
|
635
|
+
printf 'Lesson %s promoted.\n' "$lesson_id"
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
librarian_cli_lessons_defer() {
|
|
639
|
+
local lesson_id="${1:-}"
|
|
640
|
+
[[ -z "$lesson_id" ]] && { printf 'usage: librarian_cli lessons defer <lesson_id>\n'; return 1; }
|
|
641
|
+
printf 'Deferred %s; it stays in the queue.\n' "$lesson_id"
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
librarian_cli_lessons_status() {
|
|
645
|
+
local cwd="${1:-}"
|
|
646
|
+
local key pending
|
|
647
|
+
key=$(_librarian_cli_project_key "$cwd")
|
|
648
|
+
[[ -z "$key" ]] && { printf 'No project key resolvable from this directory.\n'; return 1; }
|
|
649
|
+
pending=$(librarian_lesson_list_pending "$key")
|
|
650
|
+
printf 'lessons pending: %s\n' "$(printf '%s' "$pending" | jq 'length')"
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
librarian_cli_lessons() {
|
|
654
|
+
local verb="${1:-list}"
|
|
655
|
+
shift || true
|
|
656
|
+
case "$verb" in
|
|
657
|
+
list) librarian_cli_lessons_list "$@" ;;
|
|
658
|
+
show) librarian_cli_lessons_show "$@" ;;
|
|
659
|
+
confirm) librarian_cli_lessons_confirm "$@" ;;
|
|
660
|
+
pass) librarian_cli_lessons_pass "$@" ;;
|
|
661
|
+
unconfirm) librarian_cli_lessons_unconfirm "$@" ;;
|
|
662
|
+
judge) librarian_cli_lessons_judge "$@" ;;
|
|
663
|
+
promote) librarian_cli_lessons_promote "$@" ;;
|
|
664
|
+
defer) librarian_cli_lessons_defer "$@" ;;
|
|
665
|
+
status) librarian_cli_lessons_status "$@" ;;
|
|
666
|
+
*) printf 'unknown lessons action: %s\n' "$verb"; return 2 ;;
|
|
667
|
+
esac
|
|
668
|
+
}
|
|
669
|
+
|
|
327
670
|
librarian_cli() {
|
|
328
671
|
local action="${1:-list}"
|
|
329
672
|
shift || true
|
|
@@ -334,6 +677,7 @@ librarian_cli() {
|
|
|
334
677
|
reject) librarian_cli_reject "$@" ;;
|
|
335
678
|
defer) librarian_cli_defer "$@" ;;
|
|
336
679
|
status) librarian_cli_status "$@" ;;
|
|
680
|
+
lessons) librarian_cli_lessons "$@" ;;
|
|
337
681
|
*) printf 'unknown action: %s\n' "$action"; return 2 ;;
|
|
338
682
|
esac
|
|
339
683
|
}
|
|
@@ -50,7 +50,8 @@ _LIBRARIAN_EVENT_JS="${_LIBRARIAN_EVENT_JS:-$(_librarian_resolve_event_js)}"
|
|
|
50
50
|
librarian_emit() {
|
|
51
51
|
local event_type="${1:-}"
|
|
52
52
|
local session_id="${2:-}"
|
|
53
|
-
local payload="${3:-
|
|
53
|
+
local payload="${3:-}"
|
|
54
|
+
[ -z "$payload" ] && payload='{}'
|
|
54
55
|
|
|
55
56
|
[[ -z "$event_type" || -z "$session_id" ]] && return 0
|
|
56
57
|
[[ -z "$_LIBRARIAN_EVENT_JS" || ! -f "$_LIBRARIAN_EVENT_JS" ]] && return 0
|