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.
Files changed (156) hide show
  1. package/CHANGELOG.md +155 -0
  2. package/LICENSE +21 -0
  3. package/README.md +369 -0
  4. package/README_ko-KR.md +374 -0
  5. package/RELEASE_CHECKLIST.md +165 -0
  6. package/bin/litclaude-ai.js +643 -0
  7. package/cover.png +0 -0
  8. package/docs/agents.md +67 -0
  9. package/docs/hooks.md +134 -0
  10. package/docs/lsp.md +40 -0
  11. package/docs/migration.md +209 -0
  12. package/docs/workflow-compatibility-audit.md +119 -0
  13. package/generate_cover.py +123 -0
  14. package/package.json +48 -0
  15. package/plugins/litclaude/.claude-plugin/plugin.json +25 -0
  16. package/plugins/litclaude/.lsp.json +13 -0
  17. package/plugins/litclaude/.mcp.json +9 -0
  18. package/plugins/litclaude/agents/boulder-executor.md +12 -0
  19. package/plugins/litclaude/agents/librarian-researcher.md +15 -0
  20. package/plugins/litclaude/agents/oracle-verifier.md +16 -0
  21. package/plugins/litclaude/agents/prometheus-planner.md +13 -0
  22. package/plugins/litclaude/agents/qa-runner.md +16 -0
  23. package/plugins/litclaude/agents/quality-reviewer.md +17 -0
  24. package/plugins/litclaude/bin/litclaude-hook.js +110 -0
  25. package/plugins/litclaude/bin/litclaude-hud.js +271 -0
  26. package/plugins/litclaude/bin/litclaude-lsp-doctor.js +15 -0
  27. package/plugins/litclaude/bin/litclaude-mcp.js +70 -0
  28. package/plugins/litclaude/commands/deep-interview.md +21 -0
  29. package/plugins/litclaude/commands/dynamic-workflow.md +36 -0
  30. package/plugins/litclaude/commands/lit-loop.md +40 -0
  31. package/plugins/litclaude/commands/lit-plan.md +35 -0
  32. package/plugins/litclaude/commands/litgoal.md +30 -0
  33. package/plugins/litclaude/commands/review-work.md +35 -0
  34. package/plugins/litclaude/commands/start-work.md +36 -0
  35. package/plugins/litclaude/hooks/hooks.json +54 -0
  36. package/plugins/litclaude/lib/context-pressure.mjs +25 -0
  37. package/plugins/litclaude/lib/hud-accent-palette.mjs +58 -0
  38. package/plugins/litclaude/lib/litgoal/cli.mjs +266 -0
  39. package/plugins/litclaude/lib/litgoal/ledger.mjs +16 -0
  40. package/plugins/litclaude/lib/litgoal/paths.mjs +7 -0
  41. package/plugins/litclaude/lib/litgoal/state.mjs +67 -0
  42. package/plugins/litclaude/lib/mutated-file-paths.mjs +63 -0
  43. package/plugins/litclaude/lib/start-work-continuation.mjs +99 -0
  44. package/plugins/litclaude/lib/workflow-check.mjs +83 -0
  45. package/plugins/litclaude/skills/ai-slop-remover/SKILL.md +142 -0
  46. package/plugins/litclaude/skills/comment-checker/SKILL.md +55 -0
  47. package/plugins/litclaude/skills/debugging/SKILL.md +70 -0
  48. package/plugins/litclaude/skills/debugging/references/methodology/00-setup.md +108 -0
  49. package/plugins/litclaude/skills/debugging/references/methodology/02-investigate.md +126 -0
  50. package/plugins/litclaude/skills/debugging/references/methodology/04-oracle-triple.md +106 -0
  51. package/plugins/litclaude/skills/debugging/references/methodology/05-escalate.md +69 -0
  52. package/plugins/litclaude/skills/debugging/references/methodology/06-fix.md +116 -0
  53. package/plugins/litclaude/skills/debugging/references/methodology/08-qa.md +94 -0
  54. package/plugins/litclaude/skills/debugging/references/methodology/09-cleanup.md +164 -0
  55. package/plugins/litclaude/skills/debugging/references/methodology/partial-runtime-evidence.md +228 -0
  56. package/plugins/litclaude/skills/debugging/references/runtimes/bundled-js-binary.md +415 -0
  57. package/plugins/litclaude/skills/debugging/references/runtimes/go.md +252 -0
  58. package/plugins/litclaude/skills/debugging/references/runtimes/native-binary.md +484 -0
  59. package/plugins/litclaude/skills/debugging/references/runtimes/node.md +260 -0
  60. package/plugins/litclaude/skills/debugging/references/runtimes/python.md +248 -0
  61. package/plugins/litclaude/skills/debugging/references/runtimes/rust.md +234 -0
  62. package/plugins/litclaude/skills/debugging/references/tools/ghidra.md +212 -0
  63. package/plugins/litclaude/skills/debugging/references/tools/playwright-cli.md +194 -0
  64. package/plugins/litclaude/skills/debugging/references/tools/pwndbg.md +263 -0
  65. package/plugins/litclaude/skills/debugging/references/tools/pwntools.md +265 -0
  66. package/plugins/litclaude/skills/deep-interview/SKILL.md +323 -0
  67. package/plugins/litclaude/skills/deep-interview/scripts/render_progress.py +193 -0
  68. package/plugins/litclaude/skills/frontend-ui-ux/SKILL.md +62 -0
  69. package/plugins/litclaude/skills/lit-loop/SKILL.md +144 -0
  70. package/plugins/litclaude/skills/lit-plan/SKILL.md +125 -0
  71. package/plugins/litclaude/skills/litgoal/SKILL.md +219 -0
  72. package/plugins/litclaude/skills/lsp/SKILL.md +63 -0
  73. package/plugins/litclaude/skills/programming/SKILL.md +106 -0
  74. package/plugins/litclaude/skills/programming/references/go/README.md +90 -0
  75. package/plugins/litclaude/skills/programming/references/go/backend-stack.md +641 -0
  76. package/plugins/litclaude/skills/programming/references/go/bootstrap.md +328 -0
  77. package/plugins/litclaude/skills/programming/references/go/bubbletea-v2.md +360 -0
  78. package/plugins/litclaude/skills/programming/references/go/cobra-stack.md +468 -0
  79. package/plugins/litclaude/skills/programming/references/go/concurrency.md +362 -0
  80. package/plugins/litclaude/skills/programming/references/go/data-modeling.md +329 -0
  81. package/plugins/litclaude/skills/programming/references/go/error-handling.md +359 -0
  82. package/plugins/litclaude/skills/programming/references/go/golangci-strict.md +236 -0
  83. package/plugins/litclaude/skills/programming/references/go/grpc-connect.md +375 -0
  84. package/plugins/litclaude/skills/programming/references/go/libraries.md +337 -0
  85. package/plugins/litclaude/skills/programming/references/go/one-liners.md +202 -0
  86. package/plugins/litclaude/skills/programming/references/go/sqlc-pgx.md +471 -0
  87. package/plugins/litclaude/skills/programming/references/go/testing.md +467 -0
  88. package/plugins/litclaude/skills/programming/references/go/type-patterns.md +298 -0
  89. package/plugins/litclaude/skills/programming/references/python/README.md +314 -0
  90. package/plugins/litclaude/skills/programming/references/python/async-anyio.md +442 -0
  91. package/plugins/litclaude/skills/programming/references/python/data-modeling.md +233 -0
  92. package/plugins/litclaude/skills/programming/references/python/data-processing.md +133 -0
  93. package/plugins/litclaude/skills/programming/references/python/error-handling.md +218 -0
  94. package/plugins/litclaude/skills/programming/references/python/fastapi-stack.md +316 -0
  95. package/plugins/litclaude/skills/programming/references/python/httpx2-optimization.md +360 -0
  96. package/plugins/litclaude/skills/programming/references/python/libraries.md +307 -0
  97. package/plugins/litclaude/skills/programming/references/python/one-liners.md +268 -0
  98. package/plugins/litclaude/skills/programming/references/python/orjson-stack.md +378 -0
  99. package/plugins/litclaude/skills/programming/references/python/pydantic-ai.md +285 -0
  100. package/plugins/litclaude/skills/programming/references/python/pyproject-strict.md +232 -0
  101. package/plugins/litclaude/skills/programming/references/python/textual-tui.md +201 -0
  102. package/plugins/litclaude/skills/programming/references/python/type-patterns.md +176 -0
  103. package/plugins/litclaude/skills/programming/references/rust/README.md +317 -0
  104. package/plugins/litclaude/skills/programming/references/rust/async-tokio.md +299 -0
  105. package/plugins/litclaude/skills/programming/references/rust/axum-stack.md +467 -0
  106. package/plugins/litclaude/skills/programming/references/rust/cargo-strict.md +317 -0
  107. package/plugins/litclaude/skills/programming/references/rust/clap-stack.md +409 -0
  108. package/plugins/litclaude/skills/programming/references/rust/concurrency.md +375 -0
  109. package/plugins/litclaude/skills/programming/references/rust/libraries.md +439 -0
  110. package/plugins/litclaude/skills/programming/references/rust/one-liners.md +291 -0
  111. package/plugins/litclaude/skills/programming/references/rust/proptest-insta.md +429 -0
  112. package/plugins/litclaude/skills/programming/references/rust/type-state.md +354 -0
  113. package/plugins/litclaude/skills/programming/references/rust/unsafe-discipline.md +250 -0
  114. package/plugins/litclaude/skills/programming/references/rust/zero-cost-safety.md +527 -0
  115. package/plugins/litclaude/skills/programming/references/rust-ub/README.md +289 -0
  116. package/plugins/litclaude/skills/programming/references/rust-ub/miri-sanitizers-loom.md +411 -0
  117. package/plugins/litclaude/skills/programming/references/rust-ub/ub-taxonomy.md +269 -0
  118. package/plugins/litclaude/skills/programming/references/typescript/README.md +195 -0
  119. package/plugins/litclaude/skills/programming/references/typescript/backend-hono.md +672 -0
  120. package/plugins/litclaude/skills/programming/references/typescript/bootstrap.md +199 -0
  121. package/plugins/litclaude/skills/programming/references/typescript/data-modeling.md +202 -0
  122. package/plugins/litclaude/skills/programming/references/typescript/error-handling.md +169 -0
  123. package/plugins/litclaude/skills/programming/references/typescript/tsconfig-strict.md +152 -0
  124. package/plugins/litclaude/skills/programming/references/typescript/type-patterns.md +196 -0
  125. package/plugins/litclaude/skills/programming/scripts/go/check-no-excuse-rules.sh +173 -0
  126. package/plugins/litclaude/skills/programming/scripts/go/new-project.py +138 -0
  127. package/plugins/litclaude/skills/programming/scripts/go/templates/.editorconfig +13 -0
  128. package/plugins/litclaude/skills/programming/scripts/go/templates/.golangci.yml +95 -0
  129. package/plugins/litclaude/skills/programming/scripts/go/templates/AGENTS.md.tmpl +24 -0
  130. package/plugins/litclaude/skills/programming/scripts/go/templates/README.md.tmpl +12 -0
  131. package/plugins/litclaude/skills/programming/scripts/go/templates/Taskfile.yml +40 -0
  132. package/plugins/litclaude/skills/programming/scripts/go/templates/ci.yml +37 -0
  133. package/plugins/litclaude/skills/programming/scripts/go/templates/config.go +24 -0
  134. package/plugins/litclaude/skills/programming/scripts/go/templates/gitignore +15 -0
  135. package/plugins/litclaude/skills/programming/scripts/go/templates/main.go.tmpl +22 -0
  136. package/plugins/litclaude/skills/programming/scripts/go/templates/run.go +15 -0
  137. package/plugins/litclaude/skills/programming/scripts/python/check-no-excuse-rules.py +687 -0
  138. package/plugins/litclaude/skills/programming/scripts/python/new-project.py +172 -0
  139. package/plugins/litclaude/skills/programming/scripts/python/new-script.py +116 -0
  140. package/plugins/litclaude/skills/programming/scripts/rust/check-no-excuse-rules.py +296 -0
  141. package/plugins/litclaude/skills/programming/scripts/rust/check-no-excuse-rules.sh +158 -0
  142. package/plugins/litclaude/skills/programming/scripts/rust/new-project.py +175 -0
  143. package/plugins/litclaude/skills/programming/scripts/typescript/check-no-excuse-rules.ts +282 -0
  144. package/plugins/litclaude/skills/programming/scripts/typescript/new-project.ts +177 -0
  145. package/plugins/litclaude/skills/refactor/SKILL.md +73 -0
  146. package/plugins/litclaude/skills/remove-ai-slops/SKILL.md +52 -0
  147. package/plugins/litclaude/skills/review-work/SKILL.md +331 -0
  148. package/plugins/litclaude/skills/rules/SKILL.md +66 -0
  149. package/plugins/litclaude/skills/start-work/SKILL.md +132 -0
  150. package/scripts/audit-plan-checkboxes.mjs +37 -0
  151. package/scripts/doctor.mjs +41 -0
  152. package/scripts/inspect-agent-tools.mjs +27 -0
  153. package/scripts/postinstall.mjs +50 -0
  154. package/scripts/qa-claude-plugin-smoke.sh +60 -0
  155. package/scripts/qa-portable-install.sh +136 -0
  156. package/scripts/validate-plugin.mjs +72 -0
