@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.
- package/bundles/antigravity-plugin/plugin.json +1 -1
- package/bundles/antigravity-plugin/scripts/caddis_budget.py +0 -38
- package/bundles/antigravity-plugin/scripts/caddis_inventory.py +9 -7
- package/bundles/antigravity-plugin/scripts/caddis_review.py +6 -1
- package/bundles/antigravity-plugin/scripts/caddis_roadmap.py +9 -5
- package/bundles/antigravity-plugin/scripts/caddis_roadmap_run.py +5 -6
- package/bundles/antigravity-plugin/scripts/caddis_rows.py +10 -451
- package/bundles/antigravity-plugin/scripts/caddis_tidy.py +126 -8
- package/bundles/antigravity-plugin/scripts/caddis_todo.py +35 -352
- package/bundles/antigravity-plugin/skills/flow-studio/README.md +1 -1
- package/bundles/antigravity-plugin/skills/flow-studio/scripts/lib/cli.test.mjs +3 -2
- package/bundles/antigravity-plugin/skills/handoff/SKILL.md +25 -39
- package/bundles/antigravity-plugin/warm_start_agy.py +3 -40
- package/bundles/codex/.codex/skills/frontend/flow-studio/README.md +1 -1
- package/bundles/codex/.codex/skills/frontend/flow-studio/scripts/lib/cli.test.mjs +3 -2
- package/bundles/manifest.json +2 -2
- package/package.json +1 -1
|
@@ -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
|
|
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 | `
|
|
66
|
-
| 4 | `
|
|
67
|
-
| 5 | `
|
|
68
|
-
| 6 | `
|
|
69
|
-
| 7 | `
|
|
70
|
-
| 8 | `
|
|
71
|
-
| 9 | `
|
|
72
|
-
| 10 | `
|
|
73
|
-
| 11 | `
|
|
74
|
-
| 12 | `
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
396
|
-
4
|
|
397
|
-
5
|
|
398
|
-
6
|
|
399
|
-
7
|
|
400
|
-
8
|
|
401
|
-
9
|
|
402
|
-
10
|
|
403
|
-
11
|
|
404
|
-
12
|
|
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,
|
|
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
|
-
|
|
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
|
|
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", () => {
|
package/bundles/manifest.json
CHANGED
package/package.json
CHANGED