lazyclaude-ai 0.1.0

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 (36) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +176 -0
  3. package/REFERENCE.md +21 -0
  4. package/RELEASE_CHECKLIST.md +86 -0
  5. package/bin/lazyclaude-ai.js +215 -0
  6. package/docs/agents.md +31 -0
  7. package/docs/hooks.md +60 -0
  8. package/docs/lsp.md +35 -0
  9. package/docs/migration.md +57 -0
  10. package/package.json +36 -0
  11. package/plugins/lazyclaude/.claude-plugin/plugin.json +25 -0
  12. package/plugins/lazyclaude/.lsp.json +13 -0
  13. package/plugins/lazyclaude/.mcp.json +9 -0
  14. package/plugins/lazyclaude/agents/boulder-executor.md +12 -0
  15. package/plugins/lazyclaude/agents/librarian-researcher.md +11 -0
  16. package/plugins/lazyclaude/agents/oracle-verifier.md +12 -0
  17. package/plugins/lazyclaude/agents/prometheus-planner.md +13 -0
  18. package/plugins/lazyclaude/agents/qa-runner.md +12 -0
  19. package/plugins/lazyclaude/agents/quality-reviewer.md +12 -0
  20. package/plugins/lazyclaude/bin/lazyclaude-hook.js +67 -0
  21. package/plugins/lazyclaude/bin/lazyclaude-lsp-doctor.js +15 -0
  22. package/plugins/lazyclaude/bin/lazyclaude-mcp.js +70 -0
  23. package/plugins/lazyclaude/hooks/hooks.json +54 -0
  24. package/plugins/lazyclaude/skills/lsp/SKILL.md +13 -0
  25. package/plugins/lazyclaude/skills/programming/SKILL.md +14 -0
  26. package/plugins/lazyclaude/skills/review-work/SKILL.md +13 -0
  27. package/plugins/lazyclaude/skills/rules/SKILL.md +13 -0
  28. package/plugins/lazyclaude/skills/start-work/SKILL.md +19 -0
  29. package/plugins/lazyclaude/skills/ulw-loop/SKILL.md +14 -0
  30. package/plugins/lazyclaude/skills/ulw-plan/SKILL.md +18 -0
  31. package/scripts/audit-plan-checkboxes.mjs +36 -0
  32. package/scripts/doctor.mjs +27 -0
  33. package/scripts/inspect-agent-tools.mjs +27 -0
  34. package/scripts/qa-claude-plugin-smoke.sh +60 -0
  35. package/scripts/qa-portable-install.sh +80 -0
  36. package/scripts/validate-plugin.mjs +71 -0
