artshelf 0.9.0 → 0.10.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/CHANGELOG.md +24 -0
- package/README.md +4 -1
- package/SPEC.md +25 -2
- package/dist/src/cli.js +352 -24
- package/docs/agent-monitor.html +10 -2
- package/docs/agent-review.html +8 -2
- package/docs/agent-usage.html +14 -0
- package/docs/agent-usage.md +17 -0
- package/docs/reference.html +25 -8
- package/package.json +1 -1
- package/skills/artshelf/SKILL.md +18 -20
package/CHANGELOG.md
CHANGED
|
@@ -64,6 +64,30 @@
|
|
|
64
64
|
and `artshelf ledgers help` aliases, advertised short `-h`/`-v` flags, and
|
|
65
65
|
reclassified `--ledger`, `--registry`, and `--all` as command-specific scope
|
|
66
66
|
flags instead of global options.
|
|
67
|
+
- Added an `--agent` render mode to `artshelf review`, `status`, and `doctor`: a
|
|
68
|
+
compact, deterministic single-line JSON decision packet (health, counts,
|
|
69
|
+
attention categories or classified decision groups, blockers, the next safe
|
|
70
|
+
action, and a verification command) tuned for agents acting on results.
|
|
71
|
+
`--agent` takes precedence over `--json`, while `--json` stays the full,
|
|
72
|
+
backward-compatible audit report. The default human renders of these three
|
|
73
|
+
commands now lead each ledger and summary line with a `✓`/`⚠` attention glyph
|
|
74
|
+
(plain Unicode, no color) so redirected output stays clean.
|
|
75
|
+
|
|
76
|
+
## [0.10.0](https://github.com/calvinnwq/artshelf/compare/artshelf-v0.9.0...artshelf-v0.10.0) (2026-06-12)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
### Features
|
|
80
|
+
|
|
81
|
+
* **cli:** add --agent decision-packet render mode for review, status, and doctor ([4d2dee0](https://github.com/calvinnwq/artshelf/commit/4d2dee099569803b887ae49438b0747d1330ec5d))
|
|
82
|
+
* **cli:** add --agent render mode and implement status --agent ([36f8e78](https://github.com/calvinnwq/artshelf/commit/36f8e7839d535fcabddadfc616ba518a9b444114))
|
|
83
|
+
* **cli:** add ✓/⚠ attention glyphs to human renders of status/doctor/review ([6f6cbe8](https://github.com/calvinnwq/artshelf/commit/6f6cbe85d54886cfd137791863e1b3554ca908f0))
|
|
84
|
+
* **cli:** implement artshelf doctor --agent compact decision packet ([d9abd4e](https://github.com/calvinnwq/artshelf/commit/d9abd4e75a7f4b2898eeacc3b3404221f4456bd4))
|
|
85
|
+
* **cli:** implement artshelf review --agent compact decision packet ([6f5476c](https://github.com/calvinnwq/artshelf/commit/6f5476ca987de3190f7a8760c6bb9c1efa8b9fce))
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
### Bug Fixes
|
|
89
|
+
|
|
90
|
+
* **cli:** preserve ledger scope in agent next actions ([a583683](https://github.com/calvinnwq/artshelf/commit/a583683064cdd16dd929766dc01f23fc31fa50e7))
|
|
67
91
|
|
|
68
92
|
## [0.9.0](https://github.com/calvinnwq/artshelf/compare/artshelf-v0.8.0...artshelf-v0.9.0) (2026-06-11)
|
|
69
93
|
|
package/README.md
CHANGED
|
@@ -112,6 +112,8 @@ destructive deletion.
|
|
|
112
112
|
- **Trash before delete** — `cleanup=delete` stays refused; physical deletion
|
|
113
113
|
needs its own reviewed trash purge. No silent deletion, ever.
|
|
114
114
|
- **`--json` on every command**, so agents can act on structured output.
|
|
115
|
+
- **`--agent` on `review`/`status`/`doctor`**, a compact, token-efficient
|
|
116
|
+
decision packet for agents, while the default render stays human-scannable.
|
|
115
117
|
|
|
116
118
|
## Reference
|
|
117
119
|
|
|
@@ -143,7 +145,8 @@ artshelf resolve <id> --status resolved --reason "inspected and no longer needed
|
|
|
143
145
|
Use `artshelf help` for a grouped command list, then `artshelf <command> --help`
|
|
144
146
|
or `artshelf help <command>` for focused details. Nested commands such as
|
|
145
147
|
`artshelf trash purge --help` and `artshelf ledgers add --help` show only that
|
|
146
|
-
subcommand. All core commands support `--json`;
|
|
148
|
+
subcommand. All core commands support `--json`; `review`, `status`, and `doctor`
|
|
149
|
+
also take `--agent` for a compact decision packet; `--ledger`, `--registry`, and
|
|
147
150
|
`--all` are scope flags only on commands that list them.
|
|
148
151
|
</details>
|
|
149
152
|
|
package/SPEC.md
CHANGED
|
@@ -242,7 +242,9 @@ files or writing a plan.
|
|
|
242
242
|
|
|
243
243
|
```bash
|
|
244
244
|
artshelf review --json
|
|
245
|
+
artshelf review --agent
|
|
245
246
|
artshelf review --all --json
|
|
247
|
+
artshelf review --all --agent
|
|
246
248
|
```
|
|
247
249
|
|
|
248
250
|
`review` is the compact report surface for scheduled checks. `--all` reads every
|
|
@@ -257,6 +259,16 @@ triage count and states the same next safe action (repair broken ledgers, dry-ru
|
|
|
257
259
|
cleanup, inspect missing paths, or nothing to do). Review never writes a plan, so
|
|
258
260
|
the next action always points at an explicit follow-up command.
|
|
259
261
|
|
|
262
|
+
`review`, `status`, and `doctor` share three render modes. The default human
|
|
263
|
+
render leads each ledger and summary line with a `✓`/`⚠` attention glyph; `--json`
|
|
264
|
+
stays the full, backward-compatible audit report; and `--agent` emits a compact,
|
|
265
|
+
deterministic single-line JSON decision packet for agents, taking precedence over
|
|
266
|
+
`--json` when both are passed. For `review`, the packet sorts records into
|
|
267
|
+
ready-for-approval, needs-review-first, and blocked groups. Because review is
|
|
268
|
+
read-only and never mints a cleanup plan, the only exact approval target it emits
|
|
269
|
+
is `resolve missing`; cleanup-eligible records stay needs-review-first and point
|
|
270
|
+
at `cleanup --dry-run`, which mints the reviewed plan id to approve.
|
|
271
|
+
|
|
260
272
|
### `artshelf doctor`
|
|
261
273
|
|
|
262
274
|
Reports whether Artshelf is healthy on the current machine without mutating
|
|
@@ -265,6 +277,7 @@ anything.
|
|
|
265
277
|
```bash
|
|
266
278
|
artshelf doctor
|
|
267
279
|
artshelf doctor --json
|
|
280
|
+
artshelf doctor --agent
|
|
268
281
|
artshelf doctor --ledger <path>
|
|
269
282
|
artshelf doctor --registry <path>
|
|
270
283
|
```
|
|
@@ -284,7 +297,11 @@ A healthy machine exits 0. A broken registry file or any stale or invalid
|
|
|
284
297
|
registered ledger exits non-zero with actionable errors. Humans should run
|
|
285
298
|
`artshelf doctor` after install or when `--all` commands behave unexpectedly; agents
|
|
286
299
|
may run it on a schedule to catch stale registry entries before relying on
|
|
287
|
-
cleanup planning. Doctor never creates plans, receipts, or records.
|
|
300
|
+
cleanup planning. Doctor never creates plans, receipts, or records. Like `review`
|
|
301
|
+
and `status`, `doctor` accepts `--agent` for a compact single-line JSON decision
|
|
302
|
+
packet (health, registry and registered-ledger health, blockers, cleanup-safety
|
|
303
|
+
posture, next action, and a verify command); `--agent` takes precedence over
|
|
304
|
+
`--json`.
|
|
288
305
|
|
|
289
306
|
### `artshelf status`
|
|
290
307
|
|
|
@@ -293,7 +310,9 @@ The lightweight daily "what is going on?" view across ledgers.
|
|
|
293
310
|
```bash
|
|
294
311
|
artshelf status
|
|
295
312
|
artshelf status --json
|
|
313
|
+
artshelf status --agent
|
|
296
314
|
artshelf status --all --json
|
|
315
|
+
artshelf status --all --agent
|
|
297
316
|
artshelf status --all --registry <path> --json
|
|
298
317
|
```
|
|
299
318
|
|
|
@@ -312,7 +331,9 @@ never creates plans or receipts and never mutates records. A healthy machine
|
|
|
312
331
|
exits 0. In `--all` mode, a broken registry or any stale or invalid registered
|
|
313
332
|
ledger exits non-zero. Due entries are normal operational state and do not change
|
|
314
333
|
the exit code. With single `--ledger`, a not-yet-created ledger reports empty
|
|
315
|
-
counts.
|
|
334
|
+
counts. Like `review` and `doctor`, `status` accepts `--agent` for a compact
|
|
335
|
+
single-line JSON decision packet (health, counts, attention categories, blockers,
|
|
336
|
+
next action, and a verify command); `--agent` takes precedence over `--json`.
|
|
316
337
|
|
|
317
338
|
### `artshelf update`
|
|
318
339
|
|
|
@@ -773,6 +794,8 @@ human review.
|
|
|
773
794
|
- Package includes the deterministic `ArtshelfReviewReport` schema, canonical
|
|
774
795
|
example, and portable renderer script for agent-rendered review reports.
|
|
775
796
|
- All core commands support `--json`.
|
|
797
|
+
- `review`, `status`, and `doctor` also support `--agent`, a compact single-line
|
|
798
|
+
JSON decision packet for agents that takes precedence over `--json`.
|
|
776
799
|
- Tests cover record/list/find/get/status-filter/due/validate/resolve/registry,
|
|
777
800
|
`artshelf doctor`, the `artshelf status` dashboard, `--all` review, stale-registry,
|
|
778
801
|
dry-run, global-dry-run, execute-plan, and trash list/purge behavior.
|
package/dist/src/cli.js
CHANGED
|
@@ -9,7 +9,7 @@ const VERSION = readPackageVersion();
|
|
|
9
9
|
const PACKAGE_NAME = "artshelf";
|
|
10
10
|
const NPM_REGISTRY_URL = process.env.ARTSHELF_NPM_REGISTRY_URL ?? `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
|
|
11
11
|
const UPDATE_CHECK_TTL_MS = 24 * 60 * 60 * 1000;
|
|
12
|
-
const BOOLEAN_FLAGS = new Set(["all", "json", "manual-review", "dry-run", "execute", "help", "version", "plain"]);
|
|
12
|
+
const BOOLEAN_FLAGS = new Set(["all", "json", "agent", "manual-review", "dry-run", "execute", "help", "version", "plain"]);
|
|
13
13
|
const VALUE_FLAGS = new Set([
|
|
14
14
|
"cleanup",
|
|
15
15
|
"kind",
|
|
@@ -535,12 +535,17 @@ function handleTrashPurge(parsed, ledgerPath, json) {
|
|
|
535
535
|
return 0;
|
|
536
536
|
}
|
|
537
537
|
function handleReview(parsed, ledgerPath, json) {
|
|
538
|
+
const agent = boolFlag(parsed, "agent");
|
|
538
539
|
if (boolFlag(parsed, "all")) {
|
|
539
540
|
const registryPath = normalizeRegistryPath(stringFlag(parsed, "registry"));
|
|
540
541
|
const results = registeredLedgersOrThrow(registryPath).map((ledger) => reviewLedger(ledger));
|
|
541
542
|
const ok = results.every((entry) => entry.validate.ok);
|
|
542
543
|
const summary = summarizeReview(results);
|
|
543
|
-
|
|
544
|
+
if (agent) {
|
|
545
|
+
printCompactJson(buildReviewAgentPacketAll(results, summary, registryPath));
|
|
546
|
+
return ok ? 0 : 1;
|
|
547
|
+
}
|
|
548
|
+
const nextAction = reviewNextAction(summary, "all");
|
|
544
549
|
if (json) {
|
|
545
550
|
printJson({ ok, registryPath, summary, nextAction, ledgers: results });
|
|
546
551
|
return ok ? 0 : 1;
|
|
@@ -549,6 +554,10 @@ function handleReview(parsed, ledgerPath, json) {
|
|
|
549
554
|
return ok ? 0 : 1;
|
|
550
555
|
}
|
|
551
556
|
const result = reviewLedger({ name: "current", path: ledgerPath, scope: "other", createdAt: "", updatedAt: "" }, false);
|
|
557
|
+
if (agent) {
|
|
558
|
+
printCompactJson(buildReviewAgentPacketSingle(result, ledgerPath));
|
|
559
|
+
return result.validate.ok ? 0 : 1;
|
|
560
|
+
}
|
|
552
561
|
if (json) {
|
|
553
562
|
printJson({ ok: result.validate.ok, ledger: result });
|
|
554
563
|
return result.validate.ok ? 0 : 1;
|
|
@@ -558,6 +567,10 @@ function handleReview(parsed, ledgerPath, json) {
|
|
|
558
567
|
}
|
|
559
568
|
function handleDoctor(parsed, ledgerPath, json) {
|
|
560
569
|
const report = buildDoctorReport(ledgerPath, normalizeRegistryPath(stringFlag(parsed, "registry")));
|
|
570
|
+
if (boolFlag(parsed, "agent")) {
|
|
571
|
+
printCompactJson(buildDoctorAgentPacket(report));
|
|
572
|
+
return report.ok ? 0 : 1;
|
|
573
|
+
}
|
|
561
574
|
if (json) {
|
|
562
575
|
printJson(report);
|
|
563
576
|
return report.ok ? 0 : 1;
|
|
@@ -624,16 +637,72 @@ function buildDoctorReport(ledgerPath, registryPath) {
|
|
|
624
637
|
errors
|
|
625
638
|
};
|
|
626
639
|
}
|
|
640
|
+
// Actionable categories only — ok ledgers are healthy states, never attention.
|
|
641
|
+
// Order is fixed so the packet is byte-for-byte deterministic. Warnings surface
|
|
642
|
+
// even when health is ok (they never fail the machine), mirroring status attention.
|
|
643
|
+
const DOCTOR_ATTENTION_CATEGORIES = ["stale", "invalid", "warnings"];
|
|
644
|
+
function doctorAttention(summary) {
|
|
645
|
+
return DOCTOR_ATTENTION_CATEGORIES.filter((key) => summary[key] > 0);
|
|
646
|
+
}
|
|
647
|
+
function doctorNextAction(blockers, summary) {
|
|
648
|
+
if (blockers.length > 0) {
|
|
649
|
+
return `repair ${blockers.length} registry/ledger issue(s) above, then re-run \`artshelf doctor\``;
|
|
650
|
+
}
|
|
651
|
+
if (summary.warnings > 0) {
|
|
652
|
+
return `healthy, but ${summary.warnings} warning(s) noted — run \`artshelf validate --all\` to inspect; nothing is auto-executed`;
|
|
653
|
+
}
|
|
654
|
+
return "artshelf is healthy on this machine — cleanup safety enforced; no action needed";
|
|
655
|
+
}
|
|
656
|
+
function buildDoctorAgentPacket(report) {
|
|
657
|
+
const blockers = [];
|
|
658
|
+
if (report.registryError)
|
|
659
|
+
blockers.push(`registry unreadable: ${report.registryError}`);
|
|
660
|
+
for (const ledger of report.ledgers) {
|
|
661
|
+
if (ledger.status !== "ok") {
|
|
662
|
+
blockers.push(`${ledger.name} ${ledger.status}${ledger.errors.length ? `: ${ledger.errors[0]}` : ""}`);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
return {
|
|
666
|
+
schemaVersion: 1,
|
|
667
|
+
command: "doctor",
|
|
668
|
+
health: report.ok ? "ok" : "attention",
|
|
669
|
+
version: report.version,
|
|
670
|
+
node: report.node,
|
|
671
|
+
ledgerPath: report.ledgerPath,
|
|
672
|
+
registry: { path: report.registryPath, exists: report.registryExists, ok: report.registryOk, error: report.registryError },
|
|
673
|
+
ledgers: {
|
|
674
|
+
total: report.summary.ledgers,
|
|
675
|
+
ok: report.summary.ok,
|
|
676
|
+
stale: report.summary.stale,
|
|
677
|
+
invalid: report.summary.invalid,
|
|
678
|
+
warnings: report.summary.warnings
|
|
679
|
+
},
|
|
680
|
+
attention: doctorAttention(report.summary),
|
|
681
|
+
blockers,
|
|
682
|
+
cleanupSafety: report.cleanupSafety,
|
|
683
|
+
nextAction: doctorNextAction(blockers, report.summary),
|
|
684
|
+
verification: `artshelf doctor --agent --registry ${report.registryPath}`
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
// Human render (NGX-396): a scannable left-column glyph so attention state is
|
|
688
|
+
// obvious at a glance — ✓ clear, ⚠ needs attention. Plain Unicode (no ANSI
|
|
689
|
+
// color) keeps redirected/piped human output clean, and the `--agent`/`--json`
|
|
690
|
+
// renders never carry glyphs (those stay machine contracts).
|
|
691
|
+
const HUMAN_OK_GLYPH = "✓";
|
|
692
|
+
const HUMAN_ATTENTION_GLYPH = "⚠";
|
|
693
|
+
function attentionGlyph(needsAttention) {
|
|
694
|
+
return needsAttention ? HUMAN_ATTENTION_GLYPH : HUMAN_OK_GLYPH;
|
|
695
|
+
}
|
|
627
696
|
function printDoctor(report) {
|
|
628
697
|
process.stdout.write(`artshelf ${report.version} (node ${report.node})\n`);
|
|
629
|
-
process.stdout.write(
|
|
698
|
+
process.stdout.write(`${attentionGlyph(!report.ok)} health: ${report.ok ? "ok" : "needs attention"}\n`);
|
|
630
699
|
process.stdout.write(`ledger: ${report.ledgerPath}${report.ledgerExists ? "" : " (absent)"}\n`);
|
|
631
700
|
process.stdout.write(`registry: ${report.registryPath}${report.registryExists ? "" : " (absent)"}\n`);
|
|
632
701
|
if (report.registryError)
|
|
633
702
|
process.stdout.write(`registry error: ${report.registryError}\n`);
|
|
634
703
|
process.stdout.write(`registered ledgers: ${report.summary.ledgers} (${report.summary.ok} ok, ${report.summary.stale} stale, ${report.summary.invalid} invalid)\n`);
|
|
635
704
|
for (const ledger of report.ledgers) {
|
|
636
|
-
process.stdout.write(` ${ledger.status} ${ledger.name} ${ledger.path}\n`);
|
|
705
|
+
process.stdout.write(` ${attentionGlyph(ledger.status !== "ok")} ${ledger.status} ${ledger.name} ${ledger.path}\n`);
|
|
637
706
|
for (const message of ledger.errors)
|
|
638
707
|
process.stdout.write(` error: ${message}\n`);
|
|
639
708
|
}
|
|
@@ -644,8 +713,13 @@ function printDoctor(report) {
|
|
|
644
713
|
}
|
|
645
714
|
}
|
|
646
715
|
function handleStatus(parsed, ledgerPath, json) {
|
|
716
|
+
const agent = boolFlag(parsed, "agent");
|
|
647
717
|
if (boolFlag(parsed, "all")) {
|
|
648
718
|
const report = buildStatusReport(normalizeRegistryPath(stringFlag(parsed, "registry")));
|
|
719
|
+
if (agent) {
|
|
720
|
+
printCompactJson(buildStatusAgentPacketAll(report));
|
|
721
|
+
return report.ok ? 0 : 1;
|
|
722
|
+
}
|
|
649
723
|
if (json) {
|
|
650
724
|
printJson(report);
|
|
651
725
|
return report.ok ? 0 : 1;
|
|
@@ -654,6 +728,10 @@ function handleStatus(parsed, ledgerPath, json) {
|
|
|
654
728
|
return report.ok ? 0 : 1;
|
|
655
729
|
}
|
|
656
730
|
const ledger = statusLedger({ name: "current", path: ledgerPath, scope: "other", createdAt: "", updatedAt: "" }, false);
|
|
731
|
+
if (agent) {
|
|
732
|
+
printCompactJson(buildStatusAgentPacketSingle(ledger, ledgerPath));
|
|
733
|
+
return ledger.ok ? 0 : 1;
|
|
734
|
+
}
|
|
657
735
|
if (json) {
|
|
658
736
|
printJson({ ok: ledger.ok, ledger });
|
|
659
737
|
return ledger.ok ? 0 : 1;
|
|
@@ -737,23 +815,101 @@ function sumStatusCounts(ledgers, key) {
|
|
|
737
815
|
function formatStatusCounts(counts) {
|
|
738
816
|
return `active ${counts.active} · due ${counts.due} · manual-review ${counts.manualReview} · missing ${counts.missingPath} · kept ${counts.kept} · pending ${counts.pendingCleanup}`;
|
|
739
817
|
}
|
|
818
|
+
// Actionable categories only — active and kept are healthy states, never
|
|
819
|
+
// attention. Order is fixed so the packet is byte-for-byte deterministic.
|
|
820
|
+
const STATUS_ATTENTION_CATEGORIES = ["due", "manualReview", "missingPath", "pendingCleanup"];
|
|
821
|
+
function statusAttention(counts) {
|
|
822
|
+
return STATUS_ATTENTION_CATEGORIES.filter((key) => counts[key] > 0);
|
|
823
|
+
}
|
|
824
|
+
function statusCommand(scope, command, ledgerPath) {
|
|
825
|
+
if (scope === "all")
|
|
826
|
+
return `artshelf ${command} --all`;
|
|
827
|
+
return ledgerPath ? `artshelf ${command} --ledger ${ledgerPath}` : `artshelf ${command}`;
|
|
828
|
+
}
|
|
829
|
+
function statusNextAction(blockers, counts, scope, ledgerPath) {
|
|
830
|
+
if (blockers.length > 0) {
|
|
831
|
+
const verify = statusCommand(scope, "status", ledgerPath);
|
|
832
|
+
return `repair ${blockers.length} broken ledger(s) above, then re-run \`${verify}\``;
|
|
833
|
+
}
|
|
834
|
+
const review = statusCommand(scope, "review", ledgerPath);
|
|
835
|
+
if (counts.pendingCleanup > 0 || counts.due > 0) {
|
|
836
|
+
return `run \`${review}\` to preview cleanup plans; nothing is auto-executed`;
|
|
837
|
+
}
|
|
838
|
+
if (counts.manualReview > 0) {
|
|
839
|
+
return `run \`${review}\` to inspect manual-review records; nothing is auto-executed`;
|
|
840
|
+
}
|
|
841
|
+
if (counts.missingPath > 0) {
|
|
842
|
+
return "inspect missing-path records and `artshelf resolve` the ones no longer needed; nothing is auto-executable";
|
|
843
|
+
}
|
|
844
|
+
return "nothing due — no broken ledgers and no due, manual-review, missing-path, or pending cleanup entries";
|
|
845
|
+
}
|
|
846
|
+
function buildStatusAgentPacketAll(report) {
|
|
847
|
+
const blockers = [];
|
|
848
|
+
if (report.registryError)
|
|
849
|
+
blockers.push(`registry unreadable: ${report.registryError}`);
|
|
850
|
+
for (const ledger of report.ledgers) {
|
|
851
|
+
if (ledger.status !== "ok") {
|
|
852
|
+
blockers.push(`${ledger.name} ${ledger.status}${ledger.errors.length ? `: ${ledger.errors[0]}` : ""}`);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
const counts = {
|
|
856
|
+
active: report.totals.active,
|
|
857
|
+
due: report.totals.due,
|
|
858
|
+
manualReview: report.totals.manualReview,
|
|
859
|
+
missingPath: report.totals.missingPath,
|
|
860
|
+
kept: report.totals.kept,
|
|
861
|
+
pendingCleanup: report.totals.pendingCleanup
|
|
862
|
+
};
|
|
863
|
+
return {
|
|
864
|
+
schemaVersion: 1,
|
|
865
|
+
command: "status",
|
|
866
|
+
scope: "all",
|
|
867
|
+
health: report.ok ? "ok" : "attention",
|
|
868
|
+
registry: { path: report.registryPath, exists: report.registryExists, ok: report.registryOk, error: report.registryError },
|
|
869
|
+
ledgers: { total: report.totals.ledgers, ok: report.totals.ok, stale: report.totals.stale, invalid: report.totals.invalid },
|
|
870
|
+
counts,
|
|
871
|
+
attention: statusAttention(counts),
|
|
872
|
+
blockers,
|
|
873
|
+
nextAction: statusNextAction(blockers, counts, "all"),
|
|
874
|
+
verification: `artshelf status --all --agent --registry ${report.registryPath}`
|
|
875
|
+
};
|
|
876
|
+
}
|
|
877
|
+
function buildStatusAgentPacketSingle(ledger, ledgerPath) {
|
|
878
|
+
const blockers = ledger.ok
|
|
879
|
+
? []
|
|
880
|
+
: [`${ledger.status}${ledger.errors.length ? `: ${ledger.errors[0]}` : ""}`];
|
|
881
|
+
return {
|
|
882
|
+
schemaVersion: 1,
|
|
883
|
+
command: "status",
|
|
884
|
+
scope: "single",
|
|
885
|
+
health: ledger.ok ? "ok" : "attention",
|
|
886
|
+
ledgerPath,
|
|
887
|
+
counts: ledger.counts,
|
|
888
|
+
attention: statusAttention(ledger.counts),
|
|
889
|
+
blockers,
|
|
890
|
+
nextAction: statusNextAction(blockers, ledger.counts, "single", ledgerPath),
|
|
891
|
+
verification: `artshelf status --agent --ledger ${ledgerPath}`
|
|
892
|
+
};
|
|
893
|
+
}
|
|
740
894
|
function printStatusAll(report) {
|
|
741
|
-
|
|
895
|
+
const anyActionable = report.ledgers.some((ledger) => statusAttention(ledger.counts).length > 0);
|
|
896
|
+
process.stdout.write(`${attentionGlyph(!report.ok || anyActionable)} artshelf status: ${report.ok ? "ok" : "needs attention"}\n`);
|
|
742
897
|
process.stdout.write(`registry: ${report.registryPath}${report.registryExists ? "" : " (absent)"} — ${report.totals.ledgers} ledgers (${report.totals.ok} ok, ${report.totals.stale} stale, ${report.totals.invalid} invalid)\n`);
|
|
743
898
|
if (report.registryError)
|
|
744
899
|
process.stdout.write(`registry error: ${report.registryError}\n`);
|
|
745
900
|
for (const ledger of report.ledgers) {
|
|
746
901
|
if (ledger.status === "ok") {
|
|
747
|
-
process.stdout.write(
|
|
902
|
+
process.stdout.write(`${attentionGlyph(statusAttention(ledger.counts).length > 0)} [${ledger.name}] ${formatStatusCounts(ledger.counts)}\n`);
|
|
748
903
|
}
|
|
749
904
|
else {
|
|
750
|
-
process.stdout.write(
|
|
905
|
+
process.stdout.write(`${HUMAN_ATTENTION_GLYPH} [${ledger.name}] ${ledger.status}: ${ledger.errors.join("; ")}\n`);
|
|
751
906
|
}
|
|
752
907
|
}
|
|
753
908
|
process.stdout.write(`total: ${formatStatusCounts(report.totals)}\n`);
|
|
754
909
|
}
|
|
755
910
|
function printStatusSingle(ledger) {
|
|
756
|
-
|
|
911
|
+
const needsAttention = !ledger.ok || statusAttention(ledger.counts).length > 0;
|
|
912
|
+
process.stdout.write(`${attentionGlyph(needsAttention)} artshelf status: ${ledger.ok ? "ok" : ledger.status}\n`);
|
|
757
913
|
process.stdout.write(`ledger: ${ledger.path}\n`);
|
|
758
914
|
if (ledger.ok) {
|
|
759
915
|
process.stdout.write(`${formatStatusCounts(ledger.counts)}\n`);
|
|
@@ -1008,6 +1164,12 @@ function printJson(value) {
|
|
|
1008
1164
|
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
1009
1165
|
return 0;
|
|
1010
1166
|
}
|
|
1167
|
+
// Agent/compact surface: a single minified JSON line. The default `--json`
|
|
1168
|
+
// stays pretty-printed for audit/debug; agent packets optimize for tokens.
|
|
1169
|
+
function printCompactJson(value) {
|
|
1170
|
+
process.stdout.write(`${JSON.stringify(value)}\n`);
|
|
1171
|
+
return 0;
|
|
1172
|
+
}
|
|
1011
1173
|
function registeredLedgersOrThrow(registryPath) {
|
|
1012
1174
|
const ledgers = listRegisteredLedgers(registryPath);
|
|
1013
1175
|
if (ledgers.length === 0)
|
|
@@ -1157,13 +1319,16 @@ function summarizeReview(results) {
|
|
|
1157
1319
|
}
|
|
1158
1320
|
return summary;
|
|
1159
1321
|
}
|
|
1160
|
-
function reviewNextAction(summary) {
|
|
1322
|
+
function reviewNextAction(summary, scope, ledgerPath) {
|
|
1161
1323
|
const broken = summary.invalid + summary.stale;
|
|
1324
|
+
const review = statusCommand(scope, "review", ledgerPath);
|
|
1162
1325
|
if (broken > 0) {
|
|
1163
|
-
|
|
1326
|
+
const repair = scope === "all" ? "re-register or fix the file" : "fix the file";
|
|
1327
|
+
return `repair ${broken} broken ledger(s) above (${repair}), then re-run \`${review}\``;
|
|
1164
1328
|
}
|
|
1165
1329
|
if (summary.executable > 0) {
|
|
1166
|
-
|
|
1330
|
+
const dryRun = scope === "all" ? "artshelf cleanup --dry-run --all" : `artshelf cleanup --dry-run${ledgerPath ? ` --ledger ${ledgerPath}` : ""}`;
|
|
1331
|
+
return `run \`${dryRun}\` to generate plans, then \`artshelf cleanup --execute --plan-id <id> --ledger <path>\` for each reviewed plan`;
|
|
1167
1332
|
}
|
|
1168
1333
|
if (summary.missingPath > 0) {
|
|
1169
1334
|
return "inspect missing-path entries and `artshelf resolve` the ones no longer needed; nothing is auto-executable";
|
|
@@ -1172,7 +1337,7 @@ function reviewNextAction(summary) {
|
|
|
1172
1337
|
}
|
|
1173
1338
|
function printReviewAll(results, summary, nextAction, registryPath) {
|
|
1174
1339
|
const needsAttention = summary.invalid + summary.stale + summary.executable + summary.due + summary.manualReview + summary.missingPath > 0;
|
|
1175
|
-
process.stdout.write(
|
|
1340
|
+
process.stdout.write(`${attentionGlyph(needsAttention)} artshelf review --all: ${needsAttention ? "needs attention" : "all clear"}\n`);
|
|
1176
1341
|
process.stdout.write(`registry: ${registryPath} — ${summary.ledgers} ledgers (${summary.ok} ok, ${summary.invalid} invalid, ${summary.stale} stale)\n`);
|
|
1177
1342
|
printReview(results);
|
|
1178
1343
|
process.stdout.write(`triage: due ${summary.due} · manual-review ${summary.manualReview} · missing ${summary.missingPath} · executable ${summary.executable} · skipped ${summary.skipped}\n`);
|
|
@@ -1181,11 +1346,149 @@ function printReviewAll(results, summary, nextAction, registryPath) {
|
|
|
1181
1346
|
function printReview(results) {
|
|
1182
1347
|
for (const result of results) {
|
|
1183
1348
|
const visibleDue = result.due.filter((entry) => entry.dueStatus !== "kept");
|
|
1184
|
-
|
|
1349
|
+
const needsAttention = !result.validate.ok || visibleDue.length > 0 || result.plan.entries.length > 0;
|
|
1350
|
+
process.stdout.write(`${attentionGlyph(needsAttention)} [${result.ledger.name}] ${result.validate.ok ? "ok" : "invalid"}: ${result.validate.entries} entries, ${result.validate.errors.length} errors, ${result.validate.warnings.length} warnings\n`);
|
|
1185
1351
|
process.stdout.write(`due/manual/missing: ${visibleDue.length}; plan ${result.plan.planId}: ${result.plan.entries.length} entries, ${result.plan.skipped.length} skipped\n`);
|
|
1186
1352
|
process.stdout.write(`ledger: ${result.ledger.path}\n`);
|
|
1187
1353
|
}
|
|
1188
1354
|
}
|
|
1355
|
+
// review is read-only, so every safety guarantee holds unconditionally.
|
|
1356
|
+
const REVIEW_SAFETY = {
|
|
1357
|
+
dryRunOnly: true,
|
|
1358
|
+
executeAllRefused: true,
|
|
1359
|
+
noExecuteRan: true,
|
|
1360
|
+
noResolveRan: true,
|
|
1361
|
+
noDeleteRan: true
|
|
1362
|
+
};
|
|
1363
|
+
// Classify each registered ledger's records into decision groups. Order is
|
|
1364
|
+
// fixed (registry order, then a stable per-ledger sub-order) so the packet is
|
|
1365
|
+
// byte-for-byte deterministic.
|
|
1366
|
+
function buildReviewDecisions(results, scope) {
|
|
1367
|
+
const readyForApproval = [];
|
|
1368
|
+
const needsReviewFirst = [];
|
|
1369
|
+
const blocked = [];
|
|
1370
|
+
const review = scope === "all" ? "artshelf review --all" : "artshelf review";
|
|
1371
|
+
for (const result of results) {
|
|
1372
|
+
const { ledger, validate, due } = result;
|
|
1373
|
+
if (!validate.ok) {
|
|
1374
|
+
const status = existsSync(ledger.path) ? "invalid" : "missing";
|
|
1375
|
+
const repair = scope === "all" ? `re-register or fix ${ledger.path}` : `fix ${ledger.path}`;
|
|
1376
|
+
blocked.push({
|
|
1377
|
+
label: `Repair ${ledger.name} ledger (${status})`,
|
|
1378
|
+
itemIds: [],
|
|
1379
|
+
actionType: "fix-registry",
|
|
1380
|
+
approvalTarget: null,
|
|
1381
|
+
reason: validate.errors[0] ?? `${scope === "all" ? "registered ledger" : "ledger"} is ${status}`,
|
|
1382
|
+
nextStep: `${repair}, then re-run \`${review}\``
|
|
1383
|
+
});
|
|
1384
|
+
continue;
|
|
1385
|
+
}
|
|
1386
|
+
const missingPath = due.filter((entry) => entry.dueStatus === "missing-path");
|
|
1387
|
+
const trashSafe = due.filter((entry) => entry.dueStatus === "due" && entry.cleanup === "trash");
|
|
1388
|
+
const inspectItems = due.filter((entry) => entry.dueStatus === "manual-review" ||
|
|
1389
|
+
(entry.dueStatus === "due" && (entry.cleanup === "review" || entry.cleanup === "delete")));
|
|
1390
|
+
// Ready for approval: missing-path records resolve ledger-only with an exact,
|
|
1391
|
+
// plan-less approval target. Resolution updates the ledger and never touches
|
|
1392
|
+
// files, so it is the one action review can hand an agent directly.
|
|
1393
|
+
if (missingPath.length > 0) {
|
|
1394
|
+
const ids = missingPath.map((entry) => entry.id).sort();
|
|
1395
|
+
readyForApproval.push({
|
|
1396
|
+
label: `Resolve ${ids.length} missing-path record(s) in ${ledger.name}`,
|
|
1397
|
+
itemIds: ids,
|
|
1398
|
+
actionType: "resolve-missing",
|
|
1399
|
+
approvalTarget: `approve artshelf resolve missing ledger ${ledger.path} ids ${ids.join(" ")}`,
|
|
1400
|
+
reason: "the recorded path is already missing",
|
|
1401
|
+
nextStep: "confirm the artifact is no longer needed, then approve the ledger-only resolve"
|
|
1402
|
+
});
|
|
1403
|
+
}
|
|
1404
|
+
// Trash-safe records are cleanup-eligible, but review never mints a plan, so
|
|
1405
|
+
// they carry no approval target: the next step is the dry-run that produces
|
|
1406
|
+
// the reviewed plan id to approve.
|
|
1407
|
+
if (trashSafe.length > 0) {
|
|
1408
|
+
const ids = trashSafe.map((entry) => entry.id).sort();
|
|
1409
|
+
needsReviewFirst.push({
|
|
1410
|
+
label: `Plan cleanup for ${ids.length} trash-eligible artifact(s) in ${ledger.name}`,
|
|
1411
|
+
itemIds: ids,
|
|
1412
|
+
actionType: "cleanup",
|
|
1413
|
+
approvalTarget: null,
|
|
1414
|
+
reason: "disposable artifacts are due but no reviewed cleanup plan exists yet",
|
|
1415
|
+
nextStep: `run \`artshelf cleanup --dry-run --ledger ${ledger.path} --json\`, then approve \`approve artshelf cleanup ledger ${ledger.path} plan <plan-id>\``
|
|
1416
|
+
});
|
|
1417
|
+
}
|
|
1418
|
+
// manual-review and cleanup=review records need a human decision before any
|
|
1419
|
+
// cleanup; cleanup=delete is refused outright. None carry an approval target.
|
|
1420
|
+
if (inspectItems.length > 0) {
|
|
1421
|
+
const ids = inspectItems.map((entry) => entry.id).sort();
|
|
1422
|
+
const hasDelete = inspectItems.some((entry) => entry.cleanup === "delete");
|
|
1423
|
+
needsReviewFirst.push({
|
|
1424
|
+
label: `Inspect ${ids.length} record(s) in ${ledger.name} before cleanup`,
|
|
1425
|
+
itemIds: ids,
|
|
1426
|
+
actionType: "inspect",
|
|
1427
|
+
approvalTarget: null,
|
|
1428
|
+
reason: hasDelete
|
|
1429
|
+
? "records need manual review; cleanup=delete is refused and never deletes files"
|
|
1430
|
+
: "records are held for manual review before any cleanup",
|
|
1431
|
+
nextStep: "inspect each path, then keep, change retention, resolve, or set cleanup=trash and plan a cleanup"
|
|
1432
|
+
});
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
return { readyForApproval, needsReviewFirst, blocked };
|
|
1436
|
+
}
|
|
1437
|
+
function reviewCounts(summary) {
|
|
1438
|
+
return {
|
|
1439
|
+
due: summary.due,
|
|
1440
|
+
manualReview: summary.manualReview,
|
|
1441
|
+
missingPath: summary.missingPath,
|
|
1442
|
+
executable: summary.executable,
|
|
1443
|
+
skipped: summary.skipped
|
|
1444
|
+
};
|
|
1445
|
+
}
|
|
1446
|
+
function buildReviewAgentPacketAll(results, summary, registryPath) {
|
|
1447
|
+
const groups = buildReviewDecisions(results, "all");
|
|
1448
|
+
return {
|
|
1449
|
+
schemaVersion: 1,
|
|
1450
|
+
command: "review",
|
|
1451
|
+
scope: "all",
|
|
1452
|
+
health: summary.invalid + summary.stale > 0 ? "attention" : "ok",
|
|
1453
|
+
registry: { path: registryPath, exists: existsSync(registryPath) },
|
|
1454
|
+
ledgers: { total: summary.ledgers, ok: summary.ok, stale: summary.stale, invalid: summary.invalid },
|
|
1455
|
+
counts: reviewCounts(summary),
|
|
1456
|
+
decisionSummary: {
|
|
1457
|
+
readyForApproval: groups.readyForApproval.length,
|
|
1458
|
+
needsReviewFirst: groups.needsReviewFirst.length,
|
|
1459
|
+
blocked: groups.blocked.length
|
|
1460
|
+
},
|
|
1461
|
+
readyForApproval: groups.readyForApproval,
|
|
1462
|
+
needsReviewFirst: groups.needsReviewFirst,
|
|
1463
|
+
blocked: groups.blocked,
|
|
1464
|
+
safety: REVIEW_SAFETY,
|
|
1465
|
+
nextAction: reviewNextAction(summary, "all"),
|
|
1466
|
+
verification: `artshelf review --all --agent --registry ${registryPath}`
|
|
1467
|
+
};
|
|
1468
|
+
}
|
|
1469
|
+
function buildReviewAgentPacketSingle(result, ledgerPath) {
|
|
1470
|
+
const summary = summarizeReview([result]);
|
|
1471
|
+
const groups = buildReviewDecisions([result], "single");
|
|
1472
|
+
return {
|
|
1473
|
+
schemaVersion: 1,
|
|
1474
|
+
command: "review",
|
|
1475
|
+
scope: "single",
|
|
1476
|
+
health: summary.invalid + summary.stale > 0 ? "attention" : "ok",
|
|
1477
|
+
ledgerPath,
|
|
1478
|
+
counts: reviewCounts(summary),
|
|
1479
|
+
decisionSummary: {
|
|
1480
|
+
readyForApproval: groups.readyForApproval.length,
|
|
1481
|
+
needsReviewFirst: groups.needsReviewFirst.length,
|
|
1482
|
+
blocked: groups.blocked.length
|
|
1483
|
+
},
|
|
1484
|
+
readyForApproval: groups.readyForApproval,
|
|
1485
|
+
needsReviewFirst: groups.needsReviewFirst,
|
|
1486
|
+
blocked: groups.blocked,
|
|
1487
|
+
safety: REVIEW_SAFETY,
|
|
1488
|
+
nextAction: reviewNextAction(summary, "single", ledgerPath),
|
|
1489
|
+
verification: `artshelf review --agent --ledger ${ledgerPath}`
|
|
1490
|
+
};
|
|
1491
|
+
}
|
|
1189
1492
|
const COMMAND_GROUPS = [
|
|
1190
1493
|
{
|
|
1191
1494
|
group: "Create",
|
|
@@ -1387,17 +1690,28 @@ Resolved records stay in the audit trail but no longer participate in due or cle
|
|
|
1387
1690
|
}
|
|
1388
1691
|
if (command === "review") {
|
|
1389
1692
|
process.stdout.write(`Usage:
|
|
1390
|
-
artshelf review [--ledger <path>] [--json]
|
|
1391
|
-
artshelf review --all [--registry <path>] [--json]
|
|
1693
|
+
artshelf review [--ledger <path>] [--json|--agent]
|
|
1694
|
+
artshelf review --all [--registry <path>] [--json|--agent]
|
|
1695
|
+
|
|
1696
|
+
Review runs validate, due, and cleanup plan preview without moving files or
|
|
1697
|
+
writing a plan. With --all, review adds aggregate triage counts and the next
|
|
1698
|
+
safe action.
|
|
1392
1699
|
|
|
1393
|
-
|
|
1394
|
-
|
|
1700
|
+
Render modes:
|
|
1701
|
+
(default) Human summary of validation, triage counts, and the next safe action.
|
|
1702
|
+
--json Full read-only audit report (backward-compatible).
|
|
1703
|
+
--agent Compact single-line JSON decision packet for agents: health, triage
|
|
1704
|
+
counts, and classified decision groups (ready for approval, needs
|
|
1705
|
+
review first, blocked) with exact approval targets where they are
|
|
1706
|
+
safe. Review is read-only, so cleanup approval targets are minted by
|
|
1707
|
+
\`cleanup --dry-run\`, never leaked from a preview plan id.
|
|
1708
|
+
Token-efficient; --agent takes precedence over --json.
|
|
1395
1709
|
`);
|
|
1396
1710
|
return;
|
|
1397
1711
|
}
|
|
1398
1712
|
if (command === "doctor") {
|
|
1399
1713
|
process.stdout.write(`Usage:
|
|
1400
|
-
artshelf doctor [--registry <path>] [--ledger <path>] [--json]
|
|
1714
|
+
artshelf doctor [--registry <path>] [--ledger <path>] [--json|--agent]
|
|
1401
1715
|
|
|
1402
1716
|
Doctor reports whether Artshelf is healthy on this machine: CLI version, selected
|
|
1403
1717
|
or default ledger path, selected or global registry path, registered ledger health
|
|
@@ -1406,6 +1720,14 @@ selected or default ledger and still requires a reviewed plan id; --all execute
|
|
|
1406
1720
|
and cleanup=delete are refused, while physical trash purge requires a separate
|
|
1407
1721
|
reviewed purge plan.
|
|
1408
1722
|
|
|
1723
|
+
Render modes:
|
|
1724
|
+
(default) Human summary of machine health and cleanup safety.
|
|
1725
|
+
--json Full audit report (backward-compatible; suitable for cron/reporting).
|
|
1726
|
+
--agent Compact single-line JSON decision packet for agents: health, registry
|
|
1727
|
+
and registered-ledger health, blockers, cleanup-safety posture, next
|
|
1728
|
+
action, and a verify command. Token-efficient; --agent takes
|
|
1729
|
+
precedence over --json.
|
|
1730
|
+
|
|
1409
1731
|
Run it after install, when --all commands behave unexpectedly, or on a schedule to
|
|
1410
1732
|
catch stale registry entries. Doctor is read-only. A healthy machine exits 0; a
|
|
1411
1733
|
broken registry or registered ledger exits non-zero with actionable errors.
|
|
@@ -1414,8 +1736,8 @@ broken registry or registered ledger exits non-zero with actionable errors.
|
|
|
1414
1736
|
}
|
|
1415
1737
|
if (command === "status") {
|
|
1416
1738
|
process.stdout.write(`Usage:
|
|
1417
|
-
artshelf status [--ledger <path>] [--json]
|
|
1418
|
-
artshelf status --all [--registry <path>] [--json]
|
|
1739
|
+
artshelf status [--ledger <path>] [--json|--agent]
|
|
1740
|
+
artshelf status --all [--registry <path>] [--json|--agent]
|
|
1419
1741
|
|
|
1420
1742
|
Status is the lightweight daily "what is going on?" view. Without --all, it
|
|
1421
1743
|
reports counts for the selected or default ledger only. With --all, it adds
|
|
@@ -1423,10 +1745,16 @@ registry health, total ledgers, and aggregated counts across registered ledgers.
|
|
|
1423
1745
|
Counts include active artifacts, kept, due, manual-review, missing-path, and
|
|
1424
1746
|
pending cleanup entries.
|
|
1425
1747
|
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
--
|
|
1748
|
+
Render modes:
|
|
1749
|
+
(default) Human summary, short enough to paste into a chat.
|
|
1750
|
+
--json Full audit report (backward-compatible; suitable for cron/reporting).
|
|
1751
|
+
--agent Compact single-line JSON decision packet for agents: health, counts,
|
|
1752
|
+
attention categories, blockers, next action, and a verify command.
|
|
1753
|
+
Token-efficient; --agent takes precedence over --json.
|
|
1754
|
+
|
|
1755
|
+
Status is read-only: it never creates plans or receipts and never mutates
|
|
1756
|
+
records. A healthy selected ledger exits 0; with --all, a broken registry or any
|
|
1757
|
+
stale or invalid registered ledger exits non-zero.
|
|
1430
1758
|
`);
|
|
1431
1759
|
return;
|
|
1432
1760
|
}
|
package/docs/agent-monitor.html
CHANGED
|
@@ -73,7 +73,7 @@ artshelf ledgers add --ledger <repo>/.artshelf/ledger.jsonl --name <pro
|
|
|
73
73
|
artshelf ledgers list --json
|
|
74
74
|
|
|
75
75
|
<span class="c"># review and due-check every registered ledger at once</span>
|
|
76
|
-
artshelf review --all --
|
|
76
|
+
artshelf review --all --agent
|
|
77
77
|
artshelf due --all --json
|
|
78
78
|
|
|
79
79
|
<span class="c"># find records this agent owns, across ledgers</span>
|
|
@@ -102,12 +102,20 @@ artshelf due --all --json
|
|
|
102
102
|
|
|
103
103
|
<span class="c"># the full read-only pass: validate + due + plan preview</span>
|
|
104
104
|
artshelf review --all --json
|
|
105
|
+
artshelf review --all --agent
|
|
105
106
|
|
|
106
107
|
<span class="c"># CLI version, paths, registry health, safety posture</span>
|
|
107
108
|
artshelf doctor --json
|
|
109
|
+
artshelf doctor --agent
|
|
108
110
|
|
|
109
111
|
<span class="c"># lightweight counts, cron-friendly</span>
|
|
110
|
-
artshelf status --all --json
|
|
112
|
+
artshelf status --all --json
|
|
113
|
+
artshelf status --all --agent</code></pre>
|
|
114
|
+
<p>
|
|
115
|
+
Use <code>--agent</code> for concise monitor decisions and exact next
|
|
116
|
+
actions. Use <code>--json</code> instead when the job needs full
|
|
117
|
+
audit/API detail for storage, debugging, or a custom report.
|
|
118
|
+
</p>
|
|
111
119
|
</section>
|
|
112
120
|
|
|
113
121
|
<section>
|
package/docs/agent-review.html
CHANGED
|
@@ -44,16 +44,22 @@
|
|
|
44
44
|
<section>
|
|
45
45
|
<h2>Daily review workflow</h2>
|
|
46
46
|
<ol>
|
|
47
|
-
<li>Read <code>ledgers list</code>, <code>review --all</code>, and <code>trash list --all</code>.</li>
|
|
47
|
+
<li>Read <code>ledgers list --json</code>, <code>review --all --agent</code>, and <code>trash list --all --json</code>.</li>
|
|
48
48
|
<li>Run explicit-ledger purge dry-runs only when old trash needs review.</li>
|
|
49
49
|
<li>Classify each candidate: <code>trash-safe</code>, <code>needs-human-review</code>, <code>resolve-candidate</code>, or <code>registry-problem</code>.</li>
|
|
50
50
|
<li>Ask only with exact ledger path, reviewed plan id, or ids.</li>
|
|
51
51
|
</ol>
|
|
52
|
+
<p>
|
|
53
|
+
Prefer the built-in <code>--agent</code> packet when an acting agent
|
|
54
|
+
needs the compact decision surface. Use full <code>--json</code>
|
|
55
|
+
output when you need every ledger field for audit, debugging, or a
|
|
56
|
+
custom renderer.
|
|
57
|
+
</p>
|
|
52
58
|
</section>
|
|
53
59
|
|
|
54
60
|
<section>
|
|
55
61
|
<h2>Review plan report schema</h2>
|
|
56
|
-
<p>
|
|
62
|
+
<p>For richer host cards, attachments, or audit packets, construct an <code>ArtshelfReviewReport</code> JSON packet first, then render a compact decision card.</p>
|
|
57
63
|
<p>
|
|
58
64
|
Use <a href="schemas/artshelf-review-report.schema.json">schemas/artshelf-review-report.schema.json</a>
|
|
59
65
|
and <a href="examples/artshelf-review-report.json">examples/artshelf-review-report.json</a>.
|
package/docs/agent-usage.html
CHANGED
|
@@ -87,6 +87,20 @@
|
|
|
87
87
|
</dl>
|
|
88
88
|
</section>
|
|
89
89
|
|
|
90
|
+
<section>
|
|
91
|
+
<h2>Render modes</h2>
|
|
92
|
+
<p>
|
|
93
|
+
<code>review</code>, <code>status</code>, and <code>doctor</code> share three render modes
|
|
94
|
+
so the same data fits both people and agents. Reach for <code>--agent</code> when an agent
|
|
95
|
+
decides and acts; reach for <code>--json</code> for full record, plan, or health detail.
|
|
96
|
+
</p>
|
|
97
|
+
<dl class="def-rows">
|
|
98
|
+
<div><dt>default</dt><dd>human render: scannable grouped counts, attention states, and a short next action for a person at the terminal</dd></div>
|
|
99
|
+
<div><dt>--agent</dt><dd>a deterministic, token-efficient decision packet (single-line compact JSON) with health, counts, classifications, exact approval targets, blockers, and a verification command</dd></div>
|
|
100
|
+
<div><dt>--json</dt><dd>the full audit and API contract: complete machine-readable JSON for debugging and existing integrations, unchanged and backward compatible</dd></div>
|
|
101
|
+
</dl>
|
|
102
|
+
</section>
|
|
103
|
+
|
|
90
104
|
<section>
|
|
91
105
|
<h2>The mental model</h2>
|
|
92
106
|
<ul class="boundary-list">
|
package/docs/agent-usage.md
CHANGED
|
@@ -50,6 +50,23 @@ The browsable docs split the workflow into focused child pages:
|
|
|
50
50
|
- Approval names the exact ledger, plan id, or record ids.
|
|
51
51
|
- Every approved action ends with a read-only verification.
|
|
52
52
|
|
|
53
|
+
## Render modes
|
|
54
|
+
|
|
55
|
+
`review`, `status`, and `doctor` share three render modes so the same data fits
|
|
56
|
+
both people and agents:
|
|
57
|
+
|
|
58
|
+
- **default**: a human render — scannable grouped counts, attention states, and a
|
|
59
|
+
short next action for a person at the terminal.
|
|
60
|
+
- **`--agent`**: a deterministic, token-efficient decision packet (single-line
|
|
61
|
+
compact JSON) with health, counts, classifications, exact approval targets,
|
|
62
|
+
blockers, and a verification command. Use it when an agent acts on the result.
|
|
63
|
+
- **`--json`**: the full audit and API contract — complete machine-readable JSON
|
|
64
|
+
for debugging and existing integrations, unchanged and backward compatible.
|
|
65
|
+
|
|
66
|
+
Reach for `--agent` when an agent needs to decide and act cheaply; reach for
|
|
67
|
+
`--json` when you want the full record, plan, or health detail for audit or
|
|
68
|
+
debugging. `--agent` takes precedence if both flags are passed.
|
|
69
|
+
|
|
53
70
|
## Portable Skill
|
|
54
71
|
|
|
55
72
|
The repo ships a portable skill at
|
package/docs/reference.html
CHANGED
|
@@ -120,19 +120,20 @@ artshelf validate [--all] [--json]</code></pre>
|
|
|
120
120
|
<section class="cmd">
|
|
121
121
|
<div class="cmd-head"><h2>artshelf review / status / doctor</h2><span class="cmd-flag readonly">read-only</span></div>
|
|
122
122
|
<pre><code><span class="c"># validate + due + plan preview in one pass</span>
|
|
123
|
-
artshelf review [--all] [--json]
|
|
123
|
+
artshelf review [--all] [--agent] [--json]
|
|
124
124
|
|
|
125
125
|
<span class="c"># lightweight dashboard of counts</span>
|
|
126
|
-
artshelf status [--all] [--json]
|
|
126
|
+
artshelf status [--all] [--agent] [--json]
|
|
127
127
|
|
|
128
128
|
<span class="c"># CLI version, resolved paths, registry health</span>
|
|
129
|
-
artshelf doctor [--json]</code></pre>
|
|
129
|
+
artshelf doctor [--agent] [--json]</code></pre>
|
|
130
130
|
<p>
|
|
131
131
|
<code>review</code> runs validate, due, and a cleanup plan preview in one pass; no-op
|
|
132
132
|
previews report <code>not-created</code>, and <code>--all</code> adds an aggregate triage
|
|
133
133
|
summary plus the next safe action. <code>status</code> is the lightweight dashboard of
|
|
134
134
|
counts; <code>--all --json</code> is cron-friendly. <code>doctor</code> reports CLI version,
|
|
135
|
-
resolved paths, registry health, and the cleanup safety posture.
|
|
135
|
+
resolved paths, registry health, and the cleanup safety posture. All three also accept
|
|
136
|
+
<code>--agent</code> for a deterministic, token-efficient decision packet (see Output mode).
|
|
136
137
|
</p>
|
|
137
138
|
</section>
|
|
138
139
|
|
|
@@ -212,13 +213,29 @@ artshelf trash purge --execute --plan-id <id> [--ledger <path>] [--j
|
|
|
212
213
|
<section>
|
|
213
214
|
<h2>Output mode</h2>
|
|
214
215
|
<p>
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
216
|
+
Every command has a default human render: compact, scannable terminal output with
|
|
217
|
+
grouped counts, a leading <code>✓</code>/<code>⚠</code> attention glyph on each ledger
|
|
218
|
+
and the summary line, and a short next action — meant for a person reading the screen,
|
|
219
|
+
not a wall of raw JSON. The glyphs are plain Unicode (no ANSI color), so redirected
|
|
220
|
+
output stays clean.
|
|
221
|
+
</p>
|
|
222
|
+
<p>
|
|
223
|
+
<code>review</code>, <code>status</code>, and <code>doctor</code> add <code>--agent</code>:
|
|
224
|
+
a deterministic, token-efficient decision packet emitted as a single line of compact JSON.
|
|
225
|
+
It names health, counts, classifications, exact approval targets, blockers, and the command
|
|
226
|
+
to re-run for verification, so an agent can act without parsing decorative output.
|
|
227
|
+
</p>
|
|
228
|
+
<p>
|
|
229
|
+
<code>--json</code> stays the audit and API contract: the full, pretty-printed report for
|
|
230
|
+
debugging, audit trails, and existing integrations. It is unchanged and backward compatible,
|
|
231
|
+
and <code>--agent</code> takes precedence when both are passed. Update notices and other
|
|
232
|
+
diagnostics stay on stderr and never corrupt JSON or packet output.
|
|
218
233
|
</p>
|
|
219
234
|
<table class="opts">
|
|
220
235
|
<tr><th>option</th><th>meaning</th></tr>
|
|
221
|
-
<tr><td
|
|
236
|
+
<tr><td>(default)</td><td>human render: grouped counts, ✓/⚠ attention glyphs, and a short next action</td></tr>
|
|
237
|
+
<tr><td>--agent</td><td>token-efficient decision packet for agents on <code>review</code>, <code>status</code>, <code>doctor</code></td></tr>
|
|
238
|
+
<tr><td>--json</td><td>full machine-readable audit JSON on commands that return data</td></tr>
|
|
222
239
|
</table>
|
|
223
240
|
</section>
|
|
224
241
|
|
package/package.json
CHANGED
package/skills/artshelf/SKILL.md
CHANGED
|
@@ -59,8 +59,7 @@ npm link
|
|
|
59
59
|
artshelf doctor
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
Install, copy, or reference this portable skill only after the user chooses the
|
|
63
|
-
integration path. Offer to schedule read-only review job delivery in the host runtime.
|
|
62
|
+
Install, copy, or reference this portable skill only after the user chooses the integration path. Offer to schedule read-only review job delivery in the host runtime.
|
|
64
63
|
|
|
65
64
|
## Create
|
|
66
65
|
|
|
@@ -72,15 +71,11 @@ artshelf put <path> --reason "<why this exists>" --ttl 3d --kind run-artifact --
|
|
|
72
71
|
artshelf get <id> --json
|
|
73
72
|
```
|
|
74
73
|
|
|
75
|
-
Register backups, quarantine folders, debug output, generated reports, long-run
|
|
76
|
-
|
|
77
|
-
build output, dependency caches, secrets, credential dumps, and artifacts already
|
|
78
|
-
owned by another durable ledger.
|
|
74
|
+
Register backups, quarantine folders, debug output, generated reports, long-run evidence, and copied files kept for review. Skip source files, cheap regenerated
|
|
75
|
+
build output, dependency caches, secrets, credential dumps, and artifacts already owned by another durable ledger.
|
|
79
76
|
|
|
80
|
-
Defaults: `kind=scratch` for temp dirs, `backup` for rollback copies,
|
|
81
|
-
`
|
|
82
|
-
files. Use `cleanup=review` when judgment is needed and `cleanup=trash` only when
|
|
83
|
-
later disposal is clearly safe.
|
|
77
|
+
Defaults: `kind=scratch` for temp dirs, `backup` for rollback copies, `run-artifact` for logs/reports/evidence, `quarantine` for isolated questionable
|
|
78
|
+
files. Use `cleanup=review` when judgment is needed and `cleanup=trash` only when later disposal is clearly safe.
|
|
84
79
|
|
|
85
80
|
When JSON registration succeeds, include this deterministic Artshelf footnote:
|
|
86
81
|
|
|
@@ -94,13 +89,15 @@ Use the ledger registry for whole-machine review:
|
|
|
94
89
|
|
|
95
90
|
```bash
|
|
96
91
|
artshelf ledgers list --json
|
|
97
|
-
artshelf status --all --
|
|
98
|
-
artshelf review --all --
|
|
92
|
+
artshelf status --all --agent
|
|
93
|
+
artshelf review --all --agent
|
|
99
94
|
artshelf trash list --all --json
|
|
100
95
|
```
|
|
101
96
|
|
|
102
97
|
`artshelf ledgers list --json` reports per-ledger validation status. `--plain`
|
|
103
98
|
skips validation. `--all` is for discovery and review, not mutation permission.
|
|
99
|
+
Use `--agent` on `review`, `status`, and `doctor` for compact decisions; use
|
|
100
|
+
`--json` for full audit/API payloads, custom rendering, or debugging.
|
|
104
101
|
|
|
105
102
|
Register existing project ledgers explicitly:
|
|
106
103
|
|
|
@@ -144,22 +141,23 @@ Daily Review Workflow: turn raw Artshelf output into a decision packet, not a
|
|
|
144
141
|
count dump.
|
|
145
142
|
|
|
146
143
|
1. Run read-only review first: `artshelf ledgers list --json`,
|
|
147
|
-
`artshelf review --all --
|
|
144
|
+
`artshelf review --all --agent`, and `artshelf trash list --all --json`.
|
|
148
145
|
2. If cleanup attention exists, run `artshelf cleanup --dry-run --all --json`.
|
|
149
146
|
3. Classify candidates as `trash-safe`, `needs-human-review`,
|
|
150
147
|
`resolve-candidate`, or `registry-problem`.
|
|
151
|
-
4. Use `
|
|
152
|
-
|
|
153
|
-
`
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
148
|
+
4. Use the built-in `--agent` packet when the CLI output is enough to decide,
|
|
149
|
+
because it is deterministic and token-efficient. Use
|
|
150
|
+
`ArtshelfReviewReport` from `schemas/artshelf-review-report.schema.json` and
|
|
151
|
+
`examples/artshelf-review-report.json` when you need a host-specific card,
|
|
152
|
+
attachment, or richer audit record.
|
|
153
|
+
5. Render full packets with `scripts/render-review-report.mjs`; keep
|
|
154
|
+
`decisionSummary` in audit, while `decisionGroups` drive counts. Emojis are encouraged only in host-specific wrappers, not the renderer.
|
|
157
155
|
6. Always include the exact approval target in the message body as a fallback.
|
|
158
156
|
Do not paste the whole packet into chat unless the user asks for it.
|
|
159
157
|
|
|
160
158
|
### Review Plan Report Schema
|
|
161
159
|
|
|
162
|
-
Deterministic renderer:
|
|
160
|
+
Deterministic compact decision card renderer:
|
|
163
161
|
|
|
164
162
|
```bash
|
|
165
163
|
cd /path/to/skills/artshelf
|