artshelf 0.5.0 → 0.7.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/docs/site.js ADDED
@@ -0,0 +1,397 @@
1
+ /* Artshelf docs — chrome rendered from one manifest. */
2
+ (function () {
3
+ "use strict";
4
+
5
+ var NAV = [
6
+ {
7
+ title: "Start",
8
+ items: [
9
+ { n: "01", t: "Overview", h: "index.html" },
10
+ { n: "02", t: "Install", h: "install.html" },
11
+ { n: "03", t: "Quickstart", h: "quickstart.html" }
12
+ ]
13
+ },
14
+ {
15
+ title: "Agents",
16
+ items: [
17
+ {
18
+ n: "04", t: "Agent usage", h: "agent-usage.html",
19
+ children: [
20
+ { n: "4.1", t: "Create", h: "agent-create.html" },
21
+ { n: "4.2", t: "Monitor", h: "agent-monitor.html" },
22
+ { n: "4.3", t: "Review", h: "agent-review.html" },
23
+ { n: "4.4", t: "Clean", h: "agent-clean.html" }
24
+ ]
25
+ },
26
+ { t: "Agent skill", h: "https://github.com/calvinnwq/artshelf/tree/main/skills/artshelf", ext: true }
27
+ ]
28
+ },
29
+ {
30
+ title: "Reference",
31
+ items: [
32
+ { n: "05", t: "CLI reference", h: "reference.html" },
33
+ { t: "GitHub", h: "https://github.com/calvinnwq/artshelf", ext: true }
34
+ ]
35
+ }
36
+ ];
37
+
38
+ var ORDER = [];
39
+ NAV.forEach(function (g) {
40
+ g.items.forEach(function (i) {
41
+ if (!i.ext) {
42
+ ORDER.push(i);
43
+ (i.children || []).forEach(function (c) { ORDER.push(c); });
44
+ }
45
+ });
46
+ });
47
+
48
+ var page = document.body.dataset.page || "index.html";
49
+
50
+ /* ---------- theme ---------- */
51
+
52
+ var THEME_KEY = "artshelf-docs-theme";
53
+ var INDEX_KEY = "artshelf-docs-index-v1";
54
+
55
+ function getStorageItem(storageName, key) {
56
+ try {
57
+ return window[storageName].getItem(key);
58
+ } catch (_) {
59
+ return null;
60
+ }
61
+ }
62
+
63
+ function setStorageItem(storageName, key, value) {
64
+ try {
65
+ window[storageName].setItem(key, value);
66
+ } catch (_) {}
67
+ }
68
+
69
+ function getStoredTheme() {
70
+ return getStorageItem("localStorage", THEME_KEY);
71
+ }
72
+ function setStoredTheme(t) {
73
+ setStorageItem("localStorage", THEME_KEY, t);
74
+ }
75
+ function preferredTheme() {
76
+ return getStoredTheme() ||
77
+ (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");
78
+ }
79
+ function applyTheme(t) {
80
+ document.documentElement.dataset.theme = t;
81
+ document.querySelectorAll("[data-theme-toggle]").forEach(function (b) {
82
+ b.setAttribute("aria-pressed", t === "dark" ? "true" : "false");
83
+ });
84
+ }
85
+ document.addEventListener("click", function (e) {
86
+ if (!e.target.closest("[data-theme-toggle]")) return;
87
+ var next = document.documentElement.dataset.theme === "dark" ? "light" : "dark";
88
+ setStoredTheme(next);
89
+ applyTheme(next);
90
+ });
91
+
92
+ /* ---------- sidebar ---------- */
93
+
94
+ function navLink(item, child) {
95
+ var a = document.createElement("a");
96
+ a.href = item.h;
97
+ if (item.ext) { a.className = "ext"; a.rel = "noopener"; }
98
+ if (item.h === page) a.setAttribute("aria-current", "page");
99
+ if (item.n) {
100
+ var n = document.createElement("span");
101
+ n.className = "n";
102
+ n.textContent = item.n;
103
+ a.appendChild(n);
104
+ }
105
+ a.appendChild(document.createTextNode(item.t));
106
+ return a;
107
+ }
108
+
109
+ function renderSidebar() {
110
+ var nav = document.getElementById("sidebar");
111
+ if (!nav) return;
112
+ NAV.forEach(function (group) {
113
+ var box = document.createElement("div");
114
+ box.className = "nav-group";
115
+ var h = document.createElement("p");
116
+ h.className = "nav-group-title";
117
+ h.textContent = group.title;
118
+ box.appendChild(h);
119
+ group.items.forEach(function (item) {
120
+ box.appendChild(navLink(item));
121
+ if (item.children) {
122
+ var kids = document.createElement("div");
123
+ kids.className = "children";
124
+ kids.setAttribute("aria-label", item.t + " workflow pages");
125
+ item.children.forEach(function (c) { kids.appendChild(navLink(c, true)); });
126
+ box.appendChild(kids);
127
+ }
128
+ });
129
+ nav.appendChild(box);
130
+ });
131
+ }
132
+
133
+ /* ---------- pager ---------- */
134
+
135
+ function renderPager() {
136
+ var el = document.getElementById("pager");
137
+ if (!el) return;
138
+ var idx = ORDER.findIndex(function (i) { return i.h === page; });
139
+ if (idx < 0) return;
140
+ var prev = ORDER[idx - 1];
141
+ var next = ORDER[idx + 1];
142
+ el.innerHTML = "";
143
+ [["prev", prev, "← Previous"], ["next", next, "Next →"]].forEach(function (def) {
144
+ if (!def[1]) { el.appendChild(document.createElement("span")); return; }
145
+ var a = document.createElement("a");
146
+ a.className = def[0];
147
+ a.href = def[1].h;
148
+ a.innerHTML = '<span class="dir">' + def[2] + '</span><span class="t">' + def[1].t + "</span>";
149
+ el.appendChild(a);
150
+ });
151
+ }
152
+
153
+ /* ---------- headings: ids, anchors, toc ---------- */
154
+
155
+ function slug(text) {
156
+ return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
157
+ }
158
+
159
+ function renderToc() {
160
+ var toc = document.getElementById("toc");
161
+ var heads = document.querySelectorAll("article h2, article h3");
162
+ var links = [];
163
+ heads.forEach(function (h) {
164
+ if (!h.id) h.id = slug(h.textContent);
165
+ var a = document.createElement("a");
166
+ a.href = "#" + h.id;
167
+ a.textContent = "#";
168
+ a.className = "anchor";
169
+ a.setAttribute("aria-label", "Link to " + h.textContent);
170
+ h.appendChild(a);
171
+ if (toc) {
172
+ var t = document.createElement("a");
173
+ t.href = "#" + h.id;
174
+ t.textContent = h.childNodes[0].textContent.trim();
175
+ if (h.tagName === "H3") t.className = "sub";
176
+ toc.appendChild(t);
177
+ links.push({ head: h, link: t });
178
+ }
179
+ });
180
+ if (!links.length) return;
181
+ /* getBoundingClientRect, not offsetTop: the entrance animation transforms
182
+ sections, which makes them offsetParents and breaks offsetTop math. */
183
+ function spy() {
184
+ var current = links[0];
185
+ links.forEach(function (l) {
186
+ if (l.head.getBoundingClientRect().top <= 120) current = l;
187
+ });
188
+ if (window.innerHeight + window.scrollY >= document.documentElement.scrollHeight - 4) {
189
+ current = links[links.length - 1];
190
+ }
191
+ links.forEach(function (l) { l.link.classList.toggle("active", l === current); });
192
+ }
193
+ window.addEventListener("scroll", spy, { passive: true });
194
+ window.addEventListener("resize", spy, { passive: true });
195
+ spy();
196
+ }
197
+
198
+ /* ---------- copy buttons ---------- */
199
+
200
+ function renderCopy() {
201
+ document.querySelectorAll("article pre").forEach(function (pre) {
202
+ var wrap = document.createElement("div");
203
+ wrap.className = "snippet";
204
+ pre.parentNode.insertBefore(wrap, pre);
205
+ wrap.appendChild(pre);
206
+ var btn = document.createElement("button");
207
+ btn.className = "copy-btn";
208
+ btn.type = "button";
209
+ btn.textContent = "copy";
210
+ btn.addEventListener("click", function () {
211
+ navigator.clipboard.writeText(pre.textContent.trim()).then(function () {
212
+ btn.textContent = "copied";
213
+ btn.classList.add("done");
214
+ setTimeout(function () {
215
+ btn.textContent = "copy";
216
+ btn.classList.remove("done");
217
+ }, 1400);
218
+ });
219
+ });
220
+ wrap.appendChild(btn);
221
+ });
222
+ }
223
+
224
+ /* ---------- mobile drawer ---------- */
225
+
226
+ document.addEventListener("click", function (e) {
227
+ var btn = e.target.closest("[data-menu]");
228
+ if (btn) {
229
+ var open = document.body.classList.toggle("nav-open");
230
+ btn.setAttribute("aria-expanded", open ? "true" : "false");
231
+ return;
232
+ }
233
+ if (document.body.classList.contains("nav-open") && e.target.closest("#sidebar a")) {
234
+ document.body.classList.remove("nav-open");
235
+ }
236
+ });
237
+
238
+ /* ---------- search palette ---------- */
239
+
240
+ var INDEX = null;
241
+ var INDEX_PROMISE = null;
242
+
243
+ function isSearchEntry(entry) {
244
+ return entry &&
245
+ typeof entry.t === "string" &&
246
+ typeof entry.h === "string" &&
247
+ typeof entry.where === "string";
248
+ }
249
+
250
+ function isSearchIndex(value) {
251
+ return Array.isArray(value) && value.every(isSearchEntry);
252
+ }
253
+
254
+ function buildIndex() {
255
+ if (INDEX) return Promise.resolve(INDEX);
256
+ if (INDEX_PROMISE) return INDEX_PROMISE;
257
+ var cached = getStorageItem("sessionStorage", INDEX_KEY);
258
+ if (cached) {
259
+ try {
260
+ var parsed = JSON.parse(cached);
261
+ if (isSearchIndex(parsed)) {
262
+ INDEX = parsed;
263
+ return Promise.resolve(INDEX);
264
+ }
265
+ } catch (_) {}
266
+ }
267
+ var parser = new DOMParser();
268
+ INDEX_PROMISE = Promise.all(ORDER.map(function (p) {
269
+ return fetch(p.h).then(function (r) { return r.text(); }).then(function (html) {
270
+ var doc = parser.parseFromString(html, "text/html");
271
+ var entries = [{ t: p.t, h: p.h, where: p.t }];
272
+ doc.querySelectorAll("article h2, article h3").forEach(function (head) {
273
+ var text = head.textContent.trim();
274
+ entries.push({ t: text, h: p.h + "#" + slug(text), where: p.t });
275
+ });
276
+ return entries;
277
+ }).catch(function () { return [{ t: p.t, h: p.h, where: p.t }]; });
278
+ })).then(function (lists) {
279
+ INDEX = lists.flat();
280
+ setStorageItem("sessionStorage", INDEX_KEY, JSON.stringify(INDEX));
281
+ return INDEX;
282
+ }).finally(function () {
283
+ INDEX_PROMISE = null;
284
+ });
285
+ return INDEX_PROMISE;
286
+ }
287
+
288
+ var palette, paletteInput, paletteResults, backdrop, selIdx = 0;
289
+
290
+ function openPalette() {
291
+ if (!palette) buildPalette();
292
+ backdrop.hidden = false;
293
+ palette.hidden = false;
294
+ paletteInput.value = "";
295
+ renderResults("");
296
+ paletteInput.focus();
297
+ buildIndex();
298
+ }
299
+
300
+ function closePalette() {
301
+ if (!palette) return;
302
+ backdrop.hidden = true;
303
+ palette.hidden = true;
304
+ }
305
+
306
+ function buildPalette() {
307
+ backdrop = document.createElement("div");
308
+ backdrop.className = "palette-backdrop";
309
+ backdrop.hidden = true;
310
+ backdrop.addEventListener("click", closePalette);
311
+
312
+ palette = document.createElement("div");
313
+ palette.className = "palette";
314
+ palette.hidden = true;
315
+ palette.setAttribute("role", "dialog");
316
+ palette.setAttribute("aria-label", "Search documentation");
317
+
318
+ paletteInput = document.createElement("input");
319
+ paletteInput.type = "search";
320
+ paletteInput.placeholder = "Search pages, sections, commands…";
321
+ paletteInput.addEventListener("input", function () { renderResults(paletteInput.value); });
322
+ paletteInput.addEventListener("keydown", function (e) {
323
+ var items = paletteResults.querySelectorAll("a");
324
+ if (e.key === "ArrowDown") { e.preventDefault(); selIdx = Math.min(selIdx + 1, items.length - 1); paint(items); }
325
+ else if (e.key === "ArrowUp") { e.preventDefault(); selIdx = Math.max(selIdx - 1, 0); paint(items); }
326
+ else if (e.key === "Enter" && items[selIdx]) { items[selIdx].click(); }
327
+ });
328
+
329
+ paletteResults = document.createElement("div");
330
+ paletteResults.className = "palette-results";
331
+
332
+ palette.appendChild(paletteInput);
333
+ palette.appendChild(paletteResults);
334
+ document.body.appendChild(backdrop);
335
+ document.body.appendChild(palette);
336
+ }
337
+
338
+ function paint(items) {
339
+ items.forEach(function (a, i) { a.classList.toggle("sel", i === selIdx); });
340
+ if (items[selIdx]) items[selIdx].scrollIntoView({ block: "nearest" });
341
+ }
342
+
343
+ function renderResults(q) {
344
+ var capturedQuery = q;
345
+ selIdx = 0;
346
+ buildIndex().then(function (index) {
347
+ if (paletteInput && paletteInput.value !== capturedQuery) return;
348
+ var query = capturedQuery.trim().toLowerCase();
349
+ var hits = !query
350
+ ? index.filter(function (e) { return !e.h.includes("#"); })
351
+ : index.filter(function (e) { return e.t.toLowerCase().includes(query); }).slice(0, 12);
352
+ paletteResults.innerHTML = "";
353
+ if (!hits.length) {
354
+ var empty = document.createElement("p");
355
+ empty.className = "empty";
356
+ empty.textContent = "No matches — try a command name or stage.";
357
+ paletteResults.appendChild(empty);
358
+ return;
359
+ }
360
+ hits.forEach(function (hit, i) {
361
+ var a = document.createElement("a");
362
+ a.href = hit.h;
363
+ if (i === 0) a.className = "sel";
364
+ var label = document.createElement("span");
365
+ label.textContent = hit.t;
366
+ var where = document.createElement("span");
367
+ where.className = "where";
368
+ where.textContent = hit.where;
369
+ a.appendChild(label);
370
+ a.appendChild(where);
371
+ paletteResults.appendChild(a);
372
+ });
373
+ });
374
+ }
375
+
376
+ document.addEventListener("click", function (e) {
377
+ if (e.target.closest("[data-search-open]")) openPalette();
378
+ });
379
+
380
+ document.addEventListener("keydown", function (e) {
381
+ if (e.key === "/" && !e.target.closest("input, textarea") && (!palette || palette.hidden)) {
382
+ e.preventDefault();
383
+ openPalette();
384
+ } else if (e.key === "Escape") {
385
+ closePalette();
386
+ document.body.classList.remove("nav-open");
387
+ }
388
+ });
389
+
390
+ /* ---------- boot ---------- */
391
+
392
+ applyTheme(preferredTheme());
393
+ renderSidebar();
394
+ renderPager();
395
+ renderToc();
396
+ renderCopy();
397
+ })();
@@ -0,0 +1,116 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "scope": {
4
+ "registryPath": "~/.artshelf/ledgers.json",
5
+ "ledgerCount": 3,
6
+ "health": "attention",
7
+ "registryHealth": "ok",
8
+ "affectedLedgers": [
9
+ {
10
+ "name": "example-project",
11
+ "ledgerPath": "/path/to/example-project/.artshelf/ledger.jsonl",
12
+ "validationStatus": "ok"
13
+ }
14
+ ]
15
+ },
16
+ "plans": [
17
+ {
18
+ "type": "cleanup",
19
+ "ledgerPath": "/path/to/example-project/.artshelf/ledger.jsonl",
20
+ "planId": "plan_20260606_120000_ab12",
21
+ "planPath": "/path/to/example-project/.artshelf/plans/plan_20260606_120000_ab12.json",
22
+ "approvalTarget": "approve artshelf cleanup ledger /path/to/example-project/.artshelf/ledger.jsonl plan plan_20260606_120000_ab12"
23
+ }
24
+ ],
25
+ "summary": {
26
+ "executable": 1,
27
+ "skipped": 2,
28
+ "refused": 0,
29
+ "manualReview": 1,
30
+ "missingPath": 1,
31
+ "trashed": 0
32
+ },
33
+ "decisionSummary": {
34
+ "readyForApproval": 2,
35
+ "needsReviewFirst": 1,
36
+ "blocked": 0
37
+ },
38
+ "decisionGroups": {
39
+ "readyForApproval": [
40
+ {
41
+ "label": "Clean up temp debug output",
42
+ "itemIds": ["shf_20260606_120000_ab12"],
43
+ "actionType": "cleanup",
44
+ "approvalTarget": "approve artshelf cleanup ledger /path/to/example-project/.artshelf/ledger.jsonl plan plan_20260606_120000_ab12",
45
+ "reason": "Disposable temp artifact has a reviewed cleanup plan.",
46
+ "nextStep": "Approve the exact cleanup plan to move the artifact into Artshelf trash."
47
+ },
48
+ {
49
+ "label": "Resolve missing report record",
50
+ "itemIds": ["shf_20260606_120500_cd34"],
51
+ "actionType": "resolve-missing",
52
+ "approvalTarget": "approve artshelf resolve missing ledger /path/to/example-project/.artshelf/ledger.jsonl ids shf_20260606_120500_cd34",
53
+ "reason": "The report path is already missing.",
54
+ "nextStep": "Approve the ledger-only resolve command after confirming the report is no longer needed."
55
+ }
56
+ ],
57
+ "needsReviewFirst": [
58
+ {
59
+ "label": "Inspect lifecycle smoke report",
60
+ "itemIds": ["shf_20260606_121000_ef56"],
61
+ "actionType": "inspect",
62
+ "approvalTarget": null,
63
+ "reason": "cleanup=review means the artifact should be inspected before closing.",
64
+ "nextStep": "Inspect the path, then choose keep, change retention, resolve, or clean up later."
65
+ }
66
+ ],
67
+ "blocked": []
68
+ },
69
+ "recommendation": "Approve the reviewed cleanup plan for the disposable temp directory, then resolve the missing record after confirming it is no longer needed.",
70
+ "items": [
71
+ {
72
+ "id": "shf_20260606_120000_ab12",
73
+ "path": "/tmp/example-debug-output",
74
+ "classification": "trash-safe",
75
+ "proposedAction": "execute reviewed cleanup plan",
76
+ "dueStatus": "due",
77
+ "reason": "temporary debug output retained for 3 days",
78
+ "note": "The path exists, cleanup=trash, and the dry-run plan moves it into Artshelf trash."
79
+ },
80
+ {
81
+ "id": "shf_20260606_120500_cd34",
82
+ "path": "/tmp/missing-report.json",
83
+ "classification": "resolve-candidate",
84
+ "proposedAction": "resolve ledger-only after confirmation",
85
+ "dueStatus": "missing-path",
86
+ "reason": "report path is already missing",
87
+ "note": "Resolution updates only the ledger and does not move or delete files."
88
+ },
89
+ {
90
+ "id": "shf_20260606_121000_ef56",
91
+ "path": "/tmp/lifecycle-smoke-report.json",
92
+ "classification": "needs-human-review",
93
+ "proposedAction": "inspect before choosing cleanup or retention",
94
+ "dueStatus": "manual-review",
95
+ "reason": "cleanup=review artifact retained for manual inspection",
96
+ "note": "No approval target is shown until the review decision is known."
97
+ }
98
+ ],
99
+ "alternatives": [
100
+ "keep the artifact and change retention",
101
+ "inspect the path before approving cleanup",
102
+ "regenerate the plan after edits",
103
+ "resolve missing records ledger-only"
104
+ ],
105
+ "safety": {
106
+ "dryRunOnly": true,
107
+ "executeAllRefused": true,
108
+ "noExecuteRan": true,
109
+ "noResolveRan": true,
110
+ "noDeleteRan": true
111
+ },
112
+ "verification": {
113
+ "command": "artshelf review --all --json",
114
+ "successCondition": "no due, manual-review, missing-path, executable, or refused entries remain unless explicitly reported"
115
+ }
116
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "artshelf",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "Tiny CLI for accountable temporary artifact retention.",
5
5
  "type": "module",
6
6
  "author": "Calvin",
@@ -28,6 +28,8 @@
28
28
  "files": [
29
29
  "dist/src",
30
30
  "docs",
31
+ "schemas",
32
+ "examples",
31
33
  "skills",
32
34
  "CHANGELOG.md",
33
35
  "LICENSE",