@@ -0,0 +1,57 @@
1
+ # LazyClaude Migration
2
+
3
+ LazyClaude ports the pinned LazyCodex reference into Claude Code-native
4
+ surfaces. The goal is behavior parity where Claude Code exposes the same kind
5
+ of surface, and a conservative local fallback where it does not.
6
+
7
+ | Codex surface | Claude Code surface | LazyClaude implementation |
8
+ | --- | --- | --- |
9
+ | Codex CLI prompt engineering | Claude Code skills | `plugins/lazyclaude/skills/*/SKILL.md` |
10
+ | Codex ultrawork plan mode | Claude Code skill plus planner agent | `ulw-plan` and `prometheus-planner` |
11
+ | Codex execution loop | Claude Code skill plus executor agent | `ulw-loop`, `start-work`, and `boulder-executor` |
12
+ | Codex hooks | Claude Code hooks | `plugins/lazyclaude/hooks/hooks.json` |
13
+ | Codex MCP helpers | Claude Code plugin MCP config | `plugins/lazyclaude/.mcp.json` |
14
+ | Codex LSP integration | Claude Code plugin LSP config | `plugins/lazyclaude/.lsp.json` |
15
+ | Codex package alias | npm package bin alias | `lazyclaude-ai` |
16
+ | Codex review/research agents | Claude Code agents | `quality-reviewer`, `oracle-verifier`, `librarian-researcher` |
17
+
18
+ ## Local Plugin Flow
19
+
20
+ Use the local plugin path while developing from this checkout:
21
+
22
+ ```bash
23
+ claude --plugin-dir ./plugins/lazyclaude
24
+ ```
25
+
26
+ For fresh machines, the quiet npm distribution path is:
27
+
28
+ ```bash
29
+ npx lazyclaude-ai install
30
+ bunx lazyclaude-ai install
31
+ lazyclaude doctor
32
+ lazyclaude run
33
+ ```
34
+
35
+ This keeps installation convenient without requiring public repo promotion or a
36
+ Claude marketplace entry.
37
+
38
+ If OMC/omc is already installed in Claude Code, keep it disabled or start a
39
+ separate Claude Code session without OMC while testing LazyClaude. This repo no
40
+ longer ships a root marketplace skeleton; direct `--plugin-dir` loading avoids
41
+ local marketplace collision. If a user-level OMC plugin still runs, it may
42
+ create `.omc/` local state in the checkout; LazyClaude treats that as quarantined
43
+ external state and keeps it ignored and outside packaged artifacts.
44
+
45
+ Reload plugin metadata after changing skills, agents, hooks, MCP, or LSP:
46
+
47
+ ```text
48
+ /reload-plugins
49
+ ```
50
+
51
+ ## Publication Boundary
52
+
53
+ LazyClaude may be prepared as a quiet public npm package for personal install
54
+ convenience, but any `npm publish`, marketplace registration, or remote
55
+ distribution step requires explicit user approval. Until that approval exists,
56
+ uninstalling is either `lazyclaude uninstall` for npm-installed copies or
57
+ removing the local `--plugin-dir` usage and reloading Claude Code.
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "lazyclaude-ai",
3
+ "version": "0.1.0",
4
+ "description": "Claude Code-native LazyCodex-style workflow distribution.",
5
+ "type": "module",
6
+ "bin": {
7
+ "lazyclaude-ai": "bin/lazyclaude-ai.js",
8
+ "lazyclaude": "bin/lazyclaude-ai.js"
9
+ },
10
+ "files": [
11
+ "bin",
12
+ "docs",
13
+ "plugins",
14
+ "scripts",
15
+ "README.md",
16
+ "REFERENCE.md",
17
+ "RELEASE_CHECKLIST.md",
18
+ "LICENSE"
19
+ ],
20
+ "scripts": {
21
+ "test": "node --test test/*.test.mjs",
22
+ "validate:plugin": "node scripts/validate-plugin.mjs",
23
+ "doctor": "node scripts/doctor.mjs",
24
+ "qa:tmux": "bash scripts/qa-claude-plugin-smoke.sh",
25
+ "qa:portable": "bash scripts/qa-portable-install.sh",
26
+ "pack:dry-run": "npm pack --dry-run"
27
+ },
28
+ "keywords": [
29
+ "claude-code",
30
+ "plugin",
31
+ "ai-agents",
32
+ "orchestration"
33
+ ],
34
+ "author": "LazyClaude contributors",
35
+ "license": "MIT"
36
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "lazyclaude",
3
+ "description": "Claude Code-native LazyCodex-style workflow plugin.",
4
+ "version": "0.1.0",
5
+ "author": {
6
+ "name": "LazyClaude contributors"
7
+ },
8
+ "homepage": "https://github.com/code-yeongyu/lazycodex",
9
+ "repository": "https://github.com/code-yeongyu/lazycodex",
10
+ "license": "MIT",
11
+ "keywords": ["claude-code", "hooks", "skills", "agents", "lsp", "workflow"],
12
+ "skills": "./skills",
13
+ "agents": [
14
+ "./agents/boulder-executor.md",
15
+ "./agents/librarian-researcher.md",
16
+ "./agents/oracle-verifier.md",
17
+ "./agents/prometheus-planner.md",
18
+ "./agents/qa-runner.md",
19
+ "./agents/quality-reviewer.md"
20
+ ],
21
+ "mcpServers": "./.mcp.json",
22
+ "lspServers": "./.lsp.json",
23
+ "displayName": "LazyClaude",
24
+ "defaultEnabled": true
25
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "typescript": {
3
+ "command": ["typescript-language-server", "--stdio"],
4
+ "extensionToLanguage": {
5
+ ".ts": "typescript",
6
+ ".tsx": "typescriptreact",
7
+ ".js": "javascript",
8
+ ".jsx": "javascriptreact",
9
+ ".mjs": "javascript",
10
+ ".cjs": "javascript"
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "mcpServers": {
3
+ "lazyclaude": {
4
+ "type": "stdio",
5
+ "command": "node",
6
+ "args": ["${CLAUDE_PLUGIN_ROOT}/bin/lazyclaude-mcp.js"]
7
+ }
8
+ }
9
+ }
@@ -0,0 +1,12 @@
1
+ ---
2
+ name: boulder-executor
3
+ description: Executes one checked plan task at a time with tests and evidence.
4
+ tools: Read, Grep, Glob, Bash, Write, Edit, MultiEdit
5
+ permissionMode: acceptEdits
6
+ skills:
7
+ - start-work
8
+ - programming
9
+ ---
10
+
11
+ Execute only the assigned plan checkbox. Write the failing test first, make the
12
+ smallest change, run verification, capture evidence, and report cleanup.
@@ -0,0 +1,11 @@
1
+ ---
2
+ name: librarian-researcher
3
+ description: Researches official docs and pinned source references.
4
+ tools: Read, Grep, Glob, WebFetch, WebSearch
5
+ permissionMode: plan
6
+ skills:
7
+ - rules
8
+ ---
9
+
10
+ Prefer official documentation and pinned source links. Return concise findings
11
+ with exact files, URLs, and version details.
@@ -0,0 +1,12 @@
1
+ ---
2
+ name: oracle-verifier
3
+ description: Verifies implementation against objective, evidence, and guardrails.
4
+ tools: Read, Grep, Glob, Bash
5
+ permissionMode: default
6
+ skills:
7
+ - review-work
8
+ - rules
9
+ ---
10
+
11
+ Review claims against files, commands, and artifacts. A green test suite alone
12
+ is not completion evidence.
@@ -0,0 +1,13 @@
1
+ ---
2
+ name: prometheus-planner
3
+ description: Creates decision-complete Claude Code work plans without product-code edits.
4
+ tools: Read, Grep, Glob, WebFetch, WebSearch, Agent
5
+ permissionMode: plan
6
+ skills:
7
+ - ulw-plan
8
+ - rules
9
+ ---
10
+
11
+ You are Prometheus, the planning agent. Explore first, ask only preference
12
+ questions, and write plans with concrete acceptance criteria and QA scenarios.
13
+ Do not implement product changes.
@@ -0,0 +1,12 @@
1
+ ---
2
+ name: qa-runner
3
+ description: Runs real QA scenarios and captures artifacts plus cleanup receipts.
4
+ tools: Read, Grep, Glob, Bash
5
+ permissionMode: default
6
+ skills:
7
+ - start-work
8
+ - review-work
9
+ ---
10
+
11
+ Run the requested QA channel exactly. Capture stdout, screenshots, transcripts,
12
+ or HTTP responses, then tear down every spawned process or session.
@@ -0,0 +1,12 @@
1
+ ---
2
+ name: quality-reviewer
3
+ description: Reviews changed files for defects, maintainability, and safety.
4
+ tools: Read, Grep, Glob, Bash
5
+ permissionMode: default
6
+ skills:
7
+ - review-work
8
+ - programming
9
+ ---
10
+
11
+ Lead with findings ordered by severity. Include file references, reproduction,
12
+ and concrete remediation.
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readFileSync } from "node:fs";
4
+
5
+ const eventName = process.argv[2] ?? "";
6
+
7
+ const readInput = () => {
8
+ const raw = readFileSync(0, "utf8");
9
+ try {
10
+ return JSON.parse(raw || "{}");
11
+ } catch {
12
+ console.error("invalid hook JSON");
13
+ process.exit(1);
14
+ }
15
+ };
16
+
17
+ const hookEventNames = {
18
+ "session-start": "SessionStart",
19
+ "user-prompt-submit": "UserPromptSubmit",
20
+ "post-tool-use": "PostToolUse",
21
+ "post-compact": "PostCompact",
22
+ };
23
+
24
+ const writeContext = (additionalContext) => {
25
+ console.log(
26
+ JSON.stringify({
27
+ continue: true,
28
+ hookSpecificOutput: {
29
+ hookEventName: hookEventNames[eventName],
30
+ additionalContext,
31
+ },
32
+ }),
33
+ );
34
+ };
35
+
36
+ const input = readInput();
37
+
38
+ switch (eventName) {
39
+ case "session-start": {
40
+ const cwd = typeof input.cwd === "string" ? input.cwd : "unknown workspace";
41
+ writeContext(`LazyClaude rules loaded for ${cwd}. Read CLAUDE.md, AGENTS.md, and project rule files before edits.`);
42
+ break;
43
+ }
44
+ case "user-prompt-submit": {
45
+ const prompt = typeof input.prompt === "string" ? input.prompt : "";
46
+ const activates = /\b(?:ultrawork|ulw)\b|\$(?:ulw-plan|ulw-loop|start-work)\b/u.test(prompt);
47
+ if (activates) {
48
+ writeContext("ULTRAWORK MODE ENABLED. Use evidence-bound planning, tests, manual QA, and cleanup receipts.");
49
+ } else {
50
+ writeContext("LazyClaude prompt hook checked: no workflow activation.");
51
+ }
52
+ break;
53
+ }
54
+ case "post-tool-use": {
55
+ const toolName = typeof input.tool_name === "string" ? input.tool_name : "unknown";
56
+ writeContext(`LazyClaude post-edit checks complete for ${toolName}: comments and LSP diagnostics queued.`);
57
+ break;
58
+ }
59
+ case "post-compact": {
60
+ writeContext("LazyClaude rule cache reset after compaction.");
61
+ break;
62
+ }
63
+ default: {
64
+ console.error(`unknown hook event: ${eventName || "(missing)"}`);
65
+ process.exit(64);
66
+ }
67
+ }
@@ -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: "lazyclaude", 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, "LazyClaude 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,54 @@
1
+ {
2
+ "hooks": {
3
+ "SessionStart": [
4
+ {
5
+ "hooks": [
6
+ {
7
+ "type": "command",
8
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/bin/lazyclaude-hook.js\" session-start",
9
+ "timeout": 10,
10
+ "statusMessage": "loading LazyClaude rules"
11
+ }
12
+ ]
13
+ }
14
+ ],
15
+ "UserPromptSubmit": [
16
+ {
17
+ "hooks": [
18
+ {
19
+ "type": "command",
20
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/bin/lazyclaude-hook.js\" user-prompt-submit",
21
+ "timeout": 5,
22
+ "statusMessage": "checking LazyClaude 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/lazyclaude-hook.js\" post-tool-use",
34
+ "timeout": 30,
35
+ "statusMessage": "running LazyClaude 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/lazyclaude-hook.js\" post-compact",
47
+ "timeout": 10,
48
+ "statusMessage": "resetting LazyClaude rule cache"
49
+ }
50
+ ]
51
+ }
52
+ ]
53
+ }
54
+ }
@@ -0,0 +1,13 @@
1
+ ---
2
+ name: lsp
3
+ description: Use Claude Code language-server diagnostics, symbols, definitions, and references.
4
+ ---
5
+
6
+ # LSP
7
+
8
+ LazyClaude configures plugin-local language server settings through `.lsp.json`.
9
+ The MVP enables TypeScript and JavaScript with `typescript-language-server`.
10
+
11
+ Use diagnostics after edits and report missing language-server binaries as
12
+ actionable setup warnings unless the current task explicitly requires blocking
13
+ on diagnostics.
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: programming
3
+ description: Strict programming discipline for Claude Code implementation work.
4
+ ---
5
+
6
+ # Programming
7
+
8
+ Use TDD for production changes: red, green, refactor. Prefer small files,
9
+ typed boundaries, explicit errors, and parse-once input handling. Do not
10
+ silence type or lint failures. When existing project conventions are present,
11
+ follow them over introducing a new stack.
12
+
13
+ For JavaScript utilities in this plugin, keep modules ESM, deterministic, and
14
+ covered by Node test runner tests.
@@ -0,0 +1,13 @@
1
+ ---
2
+ name: review-work
3
+ description: Post-implementation review workflow for LazyClaude changes.
4
+ ---
5
+
6
+ # Review Work
7
+
8
+ Review against the original objective, plan constraints, changed files,
9
+ security posture, and real QA evidence. Findings lead the response and must
10
+ include file references, severity, reproduction, and suggested fix.
11
+
12
+ Approval requires green automated checks, a manual QA artifact, and cleanup
13
+ receipts for any spawned resources.
@@ -0,0 +1,13 @@
1
+ ---
2
+ name: rules
3
+ description: Explain or operate LazyClaude project-rule loading in Claude Code sessions.
4
+ ---
5
+
6
+ # Rules
7
+
8
+ LazyClaude rule loading reads repository guidance such as `CLAUDE.md`,
9
+ `AGENTS.md`, `.claude/rules/**/*.md`, `.github/instructions/**/*.md`, and
10
+ project-specific context files.
11
+
12
+ Rules are injected as context on session start and prompt submission. Dynamic
13
+ post-edit feedback is limited to files touched by the last edit-like tool.
@@ -0,0 +1,19 @@
1
+ ---
2
+ name: start-work
3
+ description: Execute a plan file in Claude Code with Boulder state, evidence ledger updates, and checkbox progress.
4
+ ---
5
+
6
+ # Start Work
7
+
8
+ Read the selected plan, create or resume `.omo/boulder.json`, and complete the
9
+ first unchecked top-level checkbox. For every checkbox:
10
+
11
+ 1. Re-read the task and acceptance criteria.
12
+ 2. Write a failing test or reproduction first.
13
+ 3. Make the smallest implementation change.
14
+ 4. Run automated verification.
15
+ 5. Run the named manual QA scenario.
16
+ 6. Tear down runtime resources and record cleanup.
17
+ 7. Mark the checkbox complete only after all evidence is captured.
18
+
19
+ The durable ledger is `.omo/start-work/ledger.jsonl`.
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: ulw-loop
3
+ description: Evidence-bound execution loop for Claude Code tasks that must continue until verified completion.
4
+ ---
5
+
6
+ # ULW Loop
7
+
8
+ Convert the user's objective into explicit success criteria before editing.
9
+ For each criterion, capture both automated verification and a real manual QA
10
+ artifact through an appropriate channel such as tmux, HTTP, browser, or desktop
11
+ automation.
12
+
13
+ Keep a ledger of decisions, evidence, cleanup receipts, and remaining work.
14
+ Never claim completion from tests alone.
@@ -0,0 +1,18 @@
1
+ ---
2
+ name: ulw-plan
3
+ description: Strategic planner for Claude Code work. Use when the user asks for a plan, architecture breakdown, or decision-complete execution guide.
4
+ ---
5
+
6
+ # ULW Plan
7
+
8
+ You are a planner, not an implementer. Explore the workspace first, resolve
9
+ discoverable facts from files and docs, then produce one plan under `plans/`.
10
+
11
+ Use Claude Code surfaces directly:
12
+
13
+ - read/search files for grounding
14
+ - use subagents only for read-only research or plan review
15
+ - write only plan artifacts and drafts
16
+ - include concrete tests, manual QA, cleanup, and non-publish guardrails
17
+
18
+ When `$ARGUMENTS` is present, treat it as the planning brief.
@@ -0,0 +1,36 @@
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.length >= 14, "expected task and final verification checkboxes");
17
+
18
+ for (let index = 0; index < tasks.length; index += 1) {
19
+ const start = tasks[index].index;
20
+ const end = tasks[index + 1]?.index ?? text.length;
21
+ const block = text.slice(start, end);
22
+ const title = tasks[index][0];
23
+
24
+ if (/^- \[[ x]\] F\d\./.test(title)) {
25
+ assert.match(block, /Command:/, `${title} missing command`);
26
+ assert.match(block, /Expected:/, `${title} missing expected result`);
27
+ } else {
28
+ assert.match(title, /^- \[x\]/, `${title} is not complete`);
29
+ assert.match(block, /\*\*References\*\*:/, `${title} missing references`);
30
+ assert.match(block, /\*\*Acceptance Criteria\*\*:/, `${title} missing acceptance criteria`);
31
+ assert.match(block, /\*\*QA Scenarios\*\*:/, `${title} missing QA scenarios`);
32
+ assert.match(block, /\*\*Commit\*\*:/, `${title} missing commit metadata`);
33
+ }
34
+ }
35
+
36
+ process.stdout.write(`PLAN_AUDIT_PASS: ${tasks.length} checked items complete\n`);
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+ import { spawnSync } from "node:child_process";
3
+ import { resolve } from "node:path";
4
+
5
+ const root = resolve(new URL("..", import.meta.url).pathname);
6
+
7
+ function run(label, command, args) {
8
+ const result = spawnSync(command, args, {
9
+ cwd: root,
10
+ encoding: "utf8",
11
+ });
12
+
13
+ process.stdout.write(`\n## ${label}\n`);
14
+ if (result.stdout) process.stdout.write(result.stdout);
15
+ if (result.stderr) process.stdout.write(result.stderr);
16
+
17
+ if (result.status !== 0) {
18
+ process.stderr.write(`${label} failed with status ${result.status}\n`);
19
+ process.exit(result.status ?? 1);
20
+ }
21
+ }
22
+
23
+ run("CLI dry-run", process.execPath, ["bin/lazyclaude-ai.js", "--dry-run", "doctor"]);
24
+ run("Plugin validation", process.execPath, ["scripts/validate-plugin.mjs"]);
25
+ run("LSP doctor", process.execPath, ["plugins/lazyclaude/bin/lazyclaude-lsp-doctor.js"]);
26
+
27
+ 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));