@caddis/cli 0.4.68 → 0.4.70

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.
@@ -36,7 +36,6 @@ them into its commit, so check first, before Step 1.
36
36
  - Step 3, point 4: make the plan's Tracker edit in `<worktree>/.caddis/plans/<feature>.md`, and write
37
37
  any new parking-lot item under `<worktree>/.caddis/parking-lot/`, not in this checkout.
38
38
  - Step 4: skip `caddis_tidy.py --apply` (report `skipped: shared checkout`).
39
- - Step 6: retired; nothing to skip (row 8 reports `skipped: retired (see the 3-store model)`).
40
39
  - Step 6b: skip `session_state.py prune` (report `skipped: shared checkout`).
41
40
  - Step 6c: run `--reindex` in the worktree (it edits the tracked `DOC-MAP.md`).
42
41
  - Step 6d: runs as written. It never writes a file in this checkout; it only removes worktrees and
@@ -53,27 +52,22 @@ them into its commit, so check first, before Step 1.
53
52
 
54
53
  ## Checklist
55
54
  The handoff is a fixed checklist. Every row ends as `done`, `skipped: <reason>` or `failed: <error>`, and
56
- Step 8 prints all 14 in this order. Never drop a row from the report, even when its step did not apply.
57
- Rows 3 and 8 are retired (the 3-store model, 21 Oct 2026): they stay in the list so the row numbers do not
58
- move for a fleet that mixes caddis versions, and each always reports
59
- `skipped: retired (see the 3-store model)`. A later release removes them with their scripts.
55
+ Step 8 prints all 12 in this order. Never drop a row from the report, even when its step did not apply.
60
56
 
61
57
  | # | Row | What it is | Shared checkout (Step 0) |
62
58
  |---|---|---|---|
63
59
  | 1 | `knowledge-transfer` | Step 1 | edits only in the Step 0 worktree |
64
60
  | 2 | `plan-tracker` | the plan's Tracker row (Rules) | edit in the Step 0 worktree |
65
- | 3 | `open-work-row` | retired: always `skipped: retired (see the 3-store model)` | never runs |
66
- | 4 | `relay` | Step 3: the relay, written from scratch with current state only | the relay is local; runs |
67
- | 5 | `tasks-file` | Step 3c | runs |
68
- | 6 | `kb-index` | Step 6c: refresh the KB index | in the Step 0 worktree |
69
- | 7 | `violations-report` | Step 6c: report standing violations, each with a one-line fix command | runs (report only) |
70
- | 8 | `todo-reconcile` | retired: always `skipped: retired (see the 3-store model)` | never runs |
71
- | 9 | `usage-record` | Step 6b: `session_state.py usage` | runs |
72
- | 10 | `tidy-apply` | Step 4: `caddis_tidy.py --apply` | `skipped: shared checkout` |
73
- | 11 | `state-prune` | Step 6b: `session_state.py prune` | `skipped: shared checkout` |
74
- | 12 | `prune-list` | Step 6b: `caddis_tidy.py --prune --temp`, list only | runs (lists, never applies) |
75
- | 13 | `handover-check` | Step 5 | runs |
76
- | 14 | `own-cleanup` | Step 6d: `caddis_created.py cleanup --apply` removes this session's merged, clean worktrees and scratch folders; lists the rest with a reason | runs (only this session's recorded worktrees and scratch) |
61
+ | 3 | `relay` | Step 3: the relay, written from scratch with current state only | the relay is local; runs |
62
+ | 4 | `tasks-file` | Step 3c | runs |
63
+ | 5 | `kb-index` | Step 6c: refresh the KB index | in the Step 0 worktree |
64
+ | 6 | `violations-report` | Step 6c: report standing violations, each with a one-line fix command | runs (report only) |
65
+ | 7 | `usage-record` | Step 6b: `session_state.py usage` | runs |
66
+ | 8 | `tidy-apply` | Step 4: `caddis_tidy.py --apply` | `skipped: shared checkout` |
67
+ | 9 | `state-prune` | Step 6b: `session_state.py prune` | `skipped: shared checkout` |
68
+ | 10 | `prune-list` | Step 6b: `caddis_tidy.py --prune --temp`, list only | runs (lists, never applies) |
69
+ | 11 | `handover-check` | Step 5 | runs |
70
+ | 12 | `own-cleanup` | Step 6d: `caddis_created.py cleanup --apply` removes this session's merged, clean worktrees and scratch folders; lists the rest with a reason | runs (only this session's recorded worktrees and scratch) |
77
71
 
