@onlooker-community/ecosystem 0.43.7 → 0.44.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-plugin/plugin.json +1 -1
- package/.release-please-manifest.json +2 -2
- package/CHANGELOG.md +7 -0
- package/package.json +1 -1
- package/plugins/librarian/.claude-plugin/plugin.json +1 -1
- package/plugins/librarian/CHANGELOG.md +7 -0
- package/plugins/librarian/scripts/lib/librarian-cli.sh +34 -3
- package/plugins/librarian/skills/librarian/SKILL.md +15 -4
- package/test/bats/librarian-lesson-review.bats +89 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ecosystem",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.44.0",
|
|
4
4
|
"description": "Observability substrate for Claude Code. Provides the shared $ONLOOKER_DIR storage root (default $HOME/.onlooker), canonical schema-validated event emission, session and tool tracking hooks, and prompt rules. Required by all other Onlooker plugins.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Onlooker Community",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
".": "0.
|
|
2
|
+
".": "0.44.0",
|
|
3
3
|
"plugins/archivist": "0.3.2",
|
|
4
4
|
"plugins/tribunal": "1.2.8",
|
|
5
5
|
"plugins/echo": "0.3.2",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"plugins/scribe": "0.4.3",
|
|
10
10
|
"plugins/counsel": "0.5.2",
|
|
11
11
|
"plugins/warden": "0.3.2",
|
|
12
|
-
"plugins/librarian": "0.
|
|
12
|
+
"plugins/librarian": "0.14.0",
|
|
13
13
|
"plugins/curator": "0.2.4",
|
|
14
14
|
"plugins/historian": "0.3.4",
|
|
15
15
|
"plugins/assayer": "1.1.4",
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.44.0](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.43.7...ecosystem-v0.44.0) (2026-08-23)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **librarian:** let lessons status close the judge walk :abacus: ([#205](https://github.com/onlooker-community/ecosystem/issues/205)) ([8da1cd7](https://github.com/onlooker-community/ecosystem/commit/8da1cd72a7e564aae44750efaa1e59f1ecd59641))
|
|
9
|
+
|
|
3
10
|
## [0.43.7](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.43.6...ecosystem-v0.43.7) (2026-08-23)
|
|
4
11
|
|
|
5
12
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "librarian",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Consolidation layer between archivist's per-session artifacts and the user's durable typed memory store. Detects which session decisions, dead-ends, and open questions deserve to live across sessions, classifies them into the user/feedback/project/reference types, and queues them as proposals for explicit confirmation. Auto-promotion is opt-in. Builds on the Onlooker ecosystem plugin.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Onlooker Community",
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.14.0](https://github.com/onlooker-community/ecosystem/compare/librarian-v0.13.3...librarian-v0.14.0) (2026-08-23)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **librarian:** let lessons status close the judge walk :abacus: ([#205](https://github.com/onlooker-community/ecosystem/issues/205)) ([8da1cd7](https://github.com/onlooker-community/ecosystem/commit/8da1cd72a7e564aae44750efaa1e59f1ecd59641))
|
|
9
|
+
|
|
3
10
|
## [0.13.3](https://github.com/onlooker-community/ecosystem/compare/librarian-v0.13.2...librarian-v0.13.3) (2026-08-22)
|
|
4
11
|
|
|
5
12
|
|
|
@@ -641,13 +641,44 @@ librarian_cli_lessons_defer() {
|
|
|
641
641
|
printf 'Deferred %s; it stays in the queue.\n' "$lesson_id"
|
|
642
642
|
}
|
|
643
643
|
|
|
644
|
+
# One authoritative line for the whole lesson queue.
|
|
645
|
+
#
|
|
646
|
+
# Reports a count per status rather than pending alone, because the judge walk
|
|
647
|
+
# closes on this call. It used to close on counts the model had tallied itself
|
|
648
|
+
# across the loop, with nothing to check them against — every other walk in the
|
|
649
|
+
# skill ends on a CLI call, and this one had none to end on (ecosystem-sv3).
|
|
650
|
+
#
|
|
651
|
+
# `awaiting promotion` is the walk's fourth bucket: a lesson whose verdict is
|
|
652
|
+
# recorded but whose pool entry or declined row has not landed. promote()
|
|
653
|
+
# stamps promoted_at LAST, after the terminal record, so a terminal status with
|
|
654
|
+
# no stamp is exactly that state — and it must not be folded into `approved`,
|
|
655
|
+
# which would claim a pool entry that does not exist.
|
|
656
|
+
#
|
|
657
|
+
# The walk's remaining bucket, could-not-judge, is deliberately absent: such a
|
|
658
|
+
# candidate stays `confirmed`, which is indistinguishable on disk from one that
|
|
659
|
+
# was never judged this run. That count is run-scoped and stays the model's.
|
|
644
660
|
librarian_cli_lessons_status() {
|
|
645
661
|
local cwd="${1:-}"
|
|
646
|
-
local key
|
|
662
|
+
local key
|
|
647
663
|
key=$(_librarian_cli_project_key "$cwd")
|
|
648
664
|
[[ -z "$key" ]] && { printf 'No project key resolvable from this directory.\n'; return 1; }
|
|
649
|
-
|
|
650
|
-
|
|
665
|
+
|
|
666
|
+
local s counts=()
|
|
667
|
+
for s in pending confirmed approved rejected; do
|
|
668
|
+
counts+=("$(librarian_lesson_list_by_status "$key" "$s" | jq 'length')")
|
|
669
|
+
done
|
|
670
|
+
|
|
671
|
+
# A terminal verdict whose promote() never stamped. Counted from the same
|
|
672
|
+
# per-status reads rather than a second directory walk.
|
|
673
|
+
local awaiting=0 n
|
|
674
|
+
for s in approved rejected; do
|
|
675
|
+
n=$(librarian_lesson_list_by_status "$key" "$s" \
|
|
676
|
+
| jq '[.[] | select(has("promoted_at") | not)] | length')
|
|
677
|
+
awaiting=$(( awaiting + n ))
|
|
678
|
+
done
|
|
679
|
+
|
|
680
|
+
printf 'lessons pending: %s, confirmed: %s, approved: %s, rejected: %s, awaiting promotion: %s\n' \
|
|
681
|
+
"${counts[0]}" "${counts[1]}" "${counts[2]}" "${counts[3]}" "$awaiting"
|
|
651
682
|
}
|
|
652
683
|
|
|
653
684
|
librarian_cli_lessons() {
|
|
@@ -141,10 +141,21 @@ For `lessons judge`, run the jury over confirmed candidates:
|
|
|
141
141
|
those ids and list them at the end so the user knows to re-run. A broken judge
|
|
142
142
|
must never become a rejection — the artifact's watermark has already moved,
|
|
143
143
|
so a false rejection buries a good lesson permanently.
|
|
144
|
-
5. Finish
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
144
|
+
5. **Finish on `librarian_cli lessons status`, not on your own tally.** It
|
|
145
|
+
prints one line — pending, confirmed, approved, rejected, and **awaiting
|
|
146
|
+
promotion** — read from disk, so it is the same kind of authoritative close
|
|
147
|
+
the review walk ends on. Report those numbers as it gives them; a long batch
|
|
148
|
+
is exactly where a running count kept in your head drifts.
|
|
149
|
+
|
|
150
|
+
Two things the call cannot tell you, which you must still report yourself:
|
|
151
|
+
|
|
152
|
+
- **could-not-judge** — those candidates stay `confirmed`, which on disk is
|
|
153
|
+
indistinguishable from a candidate that was never judged this run. Keep
|
|
154
|
+
the ids from step 4 and list them.
|
|
155
|
+
- **which** lessons are awaiting promotion. The call gives the count; you
|
|
156
|
+
have the ids. List them with `librarian_cli lessons promote <id>` as the
|
|
157
|
+
next step, and don't fold them into "approved" — a lesson here has no pool
|
|
158
|
+
entry yet. If your ids and the count disagree, trust the count and say so.
|
|
148
159
|
|
|
149
160
|
`scope_accuracy` is the criterion that matters most on a `version_independent`
|
|
150
161
|
candidate. The schema guarantees such a lesson **carries** a justification; this
|
|
@@ -387,6 +387,29 @@ _cli_setup() {
|
|
|
387
387
|
source "${PLUGIN_ROOT}/scripts/lib/librarian-cli.sh"
|
|
388
388
|
}
|
|
389
389
|
|
|
390
|
+
# ── lessons status: a count per status (ecosystem-sv3) ───────────────────────
|
|
391
|
+
#
|
|
392
|
+
# The judge walk used to close by reporting counts the model tracked itself
|
|
393
|
+
# across the loop, with nothing to check them against — every other walk in the
|
|
394
|
+
# skill ends on an authoritative CLI call. `lessons status` reported only a
|
|
395
|
+
# pending count, so there was nothing to ground the summary on.
|
|
396
|
+
|
|
397
|
+
# Force a proposal to a terminal status on disk. Reaching `approved` through
|
|
398
|
+
# the real path means empaneling a jury, which is what the judge walk exists to
|
|
399
|
+
# avoid doing twice; the status field is what the counter reads.
|
|
400
|
+
_set_status() {
|
|
401
|
+
local id="$1" status="$2" promoted="${3:-}"
|
|
402
|
+
local f
|
|
403
|
+
f="$(librarian_lessons_dir "$PROJECT_KEY")/proposals/${id}.json"
|
|
404
|
+
local tmp="${f}.tmp"
|
|
405
|
+
if [[ -n "$promoted" ]]; then
|
|
406
|
+
jq --arg s "$status" --arg p "$promoted" '.status = $s | .promoted_at = $p' "$f" >"$tmp"
|
|
407
|
+
else
|
|
408
|
+
jq --arg s "$status" '.status = $s | del(.promoted_at)' "$f" >"$tmp"
|
|
409
|
+
fi
|
|
410
|
+
mv -f "$tmp" "$f"
|
|
411
|
+
}
|
|
412
|
+
|
|
390
413
|
@test "lessons status reports zero on an empty queue" {
|
|
391
414
|
_cli_setup
|
|
392
415
|
run librarian_cli lessons status "$PROJECT_REPO"
|
|
@@ -394,6 +417,72 @@ _cli_setup() {
|
|
|
394
417
|
[[ "$output" == *"0"* ]] || return 1
|
|
395
418
|
}
|
|
396
419
|
|
|
420
|
+
@test "lessons status reports a count for every status, not just pending" {
|
|
421
|
+
_cli_setup
|
|
422
|
+
local a b c d
|
|
423
|
+
a=$(_seed_pending)
|
|
424
|
+
b=$(_seed_pending)
|
|
425
|
+
c=$(_seed_pending)
|
|
426
|
+
d=$(_seed_pending)
|
|
427
|
+
librarian_lesson_confirm "$PROJECT_KEY" "$b" "org"
|
|
428
|
+
_set_status "$c" "approved" "2026-08-01T00:00:00Z"
|
|
429
|
+
_set_status "$d" "rejected" "2026-08-01T00:00:00Z"
|
|
430
|
+
|
|
431
|
+
run librarian_cli lessons status "$PROJECT_REPO"
|
|
432
|
+
[ "$status" -eq 0 ] || return 1
|
|
433
|
+
[[ "$output" == *"pending: 1"* ]] || return 1
|
|
434
|
+
[[ "$output" == *"confirmed: 1"* ]] || return 1
|
|
435
|
+
[[ "$output" == *"approved: 1"* ]] || return 1
|
|
436
|
+
[[ "$output" == *"rejected: 1"* ]]
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
@test "lessons status counts a judged-but-unpromoted lesson separately" {
|
|
440
|
+
# The judge walk's fourth bucket. promote() stamps promoted_at LAST, after
|
|
441
|
+
# the terminal record lands, so a terminal status with no stamp is exactly
|
|
442
|
+
# the state the walk is told not to fold into "approved" — the lesson has
|
|
443
|
+
# no pool entry yet.
|
|
444
|
+
_cli_setup
|
|
445
|
+
local a b
|
|
446
|
+
a=$(_seed_pending)
|
|
447
|
+
b=$(_seed_pending)
|
|
448
|
+
_set_status "$a" "approved" "2026-08-01T00:00:00Z"
|
|
449
|
+
_set_status "$b" "approved"
|
|
450
|
+
|
|
451
|
+
run librarian_cli lessons status "$PROJECT_REPO"
|
|
452
|
+
[ "$status" -eq 0 ] || return 1
|
|
453
|
+
[[ "$output" == *"approved: 2"* ]] || return 1
|
|
454
|
+
[[ "$output" == *"awaiting promotion: 1"* ]]
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
@test "lessons status reports awaiting promotion for a rejected lesson too" {
|
|
458
|
+
# A rejected verdict also lands its terminal record (the declined row)
|
|
459
|
+
# before the stamp, so the same recovery state exists on that side.
|
|
460
|
+
_cli_setup
|
|
461
|
+
local a b
|
|
462
|
+
a=$(_seed_pending)
|
|
463
|
+
b=$(_seed_pending)
|
|
464
|
+
_set_status "$a" "rejected"
|
|
465
|
+
# A promoted sibling, so the count cannot come out right by counting every
|
|
466
|
+
# rejected lesson — without it this passes whether or not the stamp is read.
|
|
467
|
+
_set_status "$b" "rejected" "2026-08-01T00:00:00Z"
|
|
468
|
+
|
|
469
|
+
run librarian_cli lessons status "$PROJECT_REPO"
|
|
470
|
+
[ "$status" -eq 0 ] || return 1
|
|
471
|
+
[[ "$output" == *"rejected: 2"* ]] || return 1
|
|
472
|
+
[[ "$output" == *"awaiting promotion: 1"* ]]
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
@test "lessons status reports zeros across every status on an empty queue" {
|
|
476
|
+
_cli_setup
|
|
477
|
+
run librarian_cli lessons status "$PROJECT_REPO"
|
|
478
|
+
[ "$status" -eq 0 ] || return 1
|
|
479
|
+
[[ "$output" == *"pending: 0"* ]] || return 1
|
|
480
|
+
[[ "$output" == *"confirmed: 0"* ]] || return 1
|
|
481
|
+
[[ "$output" == *"approved: 0"* ]] || return 1
|
|
482
|
+
[[ "$output" == *"rejected: 0"* ]] || return 1
|
|
483
|
+
[[ "$output" == *"awaiting promotion: 0"* ]]
|
|
484
|
+
}
|
|
485
|
+
|
|
397
486
|
@test "lessons list shows a pending lesson" {
|
|
398
487
|
_cli_setup
|
|
399
488
|
id=$(_seed_pending)
|