@litfamily/litclaude 1.0.25 → 1.0.27
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 +17 -0
- package/README.md +8 -8
- package/README_ko-KR.md +8 -8
- package/bin/install-ownership.mjs +19 -1
- package/bin/litclaude-ai.js +12 -5
- package/docs/assets/readme/badge-version.svg +1 -1
- package/docs/hooks.md +78 -25
- package/package.json +1 -1
- package/plugins/litclaude/.claude-plugin/plugin.json +7 -1
- package/plugins/litclaude/bin/litclaude-hook.js +43 -0
- package/plugins/litclaude/bin/litclaude-mcp.js +1 -1
- package/plugins/litclaude/hooks/hooks.json +14 -1
- package/plugins/litclaude/hooks/lit-mod.mjs +87 -25
- package/plugins/litclaude/lib/mod/frame.mjs +204 -14
- package/plugins/litclaude/lib/mod/motion.mjs +2 -0
- package/plugins/litclaude/lib/mod/settings.mjs +6 -2
- package/plugins/litclaude/lib/mod/state.mjs +84 -0
- package/plugins/litclaude/lib/mod/svg-card.mjs +413 -0
- package/plugins/litclaude/lib/mod/timeline.mjs +20 -5
- package/plugins/litclaude/lib/mod/view.mjs +14 -2
- package/plugins/litclaude/lib/mod/workflow.mjs +239 -0
- package/plugins/litclaude/lib/start-work-lifecycle.mjs +160 -1
- package/plugins/litclaude/lib/workflow-stage.mjs +463 -0
- package/plugins/litclaude/skills/lit-crucible/SKILL.md +4 -0
- package/plugins/litclaude/skills/lit-loop/SKILL.md +8 -0
- package/plugins/litclaude/skills/review-work/SKILL.md +10 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.27 - 2026-10-13
|
|
4
|
+
|
|
5
|
+
- The lit-loop map now moves when the work happens in the shell. Writing a test with a shell command (`cat > test/…`, `>>`, `tee` or `sed -i`) turns the map to RED, changing a source file the same way turns it to GREEN, and the next test run turns it to VERIFY. A failing test run while the criterion is still pinned also counts as RED, including a bare `npm test` that exits with an error. The card keeps only the stage, never the command or the file names.
|
|
6
|
+
- `litclaude-ai install` no longer stops with `INSTALL_OWNERSHIP_CONFLICT` when the Claude desktop app has marked the installed plugin as in use. The app's `.in_use` folder, with its process-numbered entries, is left in place; anything else inside it is still reported.
|
|
7
|
+
- The start-work gate lets read-only git through during active work: `git status`, `git diff`, `git log` and `git show`, with any paths they name still checked against the work's grants. Its own lifecycle commands, `litclaude-ai start-work progress`, `complete` and `cancel`, pass too. `node -e` stays blocked, because its script cannot be read as read-only from the command alone.
|
|
8
|
+
- The README demo film is retaken: the card's workflow map turns RED on the failing test, then GREEN and VERIFY when the tests pass, and the live step names the running tool and its time.
|
|
9
|
+
|
|
10
|
+
## 1.0.26 - 2026-10-13
|
|
11
|
+
|
|
12
|
+
- The LIT card now shows where you are in the LIT workflow. A map row lights the current stage of the running family (interview, plan, work, review, loop, research), and a detail line under it says what that stage is doing: the interview round and ambiguity, whether the plan awaits approval, how many tasks are checked and which comes next, each review lane's verdict. On the right of that line the live step names the tool the main loop is running and for how long, or `thinking` between tool calls, and never shows its arguments.
|
|
13
|
+
- The map moves on its own. LitClaude's hooks advance it as lit-plan saves the plan, start-work's tasks are checked, review lanes report their verdicts and a lit-loop criterion goes from RED to GREEN to VERIFY, so the model does not have to report each step. For what the hooks cannot see, such as a loop step or a crucible verdict, the new `litclaude-ai workflow-stage` command records the stage.
|
|
14
|
+
- In the Claude desktop app the card is drawn as one picture. The app sets text in a proportional font, which pulled the terminal card apart there, so the desktop and editor surfaces now get the same rows as a single drawing, moving under the same `motion` setting. The terminal keeps the card it had.
|
|
15
|
+
- A new `notify` option raises a notification through your own notification channel when LIT work completes or a LIT turn longer than three minutes ends. It is `off` unless you turn it on with `/config` or `litclaude-ai config notify finish`.
|
|
16
|
+
- The start-work gate no longer blocks read-only searches. It used to read a grep or rg pattern, a quoted phrase passed to a node script, or `litclaude-ai start-work status` as an unverified path and deny it. Patterns and plain words now count as data, while the searched paths are still checked against the work's grants.
|
|
17
|
+
- `litclaude-ai doctor` reports the card options before the Claude validation step.
|
|
18
|
+
- The README card pictures are retaken to show the workflow map and the detail line.
|
|
19
|
+
|
|
3
20
|
## 1.0.25 - 2026-10-12
|
|
4
21
|
|
|
5
22
|
- The LIT card now moves while LitClaude is at work, so a glance tells you it is busy. The LIT pill and the border slowly glow from pink to flame orange and back, a light passes over the current phase and the skill chips of this request, and a spark runs along the top edge and back along the bottom one. When the turn ends the card goes still again. With the `motion` setting at `subtle` only the glow stays, and `off` keeps the card still.
|
package/README.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
<p align="center"><picture><source media="(prefers-reduced-motion: reduce)" srcset="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
1
|
+
<p align="center"><picture><source media="(prefers-reduced-motion: reduce)" srcset="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/docs/assets/cover-motion-still.webp" /><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/docs/assets/cover-motion.webp" width="100%" alt="LitFamily motion cover: five armored robots power on one by one, the LitClaude robot wakes with glowing eyes and a lit frame, then LITFAMILY and KEEP THE WORK LIT. light up." /></picture></p>
|
|
2
2
|
|
|
3
3
|
<h1 align="center">LitClaude</h1>
|
|
4
4
|
<p align="center"><strong>Keep the work lit.</strong></p>
|
|
5
5
|
<p align="center">A Claude Code plugin that helps every session plan the work, build it, check it, and leave a note the next session can pick up.</p>
|
|
6
6
|
<p align="center">
|
|
7
|
-
<img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
8
|
-
<a href="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
7
|
+
<img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/docs/assets/readme/badge-version.svg" alt="1.0.27" />
|
|
8
|
+
<a href="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/LICENSE"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/docs/assets/readme/badge-license.svg" alt="MIT license" /></a>
|
|
9
9
|
</p>
|
|
10
10
|
<p align="center">
|
|
11
|
-
<a href="https://github.com/wjgoarxiv/litclaude#readme">Full guide and skills gallery on GitHub</a> · <a href="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
11
|
+
<a href="https://github.com/wjgoarxiv/litclaude#readme">Full guide and skills gallery on GitHub</a> · <a href="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/README_ko-KR.md">한국어</a>
|
|
12
12
|
</p>
|
|
13
13
|
|
|
14
14
|
Add `lit` to a Claude Code prompt and Claude pins the goal, writes a failing test first,
|
|
@@ -73,7 +73,7 @@ the `/plugin` menu.
|
|
|
73
73
|
## More
|
|
74
74
|
|
|
75
75
|
- [Full guide and skills gallery on GitHub](https://github.com/wjgoarxiv/litclaude#readme)
|
|
76
|
-
- [Privacy and network behavior](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
77
|
-
- [Migration and ownership conflicts](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
78
|
-
- [Release history](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
79
|
-
- [MIT license](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
76
|
+
- [Privacy and network behavior](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/docs/privacy.md)
|
|
77
|
+
- [Migration and ownership conflicts](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/docs/migration.md)
|
|
78
|
+
- [Release history](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/CHANGELOG.md)
|
|
79
|
+
- [MIT license](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/LICENSE)
|
package/README_ko-KR.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
<p align="center"><picture><source media="(prefers-reduced-motion: reduce)" srcset="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
1
|
+
<p align="center"><picture><source media="(prefers-reduced-motion: reduce)" srcset="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/docs/assets/cover-motion-still.webp" /><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/docs/assets/cover-motion.webp" width="100%" alt="LitFamily 모션 커버: 다섯 로봇 패널이 차례로 켜지고, LitClaude 로봇의 눈과 테두리가 빛난 뒤 LITFAMILY와 KEEP THE WORK LIT. 문구가 밝아지는 영상" /></picture></p>
|
|
2
2
|
|
|
3
3
|
<h1 align="center">LitClaude</h1>
|
|
4
4
|
<p align="center"><strong>Keep the work lit.</strong></p>
|
|
5
5
|
<p align="center">Claude Code에서 세션마다 계획하고, 만들고, 확인한 뒤 다음 세션이 이어받을 기록을 남기게 돕는 플러그인입니다.</p>
|
|
6
6
|
<p align="center">
|
|
7
|
-
<img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
8
|
-
<a href="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
7
|
+
<img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/docs/assets/readme/badge-version.svg" alt="1.0.27" />
|
|
8
|
+
<a href="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/LICENSE"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/docs/assets/readme/badge-license.svg" alt="MIT license" /></a>
|
|
9
9
|
</p>
|
|
10
10
|
<p align="center">
|
|
11
|
-
<a href="https://github.com/wjgoarxiv/litclaude/blob/main/README_ko-KR.md">전체 안내와 스킬 갤러리는 GitHub에서</a> · <a href="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
11
|
+
<a href="https://github.com/wjgoarxiv/litclaude/blob/main/README_ko-KR.md">전체 안내와 스킬 갤러리는 GitHub에서</a> · <a href="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/README.md">English</a>
|
|
12
12
|
</p>
|
|
13
13
|
|
|
14
14
|
Claude Code 프롬프트에 `lit`을 붙이면 Claude가 목표를 고정하고, 실패하는 테스트를 먼저 쓰고,
|
|
@@ -71,7 +71,7 @@ LitClaude는 프로젝트 상태를 `.litclaude/`에 두고, 그 안의 `.gitign
|
|
|
71
71
|
## 더 보기
|
|
72
72
|
|
|
73
73
|
- [전체 안내와 스킬 갤러리 (GitHub)](https://github.com/wjgoarxiv/litclaude/blob/main/README_ko-KR.md)
|
|
74
|
-
- [개인정보와 네트워크 동작](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
75
|
-
- [이전과 소유권 충돌](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
76
|
-
- [변경 이력](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
77
|
-
- [MIT 라이선스](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
74
|
+
- [개인정보와 네트워크 동작](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/docs/privacy.md)
|
|
75
|
+
- [이전과 소유권 충돌](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/docs/migration.md)
|
|
76
|
+
- [변경 이력](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/CHANGELOG.md)
|
|
77
|
+
- [MIT 라이선스](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/LICENSE)
|
|
@@ -23,6 +23,11 @@ const legacyVendorPathMap = [
|
|
|
23
23
|
// Python writes bytecode next to the scripts it runs. That cache is generated, never user data, so ownership
|
|
24
24
|
// checks skip it. A symlink or a plain file named __pycache__ is not a cache and is still reported.
|
|
25
25
|
const isBytecodeCache = (name, value) => (value.isDirectory() && name === "__pycache__") || (value.isFile() && name.endsWith(".pyc"));
|
|
26
|
+
// Claude Code and the desktop app mark a cache version they have loaded with `.in_use/`, empty or
|
|
27
|
+
// holding one pid-named entry per process. That marker is the host's: ownership checks skip it and
|
|
28
|
+
// never remove it. Any other name inside it, or a symlink, is still reported.
|
|
29
|
+
const isHostUseMarker = (path, name, value) => name === hostUseMarker && value.isDirectory()
|
|
30
|
+
&& readdirSync(path, { withFileTypes: true }).every((entry) => /^\d+$/u.test(entry.name) && (entry.isDirectory() || entry.isFile()));
|
|
26
31
|
const conflict = (path, detail = "") => { throw new Error(`INSTALL_OWNERSHIP_CONFLICT: ${path}; use a compatible CLI or preserve this modified, foreign, or unsupported state before retrying${detail ? `. ${detail}` : ""}`); };
|
|
27
32
|
const stat = (path) => {
|
|
28
33
|
try { return lstatSync(path); } catch (error) { if (error.code === "ENOENT") return null; throw error; }
|
|
@@ -49,7 +54,7 @@ function treeHash(root) {
|
|
|
49
54
|
if (!prefix && name === receiptName) continue;
|
|
50
55
|
const next = join(path, name), rel = prefix ? `${prefix}/${name}` : name, value = lstatSync(next);
|
|
51
56
|
if (isBytecodeCache(name, value)) continue;
|
|
52
|
-
if (!prefix && name
|
|
57
|
+
if (!prefix && isHostUseMarker(next, name, value)) continue;
|
|
53
58
|
if (value.isDirectory()) { entries.push([rel, "directory"]); walk(next, rel); }
|
|
54
59
|
else if (value.isFile() && value.nlink === 1) entries.push([rel, "file", createHash("sha256").update(readFileSync(next)).digest("hex")]);
|
|
55
60
|
else conflict(next);
|
|
@@ -69,6 +74,7 @@ function detailedTree(root, { receipt = false } = {}) {
|
|
|
69
74
|
rows.push([prefix, "directory", value.mode & 0o777]);
|
|
70
75
|
for (const name of readdirSync(path).sort()) {
|
|
71
76
|
if (!prefix && !receipt && name === receiptName) continue;
|
|
77
|
+
if (!prefix && isHostUseMarker(join(path, name), name, lstatSync(join(path, name)))) continue;
|
|
72
78
|
walk(join(path, name), prefix ? `${prefix}/${name}` : name);
|
|
73
79
|
}
|
|
74
80
|
return;
|
|
@@ -270,6 +276,18 @@ export function assertCurrentPointer(home, current, target, version, { expectedV
|
|
|
270
276
|
return currentVersion;
|
|
271
277
|
}
|
|
272
278
|
|
|
279
|
+
// Empties an owned tree before a fresh copy, leaving the host's `.in_use` marker in place.
|
|
280
|
+
export function clearOwnedTree(path) {
|
|
281
|
+
const value = stat(path);
|
|
282
|
+
if (!value) return;
|
|
283
|
+
if (!value.isDirectory() || value.isSymbolicLink()) { rmSync(path, { recursive: true, force: true }); return; }
|
|
284
|
+
for (const name of readdirSync(path)) {
|
|
285
|
+
const next = join(path, name);
|
|
286
|
+
if (isHostUseMarker(next, name, lstatSync(next))) continue;
|
|
287
|
+
rmSync(next, { recursive: true, force: true });
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
273
291
|
export function removeEmptyDirectory(path) {
|
|
274
292
|
try { rmdirSync(path); } catch (error) { if (!["ENOENT", "ENOTEMPTY", "EEXIST"].includes(error.code)) throw error; }
|
|
275
293
|
}
|
package/bin/litclaude-ai.js
CHANGED
|
@@ -39,13 +39,14 @@ import { runStartWorkContinuationCli } from "../plugins/litclaude/lib/start-work
|
|
|
39
39
|
import { runStartWorkCli } from "../plugins/litclaude/lib/start-work-cli.mjs";
|
|
40
40
|
import { runLitgoalCli } from "../plugins/litclaude/lib/litgoal/cli.mjs";
|
|
41
41
|
import { runWorkflowCheckCli } from "../plugins/litclaude/lib/workflow-check.mjs";
|
|
42
|
+
import { runWorkflowStageCli } from "../plugins/litclaude/lib/workflow-stage.mjs";
|
|
42
43
|
import { runWikifyKnowledgeCli } from "../plugins/litclaude/lib/wikify-knowledge-cli.mjs";
|
|
43
44
|
import { automaticUpdateRoot, runAutomaticUpdate } from "../plugins/litclaude/lib/automatic-update.mjs";
|
|
44
45
|
import { jevStatusLine } from "../plugins/litclaude/lib/jev-skill-hint.mjs";
|
|
45
46
|
import { autoHandoffDoctorLines } from "../plugins/litclaude/lib/auto-handoff.mjs";
|
|
46
47
|
import { resolveProjectStateRoot } from "../plugins/litclaude/lib/project-state-root.mjs";
|
|
47
48
|
import { runUpdateNotifier } from "./update-notifier.mjs";
|
|
48
|
-
import { assertInstallPath, assertOwnedTree, assertCurrentPointer, assertOwnedRegistrations, migrateLegacyVendorPaths, planModifiedLegacySkill, preserveModifiedLegacySkill, registeredPluginInstallation, writeOwnershipReceipt, removeEmptyDirectory } from "./install-ownership.mjs";
|
|
49
|
+
import { assertInstallPath, assertOwnedTree, assertCurrentPointer, assertOwnedRegistrations, migrateLegacyVendorPaths, planModifiedLegacySkill, preserveModifiedLegacySkill, registeredPluginInstallation, writeOwnershipReceipt, removeEmptyDirectory, clearOwnedTree } from "./install-ownership.mjs";
|
|
49
50
|
import { banner, lockup, colorMode, supportsBlocks, terminalRows } from "./litfamily-banner.mjs";
|
|
50
51
|
import {
|
|
51
52
|
ICON_FONT,
|
|
@@ -81,14 +82,14 @@ const prewarmMotionRuntime = () => {
|
|
|
81
82
|
};
|
|
82
83
|
const version = packageJson.version;
|
|
83
84
|
|
|
84
|
-
const usage = `Usage: litclaude-ai [--dry-run] <install|doctor|config|path|run|update|uninstall|litgoal|wikify|workflow-check|start-work|start-work-next|public-read|motion-runtime> [...args]
|
|
85
|
+
const usage = `Usage: litclaude-ai [--dry-run] <install|doctor|config|path|run|update|uninstall|litgoal|wikify|workflow-check|workflow-stage|start-work|start-work-next|public-read|motion-runtime> [...args]
|
|
85
86
|
litclaude-ai --version
|
|
86
87
|
|
|
87
88
|
Commands:
|
|
88
89
|
install Register the packaged LitClaude plugin in Claude Code.
|
|
89
90
|
doctor Validate the installed LitClaude plugin path.
|
|
90
91
|
config [<option> <value>]
|
|
91
|
-
Show or change the LIT card options (motion, glyphs, band) in
|
|
92
|
+
Show or change the LIT card options (motion, glyphs, band, notify) in
|
|
92
93
|
pluginConfigs, the same values /config edits. Works for the
|
|
93
94
|
desktop app too, which shows no editor for them.
|
|
94
95
|
path Print the installed Claude plugin path.
|
|
@@ -98,6 +99,9 @@ Commands:
|
|
|
98
99
|
workflow-check Verify Dynamic workflow, /goal, and subagent delegation readiness.
|
|
99
100
|
start-work Manage schema-3 bounded-authority lifecycle state.
|
|
100
101
|
start-work-next Print the next active start-work continuation directive.
|
|
102
|
+
workflow-stage <family> <stage> [--n N --total M --unit U --verdict name=pass]
|
|
103
|
+
Record where a review, loop, iteration or crucible run stands, for
|
|
104
|
+
the LIT card's workflow map (.litclaude/workflow-stage.json).
|
|
101
105
|
public-read Read a public http(s) source with FetchAttempt/FetchVerdict JSON.
|
|
102
106
|
motion-runtime Pre-warm (install [--audio] [--word-timing]) or report (status) the
|
|
103
107
|
lit-typographic-motion runtime cache. Run it outside a sandboxed session.
|
|
@@ -383,7 +387,7 @@ const familyBanner = ({ color = shouldColorInstall() } = {}) => [
|
|
|
383
387
|
].join("\n");
|
|
384
388
|
|
|
385
389
|
const printCommandBanner = (parsed) => {
|
|
386
|
-
if (["install", "update"].includes(parsed.command)) return;
|
|
390
|
+
if (["install", "update", "workflow-stage"].includes(parsed.command)) return;
|
|
387
391
|
if (parsed.rest.some((arg) => arg === "--json" || arg.startsWith("--json="))) return;
|
|
388
392
|
const color = shouldColorInstall();
|
|
389
393
|
process.stdout.write(`${renderLitClaudeWordmark({ color }).join("\n")}\n`);
|
|
@@ -1389,7 +1393,7 @@ const install = async ({ dryRun, rest }) => {
|
|
|
1389
1393
|
target: targetPlugin,
|
|
1390
1394
|
},
|
|
1391
1395
|
async () => {
|
|
1392
|
-
|
|
1396
|
+
clearOwnedTree(targetPlugin);
|
|
1393
1397
|
await mkdir(dirname(targetPlugin), { recursive: true });
|
|
1394
1398
|
await cp(sourcePlugin, targetPlugin, { recursive: true });
|
|
1395
1399
|
writeOwnershipReceipt(targetPlugin, "plugin", version);
|
|
@@ -1837,6 +1841,9 @@ const main = async () => {
|
|
|
1837
1841
|
case "workflow-check":
|
|
1838
1842
|
exitAfterFlush(runWorkflowCheckCli(root, version, parsed.rest));
|
|
1839
1843
|
break;
|
|
1844
|
+
case "workflow-stage":
|
|
1845
|
+
exitAfterFlush(runWorkflowStageCli(parsed.rest, process.cwd()));
|
|
1846
|
+
break;
|
|
1840
1847
|
case "public-read":
|
|
1841
1848
|
exitAfterFlush(await runPublicRead(parsed));
|
|
1842
1849
|
break;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="146" height="20" role="img" aria-label="release: 1.0.
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="146" height="20" role="img" aria-label="release: 1.0.27"><title>release: 1.0.27</title><g shape-rendering="crispEdges"><rect width="49" height="20" fill="#080d14"/><rect x="49" width="97" height="20" fill="#ff6337"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text x="255" y="140" textLength="390" transform="scale(.1)">release</text><text x="965" y="140" textLength="870" transform="scale(.1)" fill="#080D14">1.0.27</text></g></svg>
|
package/docs/hooks.md
CHANGED
|
@@ -12,7 +12,7 @@ surface: Claude Code plugin hooks
|
|
|
12
12
|
runtime: plugins/litclaude/bin/litclaude-hook.js
|
|
13
13
|
registration: plugins/litclaude/hooks/hooks.json
|
|
14
14
|
settings_activation: global Claude settings.json enabledPlugins entry for litclaude@litclaude-ai
|
|
15
|
-
events: [SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, Stop, SubagentStart, SubagentStop, SessionEnd]
|
|
15
|
+
events: [SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, PostToolUseFailure, Stop, SubagentStart, SubagentStop, SessionEnd]
|
|
16
16
|
verdicts: [PASS, FAIL, BLOCKED]
|
|
17
17
|
```
|
|
18
18
|
|
|
@@ -105,10 +105,11 @@ silent no-op for callers that still invoke it directly.
|
|
|
105
105
|
| `SessionStart` | `plugins/litclaude/bin/litclaude-hook.js session-start` | Runs the bounded foreground automatic-update barrier on a fresh session (or starts the detached version-cache refresh when the cache is stale), discovers repo-local rule files, names the newest valid `plans/<slug>.md`, and on `source: compact` spends one of two durable re-injection reservations at reduced caps and, with automatic handoff on, reloads the fresh handoff once. |
|
|
106
106
|
| `UserPromptSubmit` | `plugins/litclaude/bin/litclaude-hook.js user-prompt-submit` | Detects prompt routes and injects workflow context; independently delivers static rules not already recorded for this session; with `LITCLAUDE_JEV=1` and `TYPESAFE_API_KEY` set, adds at most one Jev skill hint line to an unrouted turn; answers the exact prompts `lit-handoff auto on <percent>`, `lit-handoff auto off` and `lit-handoff auto status` by changing or reporting the automatic handoff setting. |
|
|
107
107
|
| `PreToolUse` | `plugins/litclaude/bin/litclaude-hook.js pre-tool-use` | Enforces semantic action/root grants before Write, Edit, MultiEdit, NotebookEdit, Bash, Agent, and bounded read tools execute; denies supported reader-facing text writes with a humanizer block-tier finding. |
|
|
108
|
-
| `PostToolUse` | `plugins/litclaude/bin/litclaude-hook.js post-tool-use` | Names the post-edit checks the edit actually earned, injects any glob-scoped rule matching the edited paths, and checks successfully created DOCX/PPTX/PDF files for humanizer findings, including paths reported by Bash output. |
|
|
108
|
+
| `PostToolUse` | `plugins/litclaude/bin/litclaude-hook.js post-tool-use` | Moves the LIT card's stage record on from what the tool did (plan saved, task checked, lit-loop step, a reviewer's verdict from an `Agent` result). Names the post-edit checks the edit actually earned, injects any glob-scoped rule matching the edited paths, and checks successfully created DOCX/PPTX/PDF files for humanizer findings, including paths reported by Bash output. |
|
|
109
|
+
| `PostToolUseFailure` | `plugins/litclaude/bin/litclaude-hook.js post-tool-use-failure` | For a Bash command that exits non-zero, such as a bare failing `npm test`, moves the LIT card's lit-loop map from what the command wrote and from its failing test run, which never counts as VERIFY. Nothing else runs on a failed tool. |
|
|
109
110
|
| `Stop` | `plugins/litclaude/bin/litclaude-hook.js stop` | Holds a lit-plan turn with no persisted plan and a lit workflow turn that edited interface files without a clean interface-probe run (each at most twice per turn), emits bounded start-work continuation on new progress, otherwise applies the opt-in litgoal autoloop gate, and last of all, with automatic handoff on, blocks once per crossing of the chosen percent to have the handoff written. |
|
|
110
111
|
| `SubagentStart` | `plugins/litclaude/bin/litclaude-hook.js subagent-start` | Registers child-lane and Claude-owned worktree identity. |
|
|
111
|
-
| `SubagentStop` | `plugins/litclaude/bin/litclaude-hook.js subagent-stop` | Finalizes the lane without child continuation. |
|
|
112
|
+
| `SubagentStop` | `plugins/litclaude/bin/litclaude-hook.js subagent-stop` | Finalizes the lane without child continuation, and gives a background review-work reviewer's verdict to the LIT card's stage record. |
|
|
112
113
|
| `SessionEnd` | `plugins/litclaude/bin/litclaude-hook.js session-end` | Records root-session end without blocking Claude. |
|
|
113
114
|
|
|
114
115
|
### Changed-text humanizer guard
|
|
@@ -347,38 +348,74 @@ itself. LitClaude's is `plugins/litclaude/hooks/lit-mod.mjs`, named under `modul
|
|
|
347
348
|
setup. The status line stays as it is; the band adds a live layer above the prompt.
|
|
348
349
|
|
|
349
350
|
From the first prompt to the end of the session a LIT card sits above the prompt. It keeps the
|
|
350
|
-
same
|
|
351
|
+
same five rows whether LitClaude is working or idle, and takes the status line's accent
|
|
351
352
|
(`LITCLAUDE_HUD_ACCENT`, read from the installed status line command), so the card and the
|
|
352
353
|
status line read as one family:
|
|
353
354
|
|
|
354
355
|
```
|
|
355
|
-
╭─ [🔥 LIT] ·
|
|
356
|
-
│
|
|
357
|
-
│
|
|
358
|
-
|
|
356
|
+
╭─ [🔥 LIT] · start-work ───────────────────────────────── WORK ● ─╮
|
|
357
|
+
│ interview ✓ ━━ plan ✓ ━━ [work 3/7] ━━ review · ── done · 1 lane │
|
|
358
|
+
│ └ task 3/7 ███░░░░░ · next ▸ 4. README demo - Bash · 0:12 │
|
|
359
|
+
│ skills [⚡ start-work] [↯ lit-plan] │
|
|
360
|
+
╰─ ctx 42% ▰▰▱▱▱ · 5h 31% · 1w 12% · git main ─────────────────────╯
|
|
359
361
|
```
|
|
360
362
|
|
|
361
363
|
The brackets stand for the ends of filled pills: rounded caps from the icon font with `nerd`
|
|
362
|
-
glyphs, one cell of the pill's colour with `basic`. The brand is a pink pill, the
|
|
364
|
+
glyphs, one cell of the pill's colour with `basic`. The brand is a pink pill, the current stage
|
|
363
365
|
and the skills of this request are pills on the accent with dark text, and skills from earlier
|
|
364
366
|
requests are muted grey pills.
|
|
365
367
|
|
|
366
368
|
- The top edge names the discipline the prompt hook ignited (the last one, dimmed, while the
|
|
367
|
-
session is idle; `ready` before any) and, on the right, the current
|
|
368
|
-
or `DONE ✓` during the finish. While a subagent is still running the card stays at
|
|
369
|
-
(`LIVE ●` when no
|
|
370
|
-
- The
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
369
|
+
session is idle; `ready` before any) and, on the right, the current stage: `WORK ●`, `RED ●`,
|
|
370
|
+
`idle`, or `DONE ✓` during the finish. While a subagent is still running the card stays at
|
|
371
|
+
work (`LIVE ●` when no stage is current) and never reads `DONE`, even after the main turn ended.
|
|
372
|
+
- The second row is the workflow map: where the session stands in its LIT family
|
|
373
|
+
(`lib/mod/workflow.mjs`). The main chain is `interview › plan › work n/m › review › done`
|
|
374
|
+
(litgoal criteria and autoresearch iterations ride the work stage); litresearch is
|
|
375
|
+
`decompose › wave n › expand › verify › synthesis`; a lit-loop criterion cycles
|
|
376
|
+
`PIN › RED › GREEN › VERIFY › REVIEW › RECORD` (SURFACE shows on VERIFY, CLEAN on RECORD).
|
|
377
|
+
Done stages carry `✓` in a colour graded along the rail from flame orange through pink to the
|
|
378
|
+
accent, the current stage is a pill, the stages ahead are dim `name ·`. The rail into the
|
|
379
|
+
current stage is solid `━`; the rail leaving it fills with the stage's count and, while
|
|
380
|
+
LitClaude works, carries a bright head; the rails ahead are dim `─`. On its right the row keeps
|
|
381
|
+
the live subagents (`● 2 lanes`), the autoloop count and its time left, and `ctx 76% → 80%` when
|
|
382
|
+
the context nears the auto-handoff percent. A session no family places (a lit-docx request, a
|
|
383
|
+
fresh session) keeps the old `PLAN ━━ WORK ━━ REVIEW` track there.
|
|
384
|
+
- The stage comes from the newest of the ignited discipline, a LitClaude skill this request
|
|
385
|
+
fired, and the stage record; with none of those, from the state that says work is under way.
|
|
386
|
+
The detail comes from files LitClaude already writes: the deep-interview state
|
|
387
|
+
(`round 3/12 · ambiguity 42% → 20%`), the lit-plan draft's approval gate (`drafting`,
|
|
388
|
+
`awaiting approval`), the start-work plan's tasks and next task, the litgoal criteria and the
|
|
389
|
+
litresearch session folder (`wave-*.md`, `verify-*.md`, `SYNTHESIS.md`). What no file
|
|
390
|
+
records goes into `.litclaude/workflow-stage.json`, a small record LitClaude's hooks keep
|
|
391
|
+
moving without the model's help. The prompt and PreToolUse hooks start it when lit-plan,
|
|
392
|
+
review-work, lit-loop, autoresearch or lit-crucible starts, and clear it for any other skill. PostToolUse checks the plan stage when lit-plan saves
|
|
393
|
+
`plans/<slug>.md` (`plan ✓`, detail `plan saved`), counts the tasks each time the active
|
|
394
|
+
start-work plan is edited (`work 1/2`), and steps a lit-loop criterion to RED when a test
|
|
395
|
+
file is written, GREEN when the code changes after it, VERIFY when the tests run and RECORD
|
|
396
|
+
when `litgoal record-evidence` runs. For review-work, PreToolUse marks a lane running when a
|
|
397
|
+
prompt titled `Review lane: <lane>.` is spawned, and the lane's `verdict:` line, read by
|
|
398
|
+
PostToolUse for a foreground reviewer and by SubagentStop for a background one, marks it
|
|
399
|
+
passed or failed. The card names the lanes `goal`, `quality`, `security`, `qa` and `context`
|
|
400
|
+
(review-work's scope/diff, package/payload, security/provenance, tests/evidence and
|
|
401
|
+
real-surface/docs lanes); five passes finish the review. The hooks keep only the stage, the
|
|
402
|
+
lane and the counts, never a path, command or prompt. The model can still refine the record
|
|
403
|
+
with `litclaude-ai workflow-stage <family> <stage> [--n --total --unit --verdict
|
|
404
|
+
name=pass|fail|pending|running]` for what the hooks cannot see: a lane run without a child
|
|
405
|
+
agent, a loop step such as SURFACE, an autoresearch iteration, the crucible verdict. Another
|
|
406
|
+
session's record is ignored and a source older than six hours no longer counts.
|
|
407
|
+
- The third row is the detail line: `└` and the current stage's detail (a pink-to-cyan bar for a
|
|
408
|
+
count, the lane verdicts as `✓`, `✗`, `●` while a reviewer runs, or `·`, the next task), and on the right the live step,
|
|
409
|
+
the tool the main loop is running and for how long (`- Bash · 0:12`, `thinking` between tool
|
|
410
|
+
calls). The step shows the tool's name and its clock only, never its arguments, command,
|
|
411
|
+
prompt or paths.
|
|
412
|
+
- The fourth row shows each LitFamily skill that fired as a pill: a Skill tool call naming a LitClaude
|
|
376
413
|
skill, a typed `/litclaude:<name>`, or bare `lit` routing seen through the ignition record.
|
|
377
414
|
A skill fired in the current request is bright, with a short light passing over its name as
|
|
378
415
|
it arrives; when the turn completes it dims into the `recent` list, and a new firing brightens
|
|
379
416
|
it again. Chips follow a dim `skills` label; those that do not fit collapse into a muted `+N`. Skills of other plugins never get a chip.
|
|
380
|
-
With no chip yet, the row shows the next task while work runs
|
|
381
|
-
while idle.
|
|
417
|
+
With no chip yet, the row shows the next task while work runs (when the detail line does not),
|
|
418
|
+
or how to start (`lit <task>`) while idle.
|
|
382
419
|
- The bottom edge carries the live figures from the status line: context fill, the five-hour
|
|
383
420
|
and weekly rate windows and the Git branch (read from `HEAD`, across a linked worktree).
|
|
384
421
|
- A notice takes the chips row for a few seconds, with a toast, when a gate fires: lit-plan not
|
|
@@ -399,7 +436,9 @@ stops counting too, so a crashed or lost agent cannot hold the card at work.
|
|
|
399
436
|
|
|
400
437
|
The card is the terminal's width up to 120 columns and every row is fitted to it, with Hangul and
|
|
401
438
|
emoji counted as two cells. Nothing wraps: on a narrow terminal the Git branch goes first, then
|
|
402
|
-
the weekly and five-hour windows, the lanes
|
|
439
|
+
the weekly and five-hour windows, the lanes and the autoloop count. The map drops its rails, then
|
|
440
|
+
shortens the names (`int ✓ pla ✓ [wor 3/7] rev ·`), then shows only the current stage and its
|
|
441
|
+
neighbours; the review verdicts shorten to three letters and then to their marks.
|
|
403
442
|
|
|
404
443
|
The spinner gains ` · <discipline> · n/m` after its ellipsis. `/lit-evidence` opens a pane with
|
|
405
444
|
three tabs (keys `1`, `2`, `3`): the goal's criteria with their last evidence, blockers and the
|
|
@@ -410,18 +449,31 @@ changes ease in and out (300 ms and 140 ms), notices slide in over 220 ms and le
|
|
|
410
449
|
a chip's arrival light runs 400 ms (a plain fade under `subtle`, nothing under `off`), and the
|
|
411
450
|
finish lasts at most 1.2 s. While LitClaude is at work the card keeps moving so you can tell it
|
|
412
451
|
is active at a glance: the LIT pill breathes from pink to flame orange every 2.4 s, a light sweeps
|
|
413
|
-
across the
|
|
414
|
-
|
|
452
|
+
across the current stage and this request's skill chips every 1.8 s, a bright head runs the rail
|
|
453
|
+
leaving the current stage every 1.4 s, the count bar's head shimmers, and a comet runs along the
|
|
454
|
+
top rule and back along the bottom one every 2.6 s. Under `subtle` only the breathing stays; under `off` nothing moves. An
|
|
415
455
|
idle card holds still. The band's `Client` element animates on Claude Code's frame clock, every
|
|
416
456
|
33 ms while a transition plays and every 66 ms during work, and stops its timer once the card is
|
|
417
457
|
idle and settled. In Claude
|
|
418
458
|
Code 2.1.292 a terminal row whose only change is a non-ASCII glyph is not repainted, so every
|
|
419
459
|
moving part changes ASCII text or colour: bar cells are coloured spaces, embers are ASCII sparks,
|
|
420
|
-
a chip's light moves over its ASCII name, and
|
|
460
|
+
a chip's light moves over its ASCII name, the map's `━` and `─` cells move by colour alone, the
|
|
461
|
+
step's spinner (`- \ | /`) and clock are ASCII, and a glyph swaps only together with its words.
|
|
462
|
+
|
|
463
|
+
The desktop app's Code tab, and the other surfaces that are not a terminal, draw a mod's `Text` in
|
|
464
|
+
a proportional font and cut each span to the cells it was laid out for, so the card above comes
|
|
465
|
+
apart there. On those surfaces the mod draws the same five rows as one `Svg` element instead
|
|
466
|
+
(`lib/mod/svg-card.mjs`): monospace text placed by counted cells, real pills and a rounded border.
|
|
467
|
+
It shows the settled state, with no entrances or crossfades. While LitClaude works it moves with
|
|
468
|
+
SMIL animation inside the drawing, which the surface runs in a script-less sandboxed frame: the
|
|
469
|
+
pill and the border breathe and the step's spinner turns, and on `full` a light crosses the
|
|
470
|
+
current stage and the current chips, a head runs the rail leaving it, the count bar's head
|
|
471
|
+
shimmers and a comet runs around the border. An idle card is a still image. The step's clock
|
|
472
|
+
moves with each new drawing, about every two seconds.
|
|
421
473
|
|
|
422
474
|
Options, in `/config` under LitClaude (stored in `pluginConfigs` in `~/.claude/settings.json`,
|
|
423
475
|
which the terminal and the desktop app's Code tab both read). The installer writes each default
|
|
424
|
-
you have not set, so the desktop app, which has no editor for them, starts with all
|
|
476
|
+
you have not set, so the desktop app, which has no editor for them, starts with all four;
|
|
425
477
|
`litclaude-ai config` prints them and `litclaude-ai config <option> <value>` changes one.
|
|
426
478
|
Uninstall removes only the defaults it wrote that are still unchanged.
|
|
427
479
|
|
|
@@ -430,6 +482,7 @@ Uninstall removes only the defaults it wrote that are still unchanged.
|
|
|
430
482
|
| `motion` | `full`, `subtle` (no overshoot, shimmer, embers, sweep or comet, shorter; the LIT pill still breathes during work), `off` (final frames only) | `full` |
|
|
431
483
|
| `glyphs` | `auto` (Nerd glyphs when the icon font is installed), `nerd`, or `basic` | `auto` |
|
|
432
484
|
| `band` | `always` (the whole session, idle included), `auto` (only while work is active or a skill of this request is lit), `off` | `always` |
|
|
485
|
+
| `notify` | `off`, `finish` (a notification through your own notification channel, `$.ui.notify`, when LIT work completes or a LIT turn longer than three minutes ends), `finish+sound` (the same; a sound is added once LitClaude ships one, and none ships yet) | `off` |
|
|
433
486
|
|
|
434
487
|
Unknown values fall back to the default. The fields are plain strings with no `options` list on
|
|
435
488
|
purpose: Claude Code 2.1.270 and older refuse to load a plugin whose `userConfig` has one, and
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@litfamily/litclaude",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.27",
|
|
4
4
|
"description": "Claude Code plugin: add lit to a prompt and Claude plans, tests, checks and reviews the work, then leaves a handoff for the next session.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "litclaude",
|
|
3
3
|
"description": "Claude Code-native workflow plugin with a bounded-authority start-work lifecycle.",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.27",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "LitClaude contributors"
|
|
7
7
|
},
|
|
@@ -32,6 +32,12 @@
|
|
|
32
32
|
"title": "LIT band",
|
|
33
33
|
"description": "When the LIT card shows above the prompt: always (the whole session, idle included), auto (only while LitClaude work is active or a skill of this request is lit) or off.",
|
|
34
34
|
"default": "always"
|
|
35
|
+
},
|
|
36
|
+
"notify": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"title": "LIT finish notification",
|
|
39
|
+
"description": "off, or finish: a notification through your own notification channel when LIT work completes or a LIT turn longer than three minutes ends. finish+sound also plays a sound once LitClaude ships one; until then it notifies like finish.",
|
|
40
|
+
"default": "off"
|
|
35
41
|
}
|
|
36
42
|
}
|
|
37
43
|
}
|
|
@@ -6,6 +6,8 @@ import { fileURLToPath } from "node:url";
|
|
|
6
6
|
import { standard, micro, colorMode, supportsBlocks } from "../lib/lit-mark.mjs";
|
|
7
7
|
import { NEON_END, NEON_START, rainbowText } from "../lib/hud-accent-palette.mjs";
|
|
8
8
|
import { ignitionMark, writeIgnitionState } from "../lib/hud-ignition.mjs";
|
|
9
|
+
import { DISCIPLINE_ENTRY } from "../lib/mod/workflow.mjs";
|
|
10
|
+
import { observeWorkflowPostTool, observeWorkflowPreTool, observeWorkflowSubagentStop, startWorkflowStage } from "../lib/workflow-stage.mjs";
|
|
9
11
|
import { renameAliases, renameNote } from "../lib/rename-aliases.mjs";
|
|
10
12
|
import { hasInterfaceModeWord, interfaceMode } from "../lib/interface-mode.mjs";
|
|
11
13
|
import { transcriptHasContextPressure } from "../lib/context-pressure.mjs";
|
|
@@ -122,6 +124,7 @@ const hookEventNames = {
|
|
|
122
124
|
"user-prompt-submit": "UserPromptSubmit",
|
|
123
125
|
"pre-tool-use": "PreToolUse",
|
|
124
126
|
"post-tool-use": "PostToolUse",
|
|
127
|
+
"post-tool-use-failure": "PostToolUseFailure",
|
|
125
128
|
"stop": "Stop",
|
|
126
129
|
"subagent-start": "SubagentStart",
|
|
127
130
|
"subagent-stop": "SubagentStop",
|
|
@@ -1322,6 +1325,13 @@ switch (eventName) {
|
|
|
1322
1325
|
else clearLitPlanTurn(stateRoot);
|
|
1323
1326
|
recordInterfaceProbeTurn(stateRoot, { sessionId: input.session_id, discipline: trigger?.safetyBlock ? null : trigger?.discipline });
|
|
1324
1327
|
recordMotionTurn(stateRoot, { sessionId: input.session_id, discipline: trigger?.discipline });
|
|
1328
|
+
// The LIT card's stage record follows the discipline this prompt ignited: it starts over for a
|
|
1329
|
+
// skill only it can follow and is cleared for any other.
|
|
1330
|
+
// A typed `/litclaude:<skill>` is expanded by the host and never routes here, so its skill
|
|
1331
|
+
// is read off the prompt's first word.
|
|
1332
|
+
const typed = /^\/(?:litclaude:)?([a-z][a-z-]{0,40})(?=\s|$)/u.exec(prompt.trim())?.[1];
|
|
1333
|
+
const started = trigger?.discipline && !trigger.safetyBlock ? trigger.discipline : typed && Object.hasOwn(DISCIPLINE_ENTRY, typed) ? typed : null;
|
|
1334
|
+
if (started) startWorkflowStage(cwd, { sessionId: input.session_id, skill: started });
|
|
1325
1335
|
} catch {
|
|
1326
1336
|
// Persistence-gate state is advisory to routing; an unwritable record never alters the prompt hook.
|
|
1327
1337
|
}
|
|
@@ -1407,6 +1417,13 @@ switch (eventName) {
|
|
|
1407
1417
|
},
|
|
1408
1418
|
}));
|
|
1409
1419
|
} else {
|
|
1420
|
+
// The LIT card's stage record: a workflow skill starts it, a review lane's reviewer marks
|
|
1421
|
+
// its lane running.
|
|
1422
|
+
try {
|
|
1423
|
+
observeWorkflowPreTool(cwd, guardInput);
|
|
1424
|
+
} catch {
|
|
1425
|
+
// The stage record only feeds the card; a failed write never changes the tool decision.
|
|
1426
|
+
}
|
|
1410
1427
|
let humanizerContext = "";
|
|
1411
1428
|
try {
|
|
1412
1429
|
const result = evaluateDeliverableHedgeGuard({ input: guardInput, pluginRoot });
|
|
@@ -1455,6 +1472,16 @@ switch (eventName) {
|
|
|
1455
1472
|
case "post-tool-use": {
|
|
1456
1473
|
const toolName = typeof input.tool_name === "string" ? input.tool_name : "unknown";
|
|
1457
1474
|
const filePaths = extractMutatedFilePaths(input);
|
|
1475
|
+
// The LIT card's stage record moves on from what this tool did: the plan saved, a task checked
|
|
1476
|
+
// in the active plan, a lit-loop step, a reviewer's verdict.
|
|
1477
|
+
try {
|
|
1478
|
+
const cwd = typeof input.cwd === "string" ? input.cwd : process.cwd();
|
|
1479
|
+
observeWorkflowPostTool(cwd, input, { filePaths, lifecycleRoot: lifecycleRootFor(cwd) });
|
|
1480
|
+
} catch {
|
|
1481
|
+
// The stage record only feeds the card; a failed write never changes the tool's result.
|
|
1482
|
+
}
|
|
1483
|
+
// A reviewer's report only moves the card; the post-edit checks below are for writes.
|
|
1484
|
+
if (toolName === "Agent") break;
|
|
1458
1485
|
try {
|
|
1459
1486
|
const cwd = typeof input.cwd === "string" ? input.cwd : process.cwd();
|
|
1460
1487
|
observeInterfaceProbeTool(resolveProjectStateRoot(cwd), { input, filePaths });
|
|
@@ -1522,6 +1549,17 @@ switch (eventName) {
|
|
|
1522
1549
|
// dispatch silent; compact re-injection is delivered by SessionStart source=compact.
|
|
1523
1550
|
break;
|
|
1524
1551
|
}
|
|
1552
|
+
case "post-tool-use-failure": {
|
|
1553
|
+
// A Bash command that exits non-zero (a bare failing `npm test`) never reaches PostToolUse. Its
|
|
1554
|
+
// writes and its failing run still move the LIT card's lit-loop map; nothing else runs here.
|
|
1555
|
+
try {
|
|
1556
|
+
const cwd = typeof input.cwd === "string" ? input.cwd : process.cwd();
|
|
1557
|
+
observeWorkflowPostTool(cwd, input, { lifecycleRoot: lifecycleRootFor(cwd), failed: true });
|
|
1558
|
+
} catch {
|
|
1559
|
+
// The stage record only feeds the card.
|
|
1560
|
+
}
|
|
1561
|
+
break;
|
|
1562
|
+
}
|
|
1525
1563
|
case "subagent-start": {
|
|
1526
1564
|
try {
|
|
1527
1565
|
const cwd = typeof input.cwd === "string" ? input.cwd : process.cwd();
|
|
@@ -1545,6 +1583,11 @@ switch (eventName) {
|
|
|
1545
1583
|
} catch {
|
|
1546
1584
|
// SubagentStop remains continuation-inert; completion will fail closed on an active lane.
|
|
1547
1585
|
}
|
|
1586
|
+
try {
|
|
1587
|
+
observeWorkflowSubagentStop(typeof input.cwd === "string" ? input.cwd : process.cwd(), input);
|
|
1588
|
+
} catch {
|
|
1589
|
+
// A background reviewer's verdict only feeds the card.
|
|
1590
|
+
}
|
|
1548
1591
|
break;
|
|
1549
1592
|
}
|
|
1550
1593
|
case "session-end": {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
],
|
|
41
41
|
"PostToolUse": [
|
|
42
42
|
{
|
|
43
|
-
"matcher": "^(Write|Edit|MultiEdit|NotebookEdit|Bash)$",
|
|
43
|
+
"matcher": "^(Write|Edit|MultiEdit|NotebookEdit|Bash|Agent)$",
|
|
44
44
|
"hooks": [
|
|
45
45
|
{
|
|
46
46
|
"type": "command",
|
|
@@ -51,6 +51,19 @@
|
|
|
51
51
|
]
|
|
52
52
|
}
|
|
53
53
|
],
|
|
54
|
+
"PostToolUseFailure": [
|
|
55
|
+
{
|
|
56
|
+
"matcher": "^Bash$",
|
|
57
|
+
"hooks": [
|
|
58
|
+
{
|
|
59
|
+
"type": "command",
|
|
60
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/bin/litclaude-hook.js\" post-tool-use-failure",
|
|
61
|
+
"timeout": 10,
|
|
62
|
+
"statusMessage": "moving the LIT card's workflow map"
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
],
|
|
54
67
|
"Stop": [
|
|
55
68
|
{
|
|
56
69
|
"hooks": [
|