78
72
  `tidy-apply` and `state-prune` run only on `SHARED: no`. Handoff never runs
79
73
  `caddis_tidy.py --prune --apply` on its own, in any checkout (nor `--prune --temp --apply`); only the user can ask for it (Step 6b). In a
@@ -172,7 +166,6 @@ history, and the relay has a 4,000-character budget (`caddis_budget.py`).
172
166
  > checkout (Step 0) write it in the Step 0 worktree.
173
167
  > - **The order of work:** the plan Tracker and the roadmap (below). Set the Tracker row of each phase this
174
168
  > session finished (Rules).
175
- > Row 3 (`open-work-row`) is retired: report it exactly as `skipped: retired (see the 3-store model)`.
176
169
  > The `.caddis/open-work.md` and `.caddis/todo-list/` stores are retired. Never write them. A repo that
177
170
  > still holds an old file keeps it as its own document; caddis no longer reads or writes it.
178
171
  > **Order of work:** when the repo has a roadmap (`caddis_roadmap.py list` prints a slug), the
@@ -294,11 +287,6 @@ incoming session looking for a prompt that was never written. Fix what it lists,
294
287
  It also notes any generated artefact committed before its generator last changed. That is advisory,
295
288
  not blocking — but do not quote a report the note names without rebuilding it first.
296
289
 
297
- ## Step 6 — retired (task reconcile)
298
- This step is retired. It used to reconcile the `todo-list/` store, which is retired too (the 3-store model),
299
- so the step does nothing: do not run any script for it. Report row 8 (`todo-reconcile`) as
300
- `skipped: retired (see the 3-store model)`. The script stays in place for older installs only.
301
-
302
290
  ## Step 6b — record usage and tidy session state
303
291
  The Stop hook only writes the session-state file. These two used to run on every turn; they run
304
292
  here, once:
@@ -309,7 +297,7 @@ python "${CLAUDE_PLUGIN_ROOT}/scripts/session_state.py" prune
309
297
  `usage` finds this session's transcript by its id and appends one token-and-skill record to
310
298
  `.caddis/usage-log.jsonl`, which `/usage-review` reads. Pass `--transcript <path>` if you know the
311
299
  path and it is not under the Claude config folder. `prune` keeps the newest 8 files in
312
- `.caddis/session-state/`; run it after Step 6, which reads this session's file. Skip `prune` in a
300
+ `.caddis/session-state/`; run it after Step 3c, which reads this session's file. Skip `prune` in a
313
301
  shared checkout (Step 0). Include the
314
302
  `[USAGE]` line in your output. Both always exit 0; if the script is missing, skip this step.
315
303
 
@@ -328,12 +316,12 @@ yourself**; deleting is the user's choice. If they ask, run `--prune --temp --ap
328
316
  Both scripts fall back to `claude-harness/scripts/check_doc_coverage.py` and `scripts/caddis_tidy.py` in a
329
317
  source checkout; a script that is missing is `skipped: <script> not installed`.
330
318
 