@@ -0,0 +1,132 @@
1
+ ---
2
+ name: start-work
3
+ description: Execute a checked plan file with LitClaude Boulder state, top-level checkbox discipline, goal/workflow/worktree bootstrap, evidence ledgers, and cleanup receipts.
4
+ ---
5
+
6
+ # Start Work
7
+
8
+ Use this skill when the user asks to execute a plan file, especially
9
+ `$start-work plans/<slug>.md`. The plan file and ledger are the source of truth,
10
+ not memory.
11
+
12
+ ## Bootstrap
13
+
14
+ Before the first edit:
15
+
16
+ 1. Read the requested plan file.
17
+ 2. Read `.litclaude/start-work/ledger.jsonl` when it exists.
18
+ 3. Inspect `.litclaude/boulder.json` when it exists.
19
+ 4. Pick the first unchecked top-level checkbox in `## TODOs` or final
20
+ verification sections. Ignore nested acceptance criteria as task selectors.
21
+ 5. Decompose that checkbox into atomic tasks with tests and QA artifacts.
22
+ 6. PIN the current objective, stale state to reread, dirty worktree boundaries,
23
+ commit/push approval, publish approval, resume checkpoint, and required
24
+ cleanup receipt paths before editing.
25
+
26
+ ## Native Goal + Dynamic Workflow
27
+
28
+ Before the first checkbox, use Claude Code's native goal surface when available:
29
+
30
+ - call `get_goal` if exposed
31
+ - call `create_goal` with the plan objective only when no matching active goal
32
+ exists
33
+ - call `update_goal` only after all top-level checkboxes and final gates are
34
+ complete, or when the plan is genuinely blocked
35
+ - if the user invokes `/goal`, respect it as the native session goal
36
+ - do not auto-type or send `/goal` text from a skill
37
+
38
+ If model-facing goal tools are absent, continue with Boulder/ledger discipline.
39
+ For long plans, ask once for `/goal <plan completion condition>` if that would
40
+ help the user keep the session bounded.
41
+ If goal tools are not exposed, do not print repeated fallback status; just keep
42
+ the plan ledger accurate and continue with verified evidence.
43
+
44
+ For broad, risky, or parallel checkbox waves, use Dynamic workflow orchestration
45
+ and call `Workflow` when exposed. Use Dynamic worktree isolation with
46
+ `EnterWorktree` for isolated model-facing edit lanes when available. When
47
+ only the CLI path is available, use or recommend
48
+ `claude --worktree <short-name> --tmux`.
49
+
50
+ ## Subagent Assignment Contract
51
+
52
+ For each decomposed checkbox, child-agent assignments must be executable, not
53
+ context-only. Start each assignment with `TASK:` and include `DELIVERABLE`,
54
+ `SCOPE`, and `VERIFY`. Name exact files or directories, the characterization
55
+ test or RED reproduction, implementation constraints, automated verification,
56
+ Manual-QA channel, adversarial classes, artifact path, and cleanup receipt.
57
+
58
+ Run independent assignments in the background only when file scopes do not
59
+ collide. Use short wait cycles for mailbox updates; a timeout is not a failure
60
+ or approval. If the child returns no deliverable, sends only acknowledgement,
61
+ or reports `BLOCKED:`, record the missing deliverable and issue one targeted
62
+ follow-up before using a smaller fallback assignment. Reviewer fallback must
63
+ keep a reviewer role and is not a generic worker task.
64
+
65
+ ## Per-Checkbox Loop
66
+
67
+ For the selected checkbox:
68
+
69
+ 1. Re-read the checkbox, acceptance criteria, and prior evidence.
70
+ 2. PIN the exact file scope, non-goals, and stale facts that must be refreshed.
71
+ 3. Write or update the test first; capture RED when behavior changes.
72
+ 4. Implement the smallest change and capture GREEN with the targeted test.
73
+ 5. Run broader verification requested by the plan.
74
+ 6. Run the plan's Manual-QA scenario and capture the SURFACE artifact.
75
+ 7. Run the reviewer gate when the checkbox is broad, risky, shared,
76
+ security-sensitive, or release-facing.
77
+ 8. Clean resources and capture cleanup receipt. Cleanup must be bounded with a
78
+ timeout or kill path for tmux sessions, servers, ports, browser contexts,
79
+ temp directories, and child processes.
80
+ 9. Mark the top-level checkbox complete only after evidence exists.
81
+ 10. Append a `task-completed` line to `.litclaude/start-work/ledger.jsonl`.
82
+
83
+ Do not mark every checkbox at the end in a batch. Progress is durable and
84
+ incremental.
85
+
86
+ Use `PIN -> RED -> GREEN -> VERIFY -> SURFACE -> REVIEW -> CLEAN -> RECORD` as
87
+ the execution shorthand. If any step is missing, leave the checkbox open.
88
+
89
+ ## Evidence Standards
90
+
91
+ Every completed checkbox needs:
92
+
93
+ - automated test command and result
94
+ - manual QA artifact path
95
+ - cleanup receipt
96
+ - reviewer result or a recorded reason the reviewer gate was not required
97
+ - changed files or commit hash when applicable
98
+ - any skipped adversarial classes with reason
99
+
100
+ `--dry-run`, "looks right", or a worker's self-report is insufficient.
101
+
102
+ ## Failure Handling
103
+
104
+ If a subtask fails, retry the same task with the exact error, diagnosis, and
105
+ fix instruction. After repeated identical failures, stop and surface the
106
+ blocker with artifacts. Do not start fresh and lose the failure context.
107
+
108
+ On resume after cancel, compaction, terminal restart, or repeated interruption,
109
+ reread the plan, ledger, `.litclaude/boulder.json`, and `git status --short` before
110
+ acting. Treat prior green output as stale unless the artifact path still exists
111
+ and includes the command plus STATUS line. Never revert dirty worktree changes
112
+ you did not make.
113
+
114
+ Use `litclaude-ai start-work-next --json` when you need a compact continuation
115
+ directive from the current `.litclaude/boulder.json` state. It prints the active plan,
116
+ ledger, worktree when known, and the next unchecked top-level checkbox without
117
+ mutating state. If Claude Code later exposes a stable Stop/SubagentStop plugin
118
+ hook schema for this package shape, wire the same helper there; until then the
119
+ CLI helper is the supported continuation surface.
120
+
121
+ ## Finalization
122
+
123
+ When all top-level checkboxes are complete, run the plan's final verification
124
+ wave, update the plan file, update the ledger, commit/push if requested, and
125
+ leave a handoff if the session stops at a checkpoint.
126
+
127
+ ## Stop rules
128
+
129
+ Stop before commit/push or publish unless the user approved it for this run.
130
+ Stop when the plan is malformed, missing acceptance criteria, missing Manual-QA
131
+ channels, missing cleanup receipts, or contradicts current repository state.
132
+ Record the blocker and the next executable command instead of guessing.
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env node
2
+ import assert from "node:assert/strict";
3
+ import { readFile } from "node:fs/promises";
4
+
5
+ const planPath = process.argv[2];
6
+
7
+ if (!planPath) {
8
+ process.stderr.write("usage: audit-plan-checkboxes.mjs <plan.md>\n");
9
+ process.exit(64);
10
+ }
11
+
12
+ const text = await readFile(planPath, "utf8");
13
+ const taskPattern = /^- \[[ x]\] (?:\d+\.|F\d\.) .+$/gm;
14
+ const tasks = [...text.matchAll(taskPattern)];
15
+
16
+ assert.ok(tasks.some((task) => /^- \[[ x]\] \d+\./.test(task[0])), "expected implementation task checkboxes");
17
+ assert.ok(tasks.some((task) => /^- \[[ x]\] F\d\./.test(task[0])), "expected final verification checkboxes");
18
+
19
+ for (let index = 0; index < tasks.length; index += 1) {
20
+ const start = tasks[index].index;
21
+ const end = tasks[index + 1]?.index ?? text.length;
22
+ const block = text.slice(start, end);
23
+ const title = tasks[index][0];
24
+
25
+ if (/^- \[[ x]\] F\d\./.test(title)) {
26
+ assert.match(block, /(?:Commands?|Tool):/, `${title} missing command or tool`);
27
+ assert.match(block, /(?:Expected|Pass):/, `${title} missing expected result`);
28
+ } else {
29
+ assert.match(title, /^- \[x\]/, `${title} is not complete`);
30
+ assert.match(block, /\*\*References\*\*:/, `${title} missing references`);
31
+ assert.match(block, /\*\*Acceptance Criteria\*\*:/, `${title} missing acceptance criteria`);
32
+ assert.match(block, /\*\*QA Scenarios\*\*:/, `${title} missing QA scenarios`);
33
+ assert.match(block, /\*\*Commit\*\*:/, `${title} missing commit metadata`);
34
+ }
35
+ }
36
+
37
+ process.stdout.write(`PLAN_AUDIT_PASS: ${tasks.length} checked items complete\n`);
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env node
2
+ import { spawnSync } from "node:child_process";
3
+ import { existsSync } from "node:fs";
4
+ import { join, resolve } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+
7
+ const root = resolve(fileURLToPath(new URL("..", import.meta.url)));
8
+
9
+ function run(label, command, args) {
10
+ const result = spawnSync(command, args, {
11
+ cwd: root,
12
+ encoding: "utf8",
13
+ });
14
+
15
+ process.stdout.write(`\n## ${label}\n`);
16
+ if (result.stdout) process.stdout.write(result.stdout);
17
+ if (result.stderr) process.stdout.write(result.stderr);
18
+
19
+ if (result.status !== 0) {
20
+ process.stderr.write(`${label} failed with status ${result.status}\n`);
21
+ process.exit(result.status ?? 1);
22
+ }
23
+ }
24
+
25
+ run("CLI dry-run", process.execPath, ["bin/litclaude-ai.js", "--dry-run", "doctor"]);
26
+ run("Plugin validation", process.execPath, ["scripts/validate-plugin.mjs"]);
27
+ run("LSP doctor", process.execPath, ["plugins/litclaude/bin/litclaude-lsp-doctor.js"]);
28
+
29
+ for (const file of [
30
+ "plugins/litclaude/lib/litgoal/paths.mjs",
31
+ "plugins/litclaude/lib/litgoal/state.mjs",
32
+ "plugins/litclaude/lib/litgoal/ledger.mjs",
33
+ "plugins/litclaude/lib/litgoal/cli.mjs",
34
+ ]) {
35
+ if (!existsSync(join(root, file))) {
36
+ process.stderr.write(`Runtime payload missing: ${file}\n`);
37
+ process.exit(1);
38
+ }
39
+ }
40
+ process.stdout.write("\nLITGOAL_RUNTIME_PASS\n");
41
+ process.stdout.write("\nDOCTOR_PASS\n");
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readFileSync } from "node:fs";
4
+
5
+ const path = process.argv[2];
6
+
7
+ if (!path) {
8
+ console.error("Usage: inspect-agent-tools.mjs <agent-file>");
9
+ process.exit(64);
10
+ }
11
+
12
+ const text = readFileSync(path, "utf8");
13
+ const match = /^---\n([\s\S]*?)\n---/u.exec(text);
14
+
15
+ if (!match) {
16
+ console.error("agent frontmatter not found");
17
+ process.exit(65);
18
+ }
19
+
20
+ const toolsLine = match[1].split("\n").find((line) => line.startsWith("tools:")) ?? "tools:";
21
+ const tools = toolsLine
22
+ .replace("tools:", "")
23
+ .split(",")
24
+ .map((tool) => tool.trim())
25
+ .filter(Boolean);
26
+
27
+ console.log(JSON.stringify({ path, tools }, null, 2));
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { spawnSync } from "node:child_process";
4
+ import { existsSync } from "node:fs";
5
+ import { dirname, join, resolve } from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
9
+
10
+ const skip = (reason) => {
11
+ process.stdout.write(`LitClaude postinstall skipped: ${reason}\n`);
12
+ process.stdout.write("Run `litclaude install` to register the Claude Code plugin and HUD.\n");
13
+ process.exit(0);
14
+ };
15
+
16
+ if (process.env.LITCLAUDE_AUTO_INSTALL === "0" || process.env.LITCLAUDE_POSTINSTALL_SKIP === "1") {
17
+ skip("disabled by environment");
18
+ }
19
+
20
+ const forced = process.env.LITCLAUDE_AUTO_INSTALL === "1";
21
+ if (process.env.CI && !forced) {
22
+ skip("CI environment");
23
+ }
24
+
25
+ if (existsSync(join(root, ".git")) && !forced) {
26
+ skip("source checkout");
27
+ }
28
+
29
+ if (process.env.npm_config_global !== "true" && process.env.npm_config_location !== "global" && !forced) {
30
+ skip("non-global package install");
31
+ }
32
+
33
+ const result = spawnSync(process.execPath, [join(root, "bin", "litclaude-ai.js"), "install"], {
34
+ cwd: root,
35
+ encoding: "utf8",
36
+ env: {
37
+ ...process.env,
38
+ LITCLAUDE_POSTINSTALL: "1",
39
+ },
40
+ });
41
+
42
+ if (result.status === 0) {
43
+ if (result.stdout) process.stdout.write(result.stdout);
44
+ process.exit(0);
45
+ }
46
+
47
+ process.stdout.write("LitClaude postinstall warning: automatic Claude Code plugin/HUD setup did not complete.\n");
48
+ if (result.stderr) process.stdout.write(result.stderr);
49
+ process.stdout.write("Run `litclaude install` manually after npm finishes.\n");
50
+ process.exit(0);
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env bash
2
+ set -u
3
+
4
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5
+ EVIDENCE="$ROOT/evidence/task-9-claude-smoke.txt"
6
+ SESSION="litclaude-plugin-smoke-inner-$$"
7
+
8
+ mkdir -p "$ROOT/evidence"
9
+ : > "$EVIDENCE"
10
+
11
+ cleanup() {
12
+ if command -v tmux >/dev/null 2>&1; then
13
+ tmux kill-session -t "$SESSION" >/dev/null 2>&1 || true
14
+ fi
15
+ }
16
+ trap cleanup EXIT INT TERM
17
+
18
+ {
19
+ echo "LitClaude Claude Code smoke"
20
+ echo "ROOT: $ROOT"
21
+ date
22
+ } >> "$EVIDENCE"
23
+
24
+ if ! command -v claude >/dev/null 2>&1; then
25
+ {
26
+ echo "CONTROLLED_SKIP: claude executable unavailable"
27
+ echo "CLEANUP: no tmux session started"
28
+ } >> "$EVIDENCE"
29
+ echo "CONTROLLED_SKIP: claude executable unavailable"
30
+ exit 0
31
+ fi
32
+
33
+ CLAUDE_VERSION="$(claude --version 2>&1 || true)"
34
+ echo "CLAUDE_VERSION: $CLAUDE_VERSION" >> "$EVIDENCE"
35
+
36
+ if ! command -v tmux >/dev/null 2>&1; then
37
+ HELP_OUTPUT="$(claude --plugin-dir "$ROOT/plugins/litclaude" --help 2>&1 || true)"
38
+ {
39
+ echo "CONTROLLED_SKIP: tmux unavailable"
40
+ echo "$HELP_OUTPUT" | sed -n '1,40p'
41
+ echo "CLEANUP: no tmux session started"
42
+ } >> "$EVIDENCE"
43
+ echo "CONTROLLED_SKIP: tmux unavailable"
44
+ exit 0
45
+ fi
46
+
47
+ tmux new-session -d -s "$SESSION" "cd '$ROOT' && claude --plugin-dir ./plugins/litclaude --help; printf '\nINNER_STATUS:%s\n' \"\$?\"; sleep 5"
48
+ sleep 1
49
+ tmux capture-pane -pt "$SESSION" -S -200 >> "$EVIDENCE" 2>&1 || true
50
+ tmux kill-session -t "$SESSION" >/dev/null 2>&1 || true
51
+
52
+ if rg -q "INNER_STATUS:0|Usage|Claude Code" "$EVIDENCE"; then
53
+ echo "SMOKE_PASS: claude --plugin-dir accepted local LitClaude plugin path" >> "$EVIDENCE"
54
+ echo "CLEANUP: $SESSION killed" >> "$EVIDENCE"
55
+ echo "SMOKE_PASS: claude --plugin-dir accepted local LitClaude plugin path"
56
+ else
57
+ echo "CONTROLLED_SKIP: claude help did not expose a stable plugin-dir smoke result" >> "$EVIDENCE"
58
+ echo "CLEANUP: $SESSION killed" >> "$EVIDENCE"
59
+ echo "CONTROLLED_SKIP: claude help did not expose a stable plugin-dir smoke result"
60
+ fi
@@ -0,0 +1,136 @@
1
+ #!/usr/bin/env bash
2
+ set -u
3
+
4
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5
+ EVIDENCE="$ROOT/evidence/portable-qa-install.txt"
6
+ TMP_HOME=""
7
+ TMP_CLAUDE_HOME=""
8
+
9
+ mkdir -p "$ROOT/evidence"
10
+ : > "$EVIDENCE"
11
+
12
+ cleanup() {
13
+ if [ -n "$TMP_HOME" ]; then
14
+ rm -rf "$TMP_HOME"
15
+ fi
16
+ if [ -n "$TMP_CLAUDE_HOME" ]; then
17
+ rm -rf "$TMP_CLAUDE_HOME"
18
+ fi
19
+ }
20
+ trap cleanup EXIT INT TERM
21
+
22
+ {
23
+ echo "LitClaude portable install QA"
24
+ echo "ROOT: $ROOT"
25
+ date
26
+ } >> "$EVIDENCE"
27
+
28
+ TMP_HOME="$(mktemp -d "${TMPDIR:-/tmp/}litclaude-portable-qa.XXXXXX")"
29
+ TMP_CLAUDE_HOME="$(mktemp -d "${TMPDIR:-/tmp/}litclaude-claude-qa.XXXXXX")"
30
+ export LITCLAUDE_HOME="$TMP_HOME"
31
+ export CLAUDE_CONFIG_DIR="$TMP_CLAUDE_HOME"
32
+
33
+ run_step() {
34
+ local label="$1"
35
+ shift
36
+ local status
37
+ {
38
+ echo
39
+ echo "## $label"
40
+ "$@"
41
+ status="$?"
42
+ echo "STATUS:$status"
43
+ } >> "$EVIDENCE" 2>&1
44
+ if [ "$status" != "0" ]; then
45
+ echo "${label}_FAIL"
46
+ exit "$status"
47
+ fi
48
+ }
49
+
50
+ run_step INSTALL node "$ROOT/bin/litclaude-ai.js" install
51
+
52
+ PLUGIN_PATH="$(node "$ROOT/bin/litclaude-ai.js" path)"
53
+ {
54
+ echo
55
+ echo "## PATH"
56
+ echo "$PLUGIN_PATH"
57
+ } >> "$EVIDENCE"
58
+
59
+ if [ ! -f "$PLUGIN_PATH/.claude-plugin/plugin.json" ]; then
60
+ echo "INSTALL_FAIL: plugin manifest missing" >> "$EVIDENCE"
61
+ echo "INSTALL_FAIL"
62
+ exit 1
63
+ fi
64
+ for runtime_file in \
65
+ "$PLUGIN_PATH/lib/litgoal/paths.mjs" \
66
+ "$PLUGIN_PATH/lib/litgoal/state.mjs" \
67
+ "$PLUGIN_PATH/lib/litgoal/ledger.mjs" \
68
+ "$PLUGIN_PATH/lib/litgoal/cli.mjs"
69
+ do
70
+ if [ ! -f "$runtime_file" ]; then
71
+ echo "INSTALL_FAIL: litgoal runtime missing: $runtime_file" >> "$EVIDENCE"
72
+ echo "INSTALL_FAIL"
73
+ exit 1
74
+ fi
75
+ done
76
+ echo "LITGOAL_RUNTIME_PASS" >> "$EVIDENCE"
77
+ if [ ! -f "$TMP_CLAUDE_HOME/plugins/installed_plugins.json" ]; then
78
+ echo "INSTALL_FAIL: Claude plugin registry missing" >> "$EVIDENCE"
79
+ echo "INSTALL_FAIL"
80
+ exit 1
81
+ fi
82
+ if [ ! -f "$TMP_CLAUDE_HOME/settings.json" ]; then
83
+ echo "INSTALL_FAIL: Claude settings missing" >> "$EVIDENCE"
84
+ echo "INSTALL_FAIL"
85
+ exit 1
86
+ fi
87
+ if [ ! -f "$TMP_CLAUDE_HOME/plugins/known_marketplaces.json" ]; then
88
+ echo "INSTALL_FAIL: Claude known marketplaces missing" >> "$EVIDENCE"
89
+ echo "INSTALL_FAIL"
90
+ exit 1
91
+ fi
92
+ if [ ! -f "$TMP_HOME/marketplaces/litclaude-ai/.claude-plugin/marketplace.json" ]; then
93
+ echo "INSTALL_FAIL: LitClaude local marketplace missing" >> "$EVIDENCE"
94
+ echo "INSTALL_FAIL"
95
+ exit 1
96
+ fi
97
+ node -e 'const fs = require("fs"); const p = process.argv[1]; const registry = JSON.parse(fs.readFileSync(`${p}/plugins/installed_plugins.json`, "utf8")); const entry = registry.plugins["litclaude@litclaude-ai"]?.[0]; if (!entry || entry.scope !== "user" || !entry.installPath.includes("/plugins/cache/litclaude-ai/litclaude/")) process.exit(1);' "$TMP_CLAUDE_HOME"
98
+ node -e 'const fs = require("fs"); const p = process.argv[1]; const h = process.argv[2]; const settings = JSON.parse(fs.readFileSync(`${p}/settings.json`, "utf8")); const market = settings.extraKnownMarketplaces?.["litclaude-ai"]; if (settings.enabledPlugins?.["litclaude@litclaude-ai"] !== true || market?.source?.source !== "directory" || market.source.path !== `${h}/marketplaces/litclaude-ai`) process.exit(1);' "$TMP_CLAUDE_HOME" "$TMP_HOME"
99
+ node -e 'const fs = require("fs"); const p = process.argv[1]; const h = process.argv[2]; const known = JSON.parse(fs.readFileSync(`${p}/plugins/known_marketplaces.json`, "utf8")); const market = known["litclaude-ai"]; if (market?.source?.source !== "directory" || market.installLocation !== `${h}/marketplaces/litclaude-ai`) process.exit(1);' "$TMP_CLAUDE_HOME" "$TMP_HOME"
100
+ echo "INSTALL_PASS" >> "$EVIDENCE"
101
+
102
+ run_step DOCTOR node "$ROOT/bin/litclaude-ai.js" doctor
103
+ echo "DOCTOR_PASS" >> "$EVIDENCE"
104
+
105
+ if command -v claude >/dev/null 2>&1; then
106
+ run_step CLAUDE_PLUGIN_DETAILS claude plugin details litclaude@litclaude-ai
107
+ if ! grep -Eq "Skills \\([0-9]+\\)" "$EVIDENCE" || ! grep -q "lit-loop" "$EVIDENCE" || ! grep -q "lit-plan" "$EVIDENCE" || ! grep -q "Hooks (4)" "$EVIDENCE"; then
108
+ echo "CLAUDE_PLUGIN_DETAILS_FAIL: expected LitClaude skills/hooks inventory" >> "$EVIDENCE"
109
+ echo "CLAUDE_PLUGIN_DETAILS_FAIL"
110
+ exit 1
111
+ fi
112
+ else
113
+ echo "CLAUDE_PLUGIN_DETAILS_SKIP: claude executable not found" >> "$EVIDENCE"
114
+ fi
115
+
116
+ run_step DRY_RUN_UNINSTALL node "$ROOT/bin/litclaude-ai.js" --dry-run uninstall
117
+ if [ ! -d "$PLUGIN_PATH" ]; then
118
+ echo "DRY_RUN_UNINSTALL_FAIL: plugin removed during dry-run" >> "$EVIDENCE"
119
+ exit 1
120
+ fi
121
+
122
+ run_step UNINSTALL node "$ROOT/bin/litclaude-ai.js" uninstall
123
+ if [ -e "$TMP_HOME/current" ] || [ -e "$TMP_HOME/litclaude-ai" ] || [ -e "$TMP_CLAUDE_HOME/plugins/cache/litclaude-ai" ]; then
124
+ echo "UNINSTALL_FAIL: managed state remains" >> "$EVIDENCE"
125
+ echo "UNINSTALL_FAIL"
126
+ exit 1
127
+ fi
128
+ node -e 'const fs = require("fs"); const p = process.argv[1]; const settings = JSON.parse(fs.readFileSync(`${p}/settings.json`, "utf8")); if (settings.enabledPlugins?.["litclaude@litclaude-ai"] !== undefined) process.exit(1);' "$TMP_CLAUDE_HOME"
129
+ node -e 'const fs = require("fs"); const p = process.argv[1]; const settings = JSON.parse(fs.readFileSync(`${p}/settings.json`, "utf8")); const known = JSON.parse(fs.readFileSync(`${p}/plugins/known_marketplaces.json`, "utf8")); if (settings.extraKnownMarketplaces?.["litclaude-ai"] !== undefined || known["litclaude-ai"] !== undefined) process.exit(1);' "$TMP_CLAUDE_HOME"
130
+ echo "UNINSTALL_PASS" >> "$EVIDENCE"
131
+
132
+ cleanup
133
+ TMP_HOME=""
134
+ TMP_CLAUDE_HOME=""
135
+ echo "CLEANUP: removed portable QA temp home" >> "$EVIDENCE"
136
+ echo "PORTABLE_QA_PASS"
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env node
2
+ import assert from "node:assert/strict";
3
+ import { access, readdir, readFile } from "node:fs/promises";
4
+ import { constants } from "node:fs";
5
+ import { join, resolve } from "node:path";
6
+ import { spawnSync } from "node:child_process";
7
+ import { fileURLToPath } from "node:url";
8
+
9
+ const root = resolve(fileURLToPath(new URL("..", import.meta.url)));
10
+ const pluginRoot = join(root, "plugins", "litclaude");
11
+
12
+ async function readJson(path) {
13
+ return JSON.parse(await readFile(path, "utf8"));
14
+ }
15
+
16
+ async function exists(path) {
17
+ await access(path, constants.R_OK);
18
+ }
19
+
20
+ async function main() {
21
+ const manifest = await readJson(join(pluginRoot, ".claude-plugin", "plugin.json"));
22
+ assert.equal(manifest.name, "litclaude");
23
+ assert.equal(manifest.skills, "./skills");
24
+ assert.deepEqual(manifest.agents, [
25
+ "./agents/boulder-executor.md",
26
+ "./agents/librarian-researcher.md",
27
+ "./agents/oracle-verifier.md",
28
+ "./agents/prometheus-planner.md",
29
+ "./agents/qa-runner.md",
30
+ "./agents/quality-reviewer.md",
31
+ ]);
32
+ assert.equal("hooks" in manifest, false);
33
+ assert.equal(manifest.mcpServers, "./.mcp.json");
34
+ assert.equal(manifest.lspServers, "./.lsp.json");
35
+
36
+ await exists(join(pluginRoot, ".mcp.json"));
37
+ await exists(join(pluginRoot, ".lsp.json"));
38
+ await exists(join(pluginRoot, "bin", "litclaude-hook.js"));
39
+ await exists(join(pluginRoot, "bin", "litclaude-lsp-doctor.js"));
40
+ await exists(join(pluginRoot, "bin", "litclaude-mcp.js"));
41
+
42
+ const hooks = await readJson(join(pluginRoot, "hooks", "hooks.json"));
43
+ for (const event of ["SessionStart", "UserPromptSubmit", "PostToolUse", "PostCompact"]) {
44
+ assert.ok(hooks.hooks[event], `missing hook event ${event}`);
45
+ }
46
+
47
+ const skills = await readdir(join(pluginRoot, "skills"));
48
+ const agents = await readdir(join(pluginRoot, "agents"));
49
+ assert.ok(skills.length >= 7, "expected at least seven skills");
50
+ assert.ok(agents.length >= 6, "expected at least six agents");
51
+
52
+ const claude = spawnSync("claude", ["--version"], { encoding: "utf8" });
53
+ if (claude.status === 0) {
54
+ process.stdout.write(`CLAUDE_VERSION: ${claude.stdout.trim() || claude.stderr.trim()}\n`);
55
+ const validation = spawnSync("claude", ["plugin", "validate", "./plugins/litclaude"], {
56
+ cwd: root,
57
+ encoding: "utf8",
58
+ });
59
+ if (validation.stdout) process.stdout.write(validation.stdout);
60
+ if (validation.stderr) process.stdout.write(validation.stderr);
61
+ assert.equal(validation.status, 0, "claude plugin validate must pass");
62
+ } else {
63
+ process.stdout.write("CONTROLLED_SKIP: claude executable unavailable for version probe\n");
64
+ }
65
+
66
+ process.stdout.write("VALIDATE_PLUGIN_PASS\n");
67
+ }
68
+
69
+ main().catch((error) => {
70
+ process.stderr.write(`VALIDATE_PLUGIN_FAIL: ${error.message}\n`);
71
+ process.exit(1);
72
+ });