litclaude-ai 0.2.2
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 +155 -0
- package/LICENSE +21 -0
- package/README.md +369 -0
- package/README_ko-KR.md +374 -0
- package/RELEASE_CHECKLIST.md +165 -0
- package/bin/litclaude-ai.js +643 -0
- package/cover.png +0 -0
- package/docs/agents.md +67 -0
- package/docs/hooks.md +134 -0
- package/docs/lsp.md +40 -0
- package/docs/migration.md +209 -0
- package/docs/workflow-compatibility-audit.md +119 -0
- package/generate_cover.py +123 -0
- package/package.json +48 -0
- package/plugins/litclaude/.claude-plugin/plugin.json +25 -0
- package/plugins/litclaude/.lsp.json +13 -0
- package/plugins/litclaude/.mcp.json +9 -0
- package/plugins/litclaude/agents/boulder-executor.md +12 -0
- package/plugins/litclaude/agents/librarian-researcher.md +15 -0
- package/plugins/litclaude/agents/oracle-verifier.md +16 -0
- package/plugins/litclaude/agents/prometheus-planner.md +13 -0
- package/plugins/litclaude/agents/qa-runner.md +16 -0
- package/plugins/litclaude/agents/quality-reviewer.md +17 -0
- package/plugins/litclaude/bin/litclaude-hook.js +110 -0
- package/plugins/litclaude/bin/litclaude-hud.js +271 -0
- package/plugins/litclaude/bin/litclaude-lsp-doctor.js +15 -0
- package/plugins/litclaude/bin/litclaude-mcp.js +70 -0
- package/plugins/litclaude/commands/deep-interview.md +21 -0
- package/plugins/litclaude/commands/dynamic-workflow.md +36 -0
- package/plugins/litclaude/commands/lit-loop.md +40 -0
- package/plugins/litclaude/commands/lit-plan.md +35 -0
- package/plugins/litclaude/commands/litgoal.md +30 -0
- package/plugins/litclaude/commands/review-work.md +35 -0
- package/plugins/litclaude/commands/start-work.md +36 -0
- package/plugins/litclaude/hooks/hooks.json +54 -0
- package/plugins/litclaude/lib/context-pressure.mjs +25 -0
- package/plugins/litclaude/lib/hud-accent-palette.mjs +58 -0
- package/plugins/litclaude/lib/litgoal/cli.mjs +266 -0
- package/plugins/litclaude/lib/litgoal/ledger.mjs +16 -0
- package/plugins/litclaude/lib/litgoal/paths.mjs +7 -0
- package/plugins/litclaude/lib/litgoal/state.mjs +67 -0
- package/plugins/litclaude/lib/mutated-file-paths.mjs +63 -0
- package/plugins/litclaude/lib/start-work-continuation.mjs +99 -0
- package/plugins/litclaude/lib/workflow-check.mjs +83 -0
- package/plugins/litclaude/skills/ai-slop-remover/SKILL.md +142 -0
- package/plugins/litclaude/skills/comment-checker/SKILL.md +55 -0
- package/plugins/litclaude/skills/debugging/SKILL.md +70 -0
- package/plugins/litclaude/skills/debugging/references/methodology/00-setup.md +108 -0
- package/plugins/litclaude/skills/debugging/references/methodology/02-investigate.md +126 -0
- package/plugins/litclaude/skills/debugging/references/methodology/04-oracle-triple.md +106 -0
- package/plugins/litclaude/skills/debugging/references/methodology/05-escalate.md +69 -0
- package/plugins/litclaude/skills/debugging/references/methodology/06-fix.md +116 -0
- package/plugins/litclaude/skills/debugging/references/methodology/08-qa.md +94 -0
- package/plugins/litclaude/skills/debugging/references/methodology/09-cleanup.md +164 -0
- package/plugins/litclaude/skills/debugging/references/methodology/partial-runtime-evidence.md +228 -0
- package/plugins/litclaude/skills/debugging/references/runtimes/bundled-js-binary.md +415 -0
- package/plugins/litclaude/skills/debugging/references/runtimes/go.md +252 -0
- package/plugins/litclaude/skills/debugging/references/runtimes/native-binary.md +484 -0
- package/plugins/litclaude/skills/debugging/references/runtimes/node.md +260 -0
- package/plugins/litclaude/skills/debugging/references/runtimes/python.md +248 -0
- package/plugins/litclaude/skills/debugging/references/runtimes/rust.md +234 -0
- package/plugins/litclaude/skills/debugging/references/tools/ghidra.md +212 -0
- package/plugins/litclaude/skills/debugging/references/tools/playwright-cli.md +194 -0
- package/plugins/litclaude/skills/debugging/references/tools/pwndbg.md +263 -0
- package/plugins/litclaude/skills/debugging/references/tools/pwntools.md +265 -0
- package/plugins/litclaude/skills/deep-interview/SKILL.md +323 -0
- package/plugins/litclaude/skills/deep-interview/scripts/render_progress.py +193 -0
- package/plugins/litclaude/skills/frontend-ui-ux/SKILL.md +62 -0
- package/plugins/litclaude/skills/lit-loop/SKILL.md +144 -0
- package/plugins/litclaude/skills/lit-plan/SKILL.md +125 -0
- package/plugins/litclaude/skills/litgoal/SKILL.md +219 -0
- package/plugins/litclaude/skills/lsp/SKILL.md +63 -0
- package/plugins/litclaude/skills/programming/SKILL.md +106 -0
- package/plugins/litclaude/skills/programming/references/go/README.md +90 -0
- package/plugins/litclaude/skills/programming/references/go/backend-stack.md +641 -0
- package/plugins/litclaude/skills/programming/references/go/bootstrap.md +328 -0
- package/plugins/litclaude/skills/programming/references/go/bubbletea-v2.md +360 -0
- package/plugins/litclaude/skills/programming/references/go/cobra-stack.md +468 -0
- package/plugins/litclaude/skills/programming/references/go/concurrency.md +362 -0
- package/plugins/litclaude/skills/programming/references/go/data-modeling.md +329 -0
- package/plugins/litclaude/skills/programming/references/go/error-handling.md +359 -0
- package/plugins/litclaude/skills/programming/references/go/golangci-strict.md +236 -0
- package/plugins/litclaude/skills/programming/references/go/grpc-connect.md +375 -0
- package/plugins/litclaude/skills/programming/references/go/libraries.md +337 -0
- package/plugins/litclaude/skills/programming/references/go/one-liners.md +202 -0
- package/plugins/litclaude/skills/programming/references/go/sqlc-pgx.md +471 -0
- package/plugins/litclaude/skills/programming/references/go/testing.md +467 -0
- package/plugins/litclaude/skills/programming/references/go/type-patterns.md +298 -0
- package/plugins/litclaude/skills/programming/references/python/README.md +314 -0
- package/plugins/litclaude/skills/programming/references/python/async-anyio.md +442 -0
- package/plugins/litclaude/skills/programming/references/python/data-modeling.md +233 -0
- package/plugins/litclaude/skills/programming/references/python/data-processing.md +133 -0
- package/plugins/litclaude/skills/programming/references/python/error-handling.md +218 -0
- package/plugins/litclaude/skills/programming/references/python/fastapi-stack.md +316 -0
- package/plugins/litclaude/skills/programming/references/python/httpx2-optimization.md +360 -0
- package/plugins/litclaude/skills/programming/references/python/libraries.md +307 -0
- package/plugins/litclaude/skills/programming/references/python/one-liners.md +268 -0
- package/plugins/litclaude/skills/programming/references/python/orjson-stack.md +378 -0
- package/plugins/litclaude/skills/programming/references/python/pydantic-ai.md +285 -0
- package/plugins/litclaude/skills/programming/references/python/pyproject-strict.md +232 -0
- package/plugins/litclaude/skills/programming/references/python/textual-tui.md +201 -0
- package/plugins/litclaude/skills/programming/references/python/type-patterns.md +176 -0
- package/plugins/litclaude/skills/programming/references/rust/README.md +317 -0
- package/plugins/litclaude/skills/programming/references/rust/async-tokio.md +299 -0
- package/plugins/litclaude/skills/programming/references/rust/axum-stack.md +467 -0
- package/plugins/litclaude/skills/programming/references/rust/cargo-strict.md +317 -0
- package/plugins/litclaude/skills/programming/references/rust/clap-stack.md +409 -0
- package/plugins/litclaude/skills/programming/references/rust/concurrency.md +375 -0
- package/plugins/litclaude/skills/programming/references/rust/libraries.md +439 -0
- package/plugins/litclaude/skills/programming/references/rust/one-liners.md +291 -0
- package/plugins/litclaude/skills/programming/references/rust/proptest-insta.md +429 -0
- package/plugins/litclaude/skills/programming/references/rust/type-state.md +354 -0
- package/plugins/litclaude/skills/programming/references/rust/unsafe-discipline.md +250 -0
- package/plugins/litclaude/skills/programming/references/rust/zero-cost-safety.md +527 -0
- package/plugins/litclaude/skills/programming/references/rust-ub/README.md +289 -0
- package/plugins/litclaude/skills/programming/references/rust-ub/miri-sanitizers-loom.md +411 -0
- package/plugins/litclaude/skills/programming/references/rust-ub/ub-taxonomy.md +269 -0
- package/plugins/litclaude/skills/programming/references/typescript/README.md +195 -0
- package/plugins/litclaude/skills/programming/references/typescript/backend-hono.md +672 -0
- package/plugins/litclaude/skills/programming/references/typescript/bootstrap.md +199 -0
- package/plugins/litclaude/skills/programming/references/typescript/data-modeling.md +202 -0
- package/plugins/litclaude/skills/programming/references/typescript/error-handling.md +169 -0
- package/plugins/litclaude/skills/programming/references/typescript/tsconfig-strict.md +152 -0
- package/plugins/litclaude/skills/programming/references/typescript/type-patterns.md +196 -0
- package/plugins/litclaude/skills/programming/scripts/go/check-no-excuse-rules.sh +173 -0
- package/plugins/litclaude/skills/programming/scripts/go/new-project.py +138 -0
- package/plugins/litclaude/skills/programming/scripts/go/templates/.editorconfig +13 -0
- package/plugins/litclaude/skills/programming/scripts/go/templates/.golangci.yml +95 -0
- package/plugins/litclaude/skills/programming/scripts/go/templates/AGENTS.md.tmpl +24 -0
- package/plugins/litclaude/skills/programming/scripts/go/templates/README.md.tmpl +12 -0
- package/plugins/litclaude/skills/programming/scripts/go/templates/Taskfile.yml +40 -0
- package/plugins/litclaude/skills/programming/scripts/go/templates/ci.yml +37 -0
- package/plugins/litclaude/skills/programming/scripts/go/templates/config.go +24 -0
- package/plugins/litclaude/skills/programming/scripts/go/templates/gitignore +15 -0
- package/plugins/litclaude/skills/programming/scripts/go/templates/main.go.tmpl +22 -0
- package/plugins/litclaude/skills/programming/scripts/go/templates/run.go +15 -0
- package/plugins/litclaude/skills/programming/scripts/python/check-no-excuse-rules.py +687 -0
- package/plugins/litclaude/skills/programming/scripts/python/new-project.py +172 -0
- package/plugins/litclaude/skills/programming/scripts/python/new-script.py +116 -0
- package/plugins/litclaude/skills/programming/scripts/rust/check-no-excuse-rules.py +296 -0
- package/plugins/litclaude/skills/programming/scripts/rust/check-no-excuse-rules.sh +158 -0
- package/plugins/litclaude/skills/programming/scripts/rust/new-project.py +175 -0
- package/plugins/litclaude/skills/programming/scripts/typescript/check-no-excuse-rules.ts +282 -0
- package/plugins/litclaude/skills/programming/scripts/typescript/new-project.ts +177 -0
- package/plugins/litclaude/skills/refactor/SKILL.md +73 -0
- package/plugins/litclaude/skills/remove-ai-slops/SKILL.md +52 -0
- package/plugins/litclaude/skills/review-work/SKILL.md +331 -0
- package/plugins/litclaude/skills/rules/SKILL.md +66 -0
- package/plugins/litclaude/skills/start-work/SKILL.md +132 -0
- package/scripts/audit-plan-checkboxes.mjs +37 -0
- package/scripts/doctor.mjs +41 -0
- package/scripts/inspect-agent-tools.mjs +27 -0
- package/scripts/postinstall.mjs +50 -0
- package/scripts/qa-claude-plugin-smoke.sh +60 -0
- package/scripts/qa-portable-install.sh +136 -0
- package/scripts/validate-plugin.mjs +72 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { execFileSync } from "node:child_process";
|
|
4
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
5
|
+
import { dirname, join } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { accentCodeForName, litBrandPrefix, supportsTruecolor } from "../lib/hud-accent-palette.mjs";
|
|
8
|
+
|
|
9
|
+
const pluginRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
10
|
+
const pluginManifestPath = join(pluginRoot, ".claude-plugin", "plugin.json");
|
|
11
|
+
const noColor = process.env.NO_COLOR || process.env.LITCLAUDE_HUD_NO_COLOR === "1";
|
|
12
|
+
const sep = process.env.LITCLAUDE_HUD_SEP || "│";
|
|
13
|
+
const configuredAccent = String(process.env.LITCLAUDE_HUD_ACCENT || "cyan").toLowerCase();
|
|
14
|
+
const accentCode = accentCodeForName(configuredAccent);
|
|
15
|
+
|
|
16
|
+
const colors = noColor
|
|
17
|
+
? { reset: "", bold: "", dim: "", accent: "", empty: "", green: "", yellow: "", red: "" }
|
|
18
|
+
: {
|
|
19
|
+
reset: "\x1b[0m",
|
|
20
|
+
bold: "\x1b[1m",
|
|
21
|
+
dim: "\x1b[38;5;245m",
|
|
22
|
+
accent: `\x1b[38;5;${accentCode}m`,
|
|
23
|
+
empty: "\x1b[38;5;238m",
|
|
24
|
+
green: "\x1b[38;5;71m",
|
|
25
|
+
yellow: "\x1b[38;5;178m",
|
|
26
|
+
red: "\x1b[38;5;167m",
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const accent = (text) => `${colors.accent}${text}${colors.reset}`;
|
|
30
|
+
|
|
31
|
+
const readStdin = async () => {
|
|
32
|
+
let input = "";
|
|
33
|
+
for await (const chunk of process.stdin) input += chunk;
|
|
34
|
+
return input;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const readVersion = () => {
|
|
38
|
+
if (process.env.LITCLAUDE_VERSION) return process.env.LITCLAUDE_VERSION;
|
|
39
|
+
try {
|
|
40
|
+
return JSON.parse(readFileSync(pluginManifestPath, "utf8")).version ?? "?";
|
|
41
|
+
} catch {
|
|
42
|
+
return "?";
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const shortModel = (raw) => {
|
|
47
|
+
const compact = String(raw || "?")
|
|
48
|
+
.replace(/\([^)]*\)/gu, "")
|
|
49
|
+
.replace(/\[[^\]]*\]/gu, "")
|
|
50
|
+
.replace(/\s+/gu, " ")
|
|
51
|
+
.trim();
|
|
52
|
+
const number = compact.match(/[0-9]+(?:\.[0-9]+)?/u)?.[0] ?? "";
|
|
53
|
+
if (/opus/iu.test(compact)) return `O${number}`;
|
|
54
|
+
if (/sonnet/iu.test(compact)) return `S${number}`;
|
|
55
|
+
if (/haiku/iu.test(compact)) return `H${number}`;
|
|
56
|
+
return compact.slice(0, 10) || "?";
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const clamp = (value, min = 0, max = 100) => Math.max(min, Math.min(max, Number.isFinite(value) ? value : min));
|
|
60
|
+
|
|
61
|
+
const displayPercent = (value) => Math.round(clamp(value));
|
|
62
|
+
|
|
63
|
+
const barColor = (value) => {
|
|
64
|
+
if (value >= 90) return colors.red;
|
|
65
|
+
if (value >= 70) return colors.yellow;
|
|
66
|
+
return colors.green;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const makeBlockBar = (value, width = 3, color = null) => {
|
|
70
|
+
const pct = clamp(Math.round(value));
|
|
71
|
+
const exact = (pct * width) / 100;
|
|
72
|
+
const filled = Math.floor(exact);
|
|
73
|
+
const partial = exact - filled;
|
|
74
|
+
const partialBlocks = ["", "▏", "▎", "▍", "▌", "▋", "▊", "▉"];
|
|
75
|
+
const partialIndex = filled < width && partial > 0 ? Math.max(1, Math.min(7, Math.round(partial * 8))) : 0;
|
|
76
|
+
const empty = width - filled - (partialIndex > 0 ? 1 : 0);
|
|
77
|
+
return `${color ?? barColor(pct)}${"█".repeat(filled)}${partialBlocks[partialIndex]}${colors.empty}${"░".repeat(empty)}${colors.reset}`;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const makeContextBar = (value, width = 3) => {
|
|
81
|
+
const pct = clamp(Math.round(value));
|
|
82
|
+
return makeBlockBar(pct, width, colors.accent);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const latestUsageTokens = (transcriptPath) => {
|
|
86
|
+
if (!transcriptPath || !existsSync(transcriptPath)) return 0;
|
|
87
|
+
const lines = readFileSync(transcriptPath, "utf8").split(/\r?\n/u).filter(Boolean);
|
|
88
|
+
for (let index = lines.length - 1; index >= 0; index -= 1) {
|
|
89
|
+
try {
|
|
90
|
+
const event = JSON.parse(lines[index]);
|
|
91
|
+
const usage = event?.message?.usage;
|
|
92
|
+
if (!usage || event.isSidechain === true || event.isApiErrorMessage === true) continue;
|
|
93
|
+
return (
|
|
94
|
+
Number(usage.input_tokens ?? 0) +
|
|
95
|
+
Number(usage.cache_read_input_tokens ?? 0) +
|
|
96
|
+
Number(usage.cache_creation_input_tokens ?? 0)
|
|
97
|
+
);
|
|
98
|
+
} catch {
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return 0;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const latestUserMessage = (transcriptPath) => {
|
|
105
|
+
if (!transcriptPath || !existsSync(transcriptPath)) return "";
|
|
106
|
+
const lines = readFileSync(transcriptPath, "utf8").split(/\r?\n/u).filter(Boolean);
|
|
107
|
+
const ignoredPrefixes = ["[Request interrupted", "[Request cancelled", "<local-command-stdout>", "<local-command-stderr>"];
|
|
108
|
+
const hasCommandXml = (text) => /<(?:command-name|command-message|command-args)\b[^>]*>/u.test(text);
|
|
109
|
+
for (let index = lines.length - 1; index >= 0; index -= 1) {
|
|
110
|
+
try {
|
|
111
|
+
const event = JSON.parse(lines[index]);
|
|
112
|
+
if (event.type !== "user") continue;
|
|
113
|
+
const content = event?.message?.content;
|
|
114
|
+
const text = Array.isArray(content)
|
|
115
|
+
? content.filter((part) => part?.type === "text").map((part) => part.text).join(" ")
|
|
116
|
+
: content;
|
|
117
|
+
const normalized = String(text || "").replace(/\s+/gu, " ").trim();
|
|
118
|
+
if (normalized && !ignoredPrefixes.some((prefix) => normalized.startsWith(prefix)) && !hasCommandXml(normalized)) {
|
|
119
|
+
return normalized;
|
|
120
|
+
}
|
|
121
|
+
} catch {
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return "";
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const gitStatus = (cwd) => {
|
|
128
|
+
if (!cwd || !existsSync(cwd)) return "";
|
|
129
|
+
try {
|
|
130
|
+
const branch = execFileSync("git", ["-C", cwd, "branch", "--show-current"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
131
|
+
if (!branch) return "";
|
|
132
|
+
const status = execFileSync("git", ["-C", cwd, "--no-optional-locks", "status", "--porcelain", "-uall"], {
|
|
133
|
+
encoding: "utf8",
|
|
134
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
135
|
+
}).trim();
|
|
136
|
+
const count = status ? status.split(/\r?\n/u).length : 0;
|
|
137
|
+
let sync = "✓";
|
|
138
|
+
try {
|
|
139
|
+
execFileSync("git", ["-C", cwd, "rev-parse", "--abbrev-ref", "@{upstream}"], { stdio: "ignore" });
|
|
140
|
+
const [ahead, behind] = execFileSync("git", ["-C", cwd, "rev-list", "--left-right", "--count", "HEAD...@{upstream}"], {
|
|
141
|
+
encoding: "utf8",
|
|
142
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
143
|
+
}).trim().split(/\s+/u).map(Number);
|
|
144
|
+
sync = `${ahead > 0 ? `↑${ahead}` : ""}${behind > 0 ? `↓${behind}` : ""}` || "✓";
|
|
145
|
+
} catch {
|
|
146
|
+
sync = "✓";
|
|
147
|
+
}
|
|
148
|
+
return `${branch}${count > 0 ? ` +${count}` : ""} ${sync}`;
|
|
149
|
+
} catch {
|
|
150
|
+
return "";
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const firstNumber = (...values) => {
|
|
155
|
+
for (const value of values) {
|
|
156
|
+
const number = Number(value);
|
|
157
|
+
if (Number.isFinite(number)) return number;
|
|
158
|
+
}
|
|
159
|
+
return null;
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const firstString = (...values) => {
|
|
163
|
+
for (const value of values) {
|
|
164
|
+
if (typeof value === "string" && value.trim()) return value.trim();
|
|
165
|
+
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
166
|
+
}
|
|
167
|
+
return "";
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
const parseUsage = (status) => {
|
|
171
|
+
const raw = process.env.LITCLAUDE_HUD_TEST_USAGE || process.env.CLAUDE_HUD_TEST_USAGE || "";
|
|
172
|
+
const values = {};
|
|
173
|
+
for (const part of raw.split(",")) {
|
|
174
|
+
const [key, value] = part.split("=");
|
|
175
|
+
if (!key || value === undefined) continue;
|
|
176
|
+
values[key.trim()] = value.trim();
|
|
177
|
+
}
|
|
178
|
+
const fiveHour = status.rate_limits?.five_hour ?? status.rate_limits?.["5_hour"] ?? {};
|
|
179
|
+
const sevenDay = status.rate_limits?.seven_day ?? status.rate_limits?.["7_day"] ?? status.rate_limits?.weekly ?? {};
|
|
180
|
+
const fiveHourPct = firstNumber(values["5h"], values.five_hour, fiveHour.used_percentage, fiveHour.percentage, fiveHour.usedPercent);
|
|
181
|
+
const weeklyPct = firstNumber(values["1w"], values.wk, values.seven_day, sevenDay.used_percentage, sevenDay.percentage, sevenDay.usedPercent);
|
|
182
|
+
return {
|
|
183
|
+
fiveHour: fiveHourPct === null ? null : clamp(fiveHourPct),
|
|
184
|
+
fiveHourReset: firstString(
|
|
185
|
+
values.reset5,
|
|
186
|
+
values.reset5h,
|
|
187
|
+
fiveHour.resets_at,
|
|
188
|
+
fiveHour.reset_at,
|
|
189
|
+
fiveHour.reset_time,
|
|
190
|
+
fiveHour.resetAt,
|
|
191
|
+
fiveHour.resetTime,
|
|
192
|
+
fiveHour.next_reset,
|
|
193
|
+
fiveHour.nextReset,
|
|
194
|
+
),
|
|
195
|
+
weekly: weeklyPct === null ? null : clamp(weeklyPct),
|
|
196
|
+
weeklyReset: firstString(
|
|
197
|
+
values.reset1,
|
|
198
|
+
values.resetw,
|
|
199
|
+
values.reset7,
|
|
200
|
+
values.reset7d,
|
|
201
|
+
sevenDay.resets_at,
|
|
202
|
+
sevenDay.reset_at,
|
|
203
|
+
sevenDay.reset_time,
|
|
204
|
+
sevenDay.resetAt,
|
|
205
|
+
sevenDay.resetTime,
|
|
206
|
+
sevenDay.next_reset,
|
|
207
|
+
sevenDay.nextReset,
|
|
208
|
+
),
|
|
209
|
+
};
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
const parseResetTarget = (value) => {
|
|
213
|
+
if (!value) return NaN;
|
|
214
|
+
const raw = String(value).trim();
|
|
215
|
+
if (/^\d+(?:\.\d+)?$/u.test(raw)) {
|
|
216
|
+
const epoch = Number(raw);
|
|
217
|
+
return epoch < 100000000000 ? epoch * 1000 : epoch;
|
|
218
|
+
}
|
|
219
|
+
return Date.parse(raw);
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
const formatReset = (value) => {
|
|
223
|
+
const target = parseResetTarget(value);
|
|
224
|
+
if (!Number.isFinite(target)) return "";
|
|
225
|
+
const minutes = Math.max(0, Math.floor((target - Date.now()) / 60000));
|
|
226
|
+
const hours = Math.floor(minutes / 60);
|
|
227
|
+
const days = Math.floor(hours / 24);
|
|
228
|
+
if (days > 0) return `↻${days}d${hours % 24}h`;
|
|
229
|
+
if (hours > 0) return `↻${hours}h${minutes % 60}m`;
|
|
230
|
+
return `↻${minutes}m`;
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
const formatUsageSegment = (label, value, reset) => {
|
|
234
|
+
const labelText = accent(label);
|
|
235
|
+
if (value === null) return `${labelText} ${accent("[")}${colors.accent}░░${colors.reset}${accent("]")} ${accent("--%")}`;
|
|
236
|
+
const pct = displayPercent(value);
|
|
237
|
+
const resetText = formatReset(reset);
|
|
238
|
+
return `${labelText} ${accent("[")}${makeBlockBar(pct, 2)}${accent("]")} ${barColor(pct)}${pct}%${colors.reset}${resetText ? ` ${accent(resetText)}` : ""}`;
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
const main = async () => {
|
|
242
|
+
const input = await readStdin();
|
|
243
|
+
const status = input.trim() ? JSON.parse(input) : {};
|
|
244
|
+
const version = readVersion();
|
|
245
|
+
const model = shortModel(status.model?.display_name ?? status.model?.id);
|
|
246
|
+
const maxContext = Number(status.context_window?.context_window_size ?? 200000);
|
|
247
|
+
const maxK = Math.max(1, Math.round(maxContext / 1000));
|
|
248
|
+
const tokens = latestUsageTokens(status.transcript_path);
|
|
249
|
+
const estimatedTokens = tokens > 0 ? tokens : 20000;
|
|
250
|
+
const statusContextPct = firstNumber(status.context_window?.used_percentage, status.context_window?.usage_percentage);
|
|
251
|
+
const rawContextPct = statusContextPct === null ? Math.floor((estimatedTokens * 100) / maxContext) : statusContextPct;
|
|
252
|
+
const contextPct = displayPercent(rawContextPct);
|
|
253
|
+
const usage = parseUsage(status);
|
|
254
|
+
const usageText = ` ${accent(sep)} ${formatUsageSegment("5h", usage.fiveHour, usage.fiveHourReset)} ${accent(sep)} ${formatUsageSegment("1w", usage.weekly, usage.weeklyReset)}`;
|
|
255
|
+
const git = gitStatus(status.cwd);
|
|
256
|
+
const prefix = litBrandPrefix(version, { noColor, truecolor: supportsTruecolor() });
|
|
257
|
+
const contextText = `${accent("ctx")} ${accent("[")}${makeContextBar(contextPct)}${accent("]")} ${accent(`${contextPct}%/${maxK}k`)}`;
|
|
258
|
+
const line = `${prefix} ${accent("|")} ${accent(model)} ${accent(sep)} ${contextText}${usageText}${git ? ` ${accent(sep)} ${accent("git")} ${accent(git)}` : ""}`;
|
|
259
|
+
process.stdout.write(`${line}\n`);
|
|
260
|
+
|
|
261
|
+
const lastMessage = latestUserMessage(status.transcript_path);
|
|
262
|
+
if (lastMessage) {
|
|
263
|
+
const trimmed = lastMessage.length > 120 ? `${lastMessage.slice(0, 117)}...` : lastMessage;
|
|
264
|
+
process.stdout.write(`└─ ${trimmed}\n`);
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
main().catch((error) => {
|
|
269
|
+
process.stdout.write(`[🔥LITCLAUDE v${readVersion()}] | HUD unavailable: ${error.message}\n`);
|
|
270
|
+
process.exit(0);
|
|
271
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
4
|
+
|
|
5
|
+
const result = spawnSync("typescript-language-server", ["--version"], {
|
|
6
|
+
encoding: "utf8",
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
if (result.error) {
|
|
10
|
+
console.log("typescript-language-server is not available.");
|
|
11
|
+
console.log("Install with: npm install -g typescript-language-server typescript");
|
|
12
|
+
process.exit(0);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
console.log(`typescript-language-server available: ${(result.stdout || result.stderr).trim()}`);
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const protocolVersion = "2024-11-05";
|
|
4
|
+
|
|
5
|
+
const write = (message) => {
|
|
6
|
+
process.stdout.write(`${JSON.stringify(message)}\n`);
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const result = (id, value) => write({ jsonrpc: "2.0", id, result: value });
|
|
10
|
+
|
|
11
|
+
const error = (id, code, message) => write({ jsonrpc: "2.0", id, error: { code, message } });
|
|
12
|
+
|
|
13
|
+
const handleMessage = (message) => {
|
|
14
|
+
if (!message || typeof message !== "object" || !("id" in message)) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
switch (message.method) {
|
|
19
|
+
case "initialize":
|
|
20
|
+
result(message.id, {
|
|
21
|
+
protocolVersion,
|
|
22
|
+
capabilities: { tools: {} },
|
|
23
|
+
serverInfo: { name: "litclaude", version: "0.1.0" },
|
|
24
|
+
});
|
|
25
|
+
break;
|
|
26
|
+
case "ping":
|
|
27
|
+
result(message.id, {});
|
|
28
|
+
break;
|
|
29
|
+
case "tools/list":
|
|
30
|
+
result(message.id, { tools: [] });
|
|
31
|
+
break;
|
|
32
|
+
case "tools/call":
|
|
33
|
+
error(message.id, -32601, "LitClaude MCP exposes no callable tools in this MVP.");
|
|
34
|
+
break;
|
|
35
|
+
default:
|
|
36
|
+
error(message.id, -32601, `Unknown method: ${message.method}`);
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
let buffer = "";
|
|
42
|
+
|
|
43
|
+
process.stdin.setEncoding("utf8");
|
|
44
|
+
process.stdin.on("data", (chunk) => {
|
|
45
|
+
buffer += chunk;
|
|
46
|
+
let newlineIndex = buffer.indexOf("\n");
|
|
47
|
+
while (newlineIndex !== -1) {
|
|
48
|
+
const line = buffer.slice(0, newlineIndex).trim();
|
|
49
|
+
buffer = buffer.slice(newlineIndex + 1);
|
|
50
|
+
if (line) {
|
|
51
|
+
try {
|
|
52
|
+
handleMessage(JSON.parse(line));
|
|
53
|
+
} catch {
|
|
54
|
+
error(null, -32700, "Parse error");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
newlineIndex = buffer.indexOf("\n");
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
process.stdin.on("end", () => {
|
|
62
|
+
const line = buffer.trim();
|
|
63
|
+
if (line) {
|
|
64
|
+
try {
|
|
65
|
+
handleMessage(JSON.parse(line));
|
|
66
|
+
} catch {
|
|
67
|
+
error(null, -32700, "Parse error");
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Clarify broad or underspecified work before planning or implementation.
|
|
3
|
+
argument-hint: '[--quick|--standard|--deep] <idea or vague description>'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Use the `deep-interview` skill for the user's current brief or command
|
|
7
|
+
arguments.
|
|
8
|
+
|
|
9
|
+
Run it as a requirements mode, not an implementation mode:
|
|
10
|
+
|
|
11
|
+
- Ask one question per round.
|
|
12
|
+
- Gather read-only codebase facts before asking the user for facts Claude can
|
|
13
|
+
discover directly.
|
|
14
|
+
- Track ambiguity, non-goals, decision boundaries, and a pressure pass.
|
|
15
|
+
- Persist state under `deep-interview/` so interrupted interviews can resume.
|
|
16
|
+
- Crystallize a spec before handing off to `/litclaude:lit-plan`,
|
|
17
|
+
`/litclaude:lit-loop`, or `/litclaude:start-work`.
|
|
18
|
+
|
|
19
|
+
If the user has already supplied concrete files, acceptance criteria, and
|
|
20
|
+
non-goals, state that the interview can be skipped and hand the brief to the
|
|
21
|
+
appropriate planning or execution command.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Verify and run LitClaude Dynamic workflow delegation.
|
|
3
|
+
argument-hint: '<objective>'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Use the `lit-loop` skill for the user's current objective, with this
|
|
7
|
+
Dynamic-workflow bootstrap first.
|
|
8
|
+
|
|
9
|
+
1. Inspect native goal state when model-facing tools are exposed: call
|
|
10
|
+
`get_goal`, call `create_goal` only when no matching active goal exists, and
|
|
11
|
+
reserve `update_goal` for verified completion or a genuine blocker. If only
|
|
12
|
+
the user-visible goal surface is available, ask for one exact
|
|
13
|
+
`/goal <completion condition>` instead of claiming LitClaude set it.
|
|
14
|
+
2. Run `litclaude-ai workflow-check --json` when the package CLI is available.
|
|
15
|
+
Treat a failing check as BLOCKED until the missing route, command, or
|
|
16
|
+
subagent delegation surface is fixed.
|
|
17
|
+
3. For broad, risky, parallel, or long-running work, call the `Workflow` tool
|
|
18
|
+
when Claude Code exposes it. Bind each lane to success criteria, evidence
|
|
19
|
+
artifacts, and cleanup receipts.
|
|
20
|
+
4. Use subagent delegation where available:
|
|
21
|
+
- `prometheus-planner` for read-only planning and dependency ordering.
|
|
22
|
+
- `boulder-executor` for implementation against a checked plan.
|
|
23
|
+
- `oracle-verifier` for evidence and acceptance verification.
|
|
24
|
+
- `qa-runner` for tmux/manual-QA scenarios and cleanup receipts.
|
|
25
|
+
- `quality-reviewer` for code-quality and security findings.
|
|
26
|
+
- `librarian-researcher` for local-first context mining.
|
|
27
|
+
Each child assignment starts with `TASK:` and includes `DELIVERABLE`,
|
|
28
|
+
`SCOPE`, and `VERIFY`. Use short wait cycles; treat timeouts as no-update
|
|
29
|
+
signals, and fallback only after a missing deliverable, acknowledgement-only
|
|
30
|
+
reply, or `BLOCKED:` report.
|
|
31
|
+
5. For isolated edit lanes, use `EnterWorktree` when exposed. If only the CLI
|
|
32
|
+
surface exists, use or recommend `claude --worktree <short-name> --tmux`.
|
|
33
|
+
|
|
34
|
+
Do not auto-type `/goal`, do not echo or execute prompt text, and do not mutate
|
|
35
|
+
remote state. Continue through the normal LitClaude evidence loop:
|
|
36
|
+
`PIN -> RED -> GREEN -> VERIFY -> SURFACE -> REVIEW -> CLEAN -> RECORD`.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Run LitClaude lit-loop discipline with goal and Dynamic workflow bootstrap.
|
|
3
|
+
argument-hint: '<objective>'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Use the `lit-loop` skill for the user's current objective or command arguments.
|
|
7
|
+
|
|
8
|
+
Before implementation, bootstrap Claude Code-native workflow state:
|
|
9
|
+
|
|
10
|
+
1. If model-facing goal tools are available in this session, inspect `get_goal`,
|
|
11
|
+
call `create_goal` only when no matching goal exists, and reserve
|
|
12
|
+
`update_goal` for verified completion or a genuine blocker.
|
|
13
|
+
2. If goal tools are unavailable, state that plainly and ask the user to bind
|
|
14
|
+
the native Claude Code goal with this exact surface before long execution:
|
|
15
|
+
`/goal <completion condition for the current objective>`.
|
|
16
|
+
3. For broad, risky, parallel, or long-running work, call the `Workflow` tool
|
|
17
|
+
when Claude Code exposes it. Bind every lane to explicit criteria, evidence
|
|
18
|
+
artifacts, and cleanup receipts.
|
|
19
|
+
4. When isolated edits are needed, use `EnterWorktree` when Claude Code exposes
|
|
20
|
+
it. If only the CLI surface is available, tell the user the concrete launch
|
|
21
|
+
form: `claude --worktree <short-name> --tmux`.
|
|
22
|
+
|
|
23
|
+
Then continue with evidence-bound success criteria, tests, manual QA artifacts,
|
|
24
|
+
cleanup receipts, and explicit release approval boundaries.
|
|
25
|
+
|
|
26
|
+
Run the objective through `PIN -> RED -> GREEN -> VERIFY -> SURFACE -> REVIEW
|
|
27
|
+
-> CLEAN -> RECORD`:
|
|
28
|
+
|
|
29
|
+
- PIN the objective, non-goals, stale state to reread, dirty worktree files,
|
|
30
|
+
commit/push approval, publish approval, and resume checkpoint.
|
|
31
|
+
- RED before implementation when behavior changes, then GREEN with targeted
|
|
32
|
+
evidence and broader verification.
|
|
33
|
+
- SURFACE with a real Manual-QA channel and artifact.
|
|
34
|
+
- REVIEW when the change is broad, risky, shared, security-sensitive, or
|
|
35
|
+
release-facing.
|
|
36
|
+
- CLEAN with a bounded cleanup receipt for tmux sessions, servers, ports,
|
|
37
|
+
browser contexts, temp directories, and child processes.
|
|
38
|
+
|
|
39
|
+
Stop rules: stop before unapproved commit/push or publish, stop on malformed or
|
|
40
|
+
contradictory requirements, and reread live repo state on resume before acting.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Plan LitClaude work with explicit goal, Dynamic workflow, and QA criteria.
|
|
3
|
+
argument-hint: '<planning brief>'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Use the `lit-plan` skill for the user's current planning brief or command
|
|
7
|
+
arguments.
|
|
8
|
+
|
|
9
|
+
The plan must include Claude Code-native bootstrap steps:
|
|
10
|
+
|
|
11
|
+
- If model-facing goal tools are exposed, use `get_goal`, `create_goal`, and
|
|
12
|
+
delayed `update_goal` exactly as native goal state, not as slash-command text.
|
|
13
|
+
- If goal tools are unavailable, include the exact user-visible `/goal`
|
|
14
|
+
completion condition to bind before execution.
|
|
15
|
+
- For independent, risky, parallel, or long-running work, include when Claude
|
|
16
|
+
should call the `Workflow` tool and how each lane proves its evidence.
|
|
17
|
+
- For isolated edit lanes, include when to use `EnterWorktree`; if only the CLI
|
|
18
|
+
surface is available, include `claude --worktree <short-name> --tmux`, plus
|
|
19
|
+
evidence paths and cleanup.
|
|
20
|
+
|
|
21
|
+
Write the plan under `plans/` and keep it executable: concrete files, tests,
|
|
22
|
+
manual QA, cleanup, and publish/remote-mutation guardrails.
|
|
23
|
+
|
|
24
|
+
The plan must include a strict execution section:
|
|
25
|
+
|
|
26
|
+
- Bootstrap and PIN: objective, non-goals, stale state, dirty worktree
|
|
27
|
+
constraints, resume ledger, commit/push boundary, and publish boundary.
|
|
28
|
+
- TDD loop: `PIN -> RED -> GREEN -> VERIFY -> SURFACE -> REVIEW -> CLEAN ->
|
|
29
|
+
RECORD`.
|
|
30
|
+
- Manual-QA: exact channel, command or steps, PASS/FAIL observable, artifact
|
|
31
|
+
path, and cleanup receipt.
|
|
32
|
+
- Reviewer gate: when to run it and what artifact proves it passed or was not
|
|
33
|
+
required.
|
|
34
|
+
- Stop rules: stop on malformed plan input, contradictory live state,
|
|
35
|
+
unapproved remote mutation, missing artifacts, or repeated identical failure.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Manage LitClaude litgoal ledger and durable goal state.
|
|
3
|
+
argument-hint: '<goal operation>'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Use the `litgoal` skill for the user's current goal operation or command
|
|
7
|
+
arguments.
|
|
8
|
+
|
|
9
|
+
Prefer the package CLI for durable local state:
|
|
10
|
+
`litclaude-ai litgoal create-goals`, `status`, `criteria`,
|
|
11
|
+
`record-evidence`, `checkpoint`, `steer`, and `record-review-blockers`.
|
|
12
|
+
The installed alias may also be invoked as:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
litclaude litgoal create-goals --brief "<brief>" --json
|
|
16
|
+
litclaude litgoal record-evidence --criterion <id> --status pass --json '{"artifact":"...","cleanup":"..."}'
|
|
17
|
+
litclaude litgoal checkpoint --status active --note "<progress>" --json
|
|
18
|
+
litclaude litgoal steer --kind scope --note "<what changed and why>" --json
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The ledger lives under `.litclaude/litgoal/` unless test environment variables
|
|
22
|
+
override it. Bind work to native goal tools when they are available; when goal
|
|
23
|
+
tools are unavailable, record clear criteria and evidence in the local ledger.
|
|
24
|
+
For broad goal execution, use Dynamic workflow when Claude Code exposes it, and
|
|
25
|
+
use `claude --worktree <short-name> --tmux` only when isolated worktree
|
|
26
|
+
execution is needed.
|
|
27
|
+
Manual-QA channels and cleanup receipt artifacts should be recorded with
|
|
28
|
+
`record-evidence`. Malformed JSON, unknown criteria, corrupt state, and invalid
|
|
29
|
+
steering kinds must fail as controlled errors. Use current docs/test reads
|
|
30
|
+
before trusting stale local state.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Run LitClaude 5-lane review discipline.
|
|
3
|
+
argument-hint: '<scope>'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Use the `review-work` skill for the user's current scope or command arguments.
|
|
7
|
+
|
|
8
|
+
Run the 5-lane review contract: goal and constraint verification
|
|
9
|
+
(goal/constraint), hands-on QA execution, code quality review, security review,
|
|
10
|
+
and local-first context mining.
|
|
11
|
+
Aggregate findings into a PASS, FAIL, or NEEDS-CONTEXT verdict, and cite the
|
|
12
|
+
evidence used for every lane.
|
|
13
|
+
Manual-QA channels must leave artifacts, cleanup receipt paths, and bounded
|
|
14
|
+
session teardown proof. Respect the publish boundary: reviewing release
|
|
15
|
+
readiness is allowed, but npm publish, remote marketplace registration, and
|
|
16
|
+
other remote mutation still need explicit user approval.
|
|
17
|
+
|
|
18
|
+
Lane routing:
|
|
19
|
+
|
|
20
|
+
- goal and constraint verification: use `oracle-verifier` with `review-work`
|
|
21
|
+
and `rules`.
|
|
22
|
+
- hands-on QA execution: use `qa-runner` with `start-work` and `review-work`.
|
|
23
|
+
- code quality review: use `quality-reviewer` with `review-work` and
|
|
24
|
+
`programming`.
|
|
25
|
+
- security review: use `quality-reviewer` with `review-work` and
|
|
26
|
+
`programming`.
|
|
27
|
+
- local-first context mining: use `librarian-researcher` with `rules`.
|
|
28
|
+
|
|
29
|
+
Before launching broad review work, check whether native goal tools are
|
|
30
|
+
available and bind the review to the active goal. If goal tools are unavailable,
|
|
31
|
+
keep the local evidence ledger authoritative. For large independent lanes, use
|
|
32
|
+
Dynamic workflow when Claude Code exposes it, and use `claude --worktree` only
|
|
33
|
+
when isolated review edits or reproduction steps need a separate checkout.
|
|
34
|
+
Use current docs/test reads before trusting stale local state or continuation
|
|
35
|
+
notes.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Execute a checked plan with LitClaude start-work discipline.
|
|
3
|
+
argument-hint: '<plan-file>'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Use the `start-work` skill for the user's current plan file or command
|
|
7
|
+
arguments.
|
|
8
|
+
|
|
9
|
+
Before the first checkbox, bootstrap Claude Code-native workflow state:
|
|
10
|
+
|
|
11
|
+
- Use `get_goal` and `create_goal` only if model-facing goal tools are exposed.
|
|
12
|
+
- If goal tools are unavailable, ask the user to set a native `/goal` completion
|
|
13
|
+
condition for the plan before multi-turn execution.
|
|
14
|
+
- For broad, risky, parallel, or long-running checkbox waves, call the
|
|
15
|
+
`Workflow` tool when Claude Code exposes it.
|
|
16
|
+
- For isolated edit lanes, use `EnterWorktree` when exposed; otherwise launch
|
|
17
|
+
or recommend `claude --worktree <short-name> --tmux`.
|
|
18
|
+
|
|
19
|
+
Then execute the first unchecked top-level checkbox with failing-test-first
|
|
20
|
+
implementation, automated verification, manual QA evidence, cleanup receipts,
|
|
21
|
+
and ledger updates.
|
|
22
|
+
|
|
23
|
+
For that checkbox, enforce `PIN -> RED -> GREEN -> VERIFY -> SURFACE -> REVIEW
|
|
24
|
+
-> CLEAN -> RECORD`:
|
|
25
|
+
|
|
26
|
+
- PIN the plan objective, selected checkbox, stale state, dirty worktree
|
|
27
|
+
boundaries, resume checkpoint, commit/push approval, and publish approval.
|
|
28
|
+
- RED first for behavior changes, then GREEN with targeted and plan-level tests.
|
|
29
|
+
- SURFACE through the plan's Manual-QA channel with an artifact path.
|
|
30
|
+
- REVIEW broad, risky, shared, security-sensitive, or release-facing changes.
|
|
31
|
+
- CLEAN with bounded cleanup receipt for tmux sessions, servers, ports, browser
|
|
32
|
+
contexts, temp directories, and child processes.
|
|
33
|
+
|
|
34
|
+
Stop rules: stop on malformed plan structure, missing acceptance criteria,
|
|
35
|
+
missing Manual-QA or cleanup requirements, contradictory live state, or
|
|
36
|
+
unapproved commit/push or publish.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"SessionStart": [
|
|
4
|
+
{
|
|
5
|
+
"hooks": [
|
|
6
|
+
{
|
|
7
|
+
"type": "command",
|
|
8
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/bin/litclaude-hook.js\" session-start",
|
|
9
|
+
"timeout": 10,
|
|
10
|
+
"statusMessage": "loading LitClaude rules"
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"UserPromptSubmit": [
|
|
16
|
+
{
|
|
17
|
+
"hooks": [
|
|
18
|
+
{
|
|
19
|
+
"type": "command",
|
|
20
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/bin/litclaude-hook.js\" user-prompt-submit",
|
|
21
|
+
"timeout": 5,
|
|
22
|
+
"statusMessage": "checking LitClaude workflow trigger"
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"PostToolUse": [
|
|
28
|
+
{
|
|
29
|
+
"matcher": "^(Write|Edit|MultiEdit|NotebookEdit)$",
|
|
30
|
+
"hooks": [
|
|
31
|
+
{
|
|
32
|
+
"type": "command",
|
|
33
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/bin/litclaude-hook.js\" post-tool-use",
|
|
34
|
+
"timeout": 30,
|
|
35
|
+
"statusMessage": "running LitClaude post-edit checks"
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
"PostCompact": [
|
|
41
|
+
{
|
|
42
|
+
"matcher": "manual|auto",
|
|
43
|
+
"hooks": [
|
|
44
|
+
{
|
|
45
|
+
"type": "command",
|
|
46
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/bin/litclaude-hook.js\" post-compact",
|
|
47
|
+
"timeout": 10,
|
|
48
|
+
"statusMessage": "resetting LitClaude rule cache"
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
|
|
3
|
+
const contextPressureMarkers = [
|
|
4
|
+
"context compacted",
|
|
5
|
+
"context_length_exceeded",
|
|
6
|
+
"context_too_large",
|
|
7
|
+
"context window",
|
|
8
|
+
"skill descriptions were shortened",
|
|
9
|
+
"input exceeds the context",
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
export const hasContextPressure = (text) => {
|
|
13
|
+
if (typeof text !== "string") return false;
|
|
14
|
+
const normalized = text.toLowerCase();
|
|
15
|
+
return contextPressureMarkers.some((marker) => normalized.includes(marker));
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const transcriptHasContextPressure = (transcriptPath) => {
|
|
19
|
+
if (typeof transcriptPath !== "string" || transcriptPath.length === 0) return false;
|
|
20
|
+
try {
|
|
21
|
+
return hasContextPressure(readFileSync(transcriptPath, "utf8"));
|
|
22
|
+
} catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
};
|