331
- Checklist row 6, `kb-index` (in a shared checkout, run it in the Step 0 worktree, before the Step 0
319
+ Checklist row 5, `kb-index` (in a shared checkout, run it in the Step 0 worktree, before the Step 0
332
320
  `finish`; it edits `DOC-MAP.md`):
333
321
  ```
334
322
  python "${CLAUDE_PLUGIN_ROOT}/scripts/check_doc_coverage.py" --reindex
335
323
  ```
336
- Checklist row 7, `violations-report` (all three only report; never fix files here):
324
+ Checklist row 6, `violations-report` (all three only report; never fix files here):
337
325
  ```
338
326
  python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_tidy.py" --check
339
327
  python "${CLAUDE_PLUGIN_ROOT}/scripts/check_doc_coverage.py"
@@ -353,7 +341,7 @@ python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_roadmap.py" render --all
353
341
  ```
354
342
 
355
343
  ## Step 6d — remove this session's own worktrees and scratch folders
356
- Checklist row 14, `own-cleanup`. It runs in every checkout, a shared one too, after the Step 0 `finish`
344
+ Checklist row 12, `own-cleanup`. It runs in every checkout, a shared one too, after the Step 0 `finish`
357
345
  (falls back to `scripts/caddis_created.py` in a source checkout; if the script is missing, or exits 2 because
358
346
  it has no `cleanup`, the row is `skipped: not installed`):
359
347
  ```
@@ -392,18 +380,16 @@ Print this block, every row filled with `done`, `skipped: <reason>` or `failed:
392
380
  === HANDOFF CHECKLIST ===
393
381
  1 knowledge-transfer done | skipped: <reason> | failed: <error>
394
382
  2 plan-tracker <same three forms>
395
- 3 open-work-row skipped: retired (see the 3-store model)
396
- 4 relay <same three forms>
397
- 5 tasks-file <same three forms>
398
- 6 kb-index <same three forms>
399
- 7 violations-report <same three forms>
400
- 8 todo-reconcile skipped: retired (see the 3-store model)
401
- 9 usage-record <same three forms>
402
- 10 tidy-apply <same three forms>
403
- 11 state-prune <same three forms>
404
- 12 prune-list <same three forms>
405
- 13 handover-check <same three forms>
406
- 14 own-cleanup <same three forms>
383
+ 3 relay <same three forms>
384
+ 4 tasks-file <same three forms>
385
+ 5 kb-index <same three forms>
386
+ 6 violations-report <same three forms>
387
+ 7 usage-record <same three forms>
388
+ 8 tidy-apply <same three forms>
389
+ 9 state-prune <same three forms>
390
+ 10 prune-list <same three forms>
391
+ 11 handover-check <same three forms>
392
+ 12 own-cleanup <same three forms>
407
393
  Shared checkout: yes|no <reason>
408
394
  ```
409
395
 
@@ -351,11 +351,10 @@ def main() -> None:
351
351
  conversation = str(data.get("conversationId") or "").strip()
352
352
 
353
353
  blocks = []
354
- open_work_blocks = []
355
354
  for root in roots:
356
355
  if conversation and _already_injected(root, conversation):
357
356
  continue
358
- relay, matched_ws = resolve_relay(root, conversation)
357
+ relay, _ws = resolve_relay(root, conversation)
359
358
  text = ""
360
359
  if relay:
361
360
  try:
@@ -370,41 +369,7 @@ def main() -> None:
370
369
  blocks.append("relay for " + os.path.basename(root.rstrip("/\\")) + ":")
371
370
  blocks.append(truncate_relay(text))
372
371
 
373
- # Open-work rows as plain text without seeding instruction. Shown with or without a
374
- # relay: to-dos and plan phases exist before the first handoff writes one.
375
- shown_open_work = False
376
- try:
377
- from pathlib import Path as _Path
378
- # agy plugin: warm_start_agy.py sits at the plugin root, scripts in <plugin>/scripts.
379
- # Source tree: claude-harness/agy -> <repo>/scripts, where caddis_todo.py is authored.
380
- _here = os.path.dirname(os.path.abspath(__file__))
381
- for _sc in (os.path.join(os.path.dirname(os.path.dirname(_here)), "scripts"),
382
- os.path.join(_here, "scripts")):
383
- if os.path.isdir(_sc) and _sc not in sys.path:
384
- sys.path.insert(0, _sc)
385
- import caddis_todo
386
- open_items = caddis_todo.open_work(_Path(root), matched_ws)
387
- if open_items:
388
- # Same budget as the Claude Code hook: next 5 phases, 5 ad-hoc items.
389
- phases = [r for r in open_items if r.get("kind") == "phase"][:5]
390
- todos = [r for r in open_items if r.get("kind") != "phase"][:5]
391
- shown = phases + todos
392
- ow_lines = ["## Open work"]
393
- if len(open_items) > len(shown):
394
- ow_lines.append(f"(+{len(open_items) - len(shown)} more open items — run /catchup to see them.)")
395
- for row in shown:
396
- ow_lines.append(f"- {row['id']} [{row['kind']}] {' '.join(str(row['title']).split())[:100]}")
397
- if len(roots) > 1:
398
- open_work_blocks.append("open work for " + os.path.basename(root.rstrip("/\\")) + ":\n" + "\n".join(ow_lines))
399
- else:
400
- open_work_blocks.append("\n".join(ow_lines))
401
- shown_open_work = True
402
- except Exception as _exc:
403
- _hook_note("agy open work injection", _exc, root)
404
-
405
- # A relay that exists but failed to read must not be marked injected just because
406
- # open work was shown: the next invocation retries the relay.
407
- if conversation and (text or (not relay and shown_open_work)):
372
+ if conversation and text:
408
373
  _mark_injected(root, conversation)
409
374
 
410
375
  # agy has no SessionStart event, so this first invocation is also where the freshness
@@ -414,14 +379,12 @@ def main() -> None:
414
379
  for root in roots:
415
380
  fresh.extend(freshness_lines(root))
416
381
 
417
- if not blocks and not fresh and not open_work_blocks:
382
+ if not blocks and not fresh:
418
383
  return
419
384
  parts = []
420
385
  if blocks:
421
386
  parts.append(RELAY_FRAME_HEADER + "\n" + "\n\n".join(blocks)
422
387
  + "\n\n" + RELAY_FRAME_FOOTER)
423
- if open_work_blocks:
424
- parts.append("\n\n".join(open_work_blocks))
425
388
  if fresh:
426
389
  parts.append("\n".join(fresh))
427
390
  payload = json.dumps({"injectSteps": [{"ephemeralMessage": "\n\n".join(parts)}]})
@@ -3,7 +3,7 @@
3
3
  The `flow-studio` skill: a model file (JSON) describes a flow, lifecycle or journey, and one
4
4
  engine draws it as a self-contained HTML page with pan and zoom, lanes, linked nodes, a slide-in
5
5
  inspector, scenario playback, metric overlays, live update, motion that carries state, and numbered implementation notes. The design is in
6
- `.caddis/plans/flow-studio-skill-design.md`; the S4 stage status is in `.caddis/plans/flow-studio-s4-status.md`.
6
+ `.caddis/plans/done/flow-studio-skill-design.md`; the S4 stage status is in `.caddis/plans/flow-studio-s4-status.md`.
7
7
  `SKILL.md` is the current playbook.
8
8
 
9
9
  ## Use it
@@ -1,7 +1,7 @@
1
- import { test } from "node:test";
1
+ import { after, test } from "node:test";
2
2
  import assert from "node:assert/strict";
3
3
  import { spawnSync } from "node:child_process";
4
- import { existsSync, mkdtempSync, readFileSync, writeFileSync } from "node:fs";
4
+ import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
5
5
  import { tmpdir } from "node:os";
6
6
  import { join, resolve } from "node:path";
7
7
  import { fileURLToPath } from "node:url";
@@ -25,6 +25,7 @@ const good = {
25
25
  links: [{ id: "a-b", from: "a", to: "b", state: "ok" }],
26
26
  };
27
27
  const dir = mkdtempSync(join(tmpdir(), "flow-studio-"));
28
+ after(() => rmSync(dir, { recursive: true, force: true })); // a test run leaves nothing in the temp folder (tidy v2 Phase 5)
28
29
  const write = (name, value) => { const p = join(dir, name); writeFileSync(p, typeof value === "string" ? value : JSON.stringify(value)); return p; };
29
30
 
30
31
  test("validate: a good model exits 0 and prints OK", () => {
@@ -1,7 +1,7 @@
1
1
  {
2
- "poolVersion": "1.3.154",
2
+ "poolVersion": "1.3.156",
3
3
  "bundles": {
4
- "antigravity-plugin": "1.3.154",
4
+ "antigravity-plugin": "1.3.156",
5
5
  "antigravity-plugin-extras": "1.3.46",
6
6
  "codex": "unknown"
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@caddis/cli",
3
- "version": "0.4.68",
3
+ "version": "0.4.70",
4
4
  "description": "Install, update and diagnose the caddis dev harness across every coding agent you use (Claude Code, agy/Antigravity, and more).",
5
5
  "keywords": [
6
6
  "caddis",