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,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="lazyclaude-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 "LazyClaude 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/lazyclaude" --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/lazyclaude --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 LazyClaude plugin path" >> "$EVIDENCE"
54
+ echo "CLEANUP: $SESSION killed" >> "$EVIDENCE"
55
+ echo "SMOKE_PASS: claude --plugin-dir accepted local LazyClaude 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,80 @@
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
+
8
+ mkdir -p "$ROOT/evidence"
9
+ : > "$EVIDENCE"
10
+
11
+ cleanup() {
12
+ if [ -n "$TMP_HOME" ]; then
13
+ rm -rf "$TMP_HOME"
14
+ fi
15
+ }
16
+ trap cleanup EXIT INT TERM
17
+
18
+ {
19
+ echo "LazyClaude portable install QA"
20
+ echo "ROOT: $ROOT"
21
+ date
22
+ } >> "$EVIDENCE"
23
+
24
+ TMP_HOME="$(mktemp -d "${TMPDIR:-/tmp/}lazyclaude-portable-qa.XXXXXX")"
25
+ export LAZYCLAUDE_HOME="$TMP_HOME"
26
+
27
+ run_step() {
28
+ local label="$1"
29
+ shift
30
+ {
31
+ echo
32
+ echo "## $label"
33
+ "$@"
34
+ echo "STATUS:$?"
35
+ } >> "$EVIDENCE" 2>&1
36
+ local status
37
+ status="$(tail -n 1 "$EVIDENCE" | sed 's/^STATUS://')"
38
+ if [ "$status" != "0" ]; then
39
+ echo "${label}_FAIL"
40
+ exit "$status"
41
+ fi
42
+ }
43
+
44
+ run_step INSTALL node "$ROOT/bin/lazyclaude-ai.js" install
45
+
46
+ PLUGIN_PATH="$(node "$ROOT/bin/lazyclaude-ai.js" path)"
47
+ {
48
+ echo
49
+ echo "## PATH"
50
+ echo "$PLUGIN_PATH"
51
+ } >> "$EVIDENCE"
52
+
53
+ if [ ! -f "$PLUGIN_PATH/.claude-plugin/plugin.json" ]; then
54
+ echo "INSTALL_FAIL: plugin manifest missing" >> "$EVIDENCE"
55
+ echo "INSTALL_FAIL"
56
+ exit 1
57
+ fi
58
+ echo "INSTALL_PASS" >> "$EVIDENCE"
59
+
60
+ run_step DOCTOR node "$ROOT/bin/lazyclaude-ai.js" doctor
61
+ echo "DOCTOR_PASS" >> "$EVIDENCE"
62
+
63
+ run_step DRY_RUN_UNINSTALL node "$ROOT/bin/lazyclaude-ai.js" --dry-run uninstall
64
+ if [ ! -d "$PLUGIN_PATH" ]; then
65
+ echo "DRY_RUN_UNINSTALL_FAIL: plugin removed during dry-run" >> "$EVIDENCE"
66
+ exit 1
67
+ fi
68
+
69
+ run_step UNINSTALL node "$ROOT/bin/lazyclaude-ai.js" uninstall
70
+ if [ -e "$TMP_HOME/current" ] || [ -e "$TMP_HOME/lazyclaude-ai" ]; then
71
+ echo "UNINSTALL_FAIL: managed state remains" >> "$EVIDENCE"
72
+ echo "UNINSTALL_FAIL"
73
+ exit 1
74
+ fi
75
+ echo "UNINSTALL_PASS" >> "$EVIDENCE"
76
+
77
+ cleanup
78
+ TMP_HOME=""
79
+ echo "CLEANUP: removed portable QA temp home" >> "$EVIDENCE"
80
+ echo "PORTABLE_QA_PASS"
@@ -0,0 +1,71 @@
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
+
8
+ const root = resolve(new URL("..", import.meta.url).pathname);
9
+ const pluginRoot = join(root, "plugins", "lazyclaude");
10
+
11
+ async function readJson(path) {
12
+ return JSON.parse(await readFile(path, "utf8"));
13
+ }
14
+
15
+ async function exists(path) {
16
+ await access(path, constants.R_OK);
17
+ }
18
+
19
+ async function main() {
20
+ const manifest = await readJson(join(pluginRoot, ".claude-plugin", "plugin.json"));
21
+ assert.equal(manifest.name, "lazyclaude");
22
+ assert.equal(manifest.skills, "./skills");
23
+ assert.deepEqual(manifest.agents, [
24
+ "./agents/boulder-executor.md",
25
+ "./agents/librarian-researcher.md",
26
+ "./agents/oracle-verifier.md",
27
+ "./agents/prometheus-planner.md",
28
+ "./agents/qa-runner.md",
29
+ "./agents/quality-reviewer.md",
30
+ ]);
31
+ assert.equal("hooks" in manifest, false);
32
+ assert.equal(manifest.mcpServers, "./.mcp.json");
33
+ assert.equal(manifest.lspServers, "./.lsp.json");
34
+
35
+ await exists(join(pluginRoot, ".mcp.json"));
36
+ await exists(join(pluginRoot, ".lsp.json"));
37
+ await exists(join(pluginRoot, "bin", "lazyclaude-hook.js"));
38
+ await exists(join(pluginRoot, "bin", "lazyclaude-lsp-doctor.js"));
39
+ await exists(join(pluginRoot, "bin", "lazyclaude-mcp.js"));
40
+
41
+ const hooks = await readJson(join(pluginRoot, "hooks", "hooks.json"));
42
+ for (const event of ["SessionStart", "UserPromptSubmit", "PostToolUse", "PostCompact"]) {
43
+ assert.ok(hooks.hooks[event], `missing hook event ${event}`);
44
+ }
45
+
46
+ const skills = await readdir(join(pluginRoot, "skills"));
47
+ const agents = await readdir(join(pluginRoot, "agents"));
48
+ assert.ok(skills.length >= 7, "expected at least seven skills");
49
+ assert.ok(agents.length >= 6, "expected at least six agents");
50
+
51
+ const claude = spawnSync("claude", ["--version"], { encoding: "utf8" });
52
+ if (claude.status === 0) {
53
+ process.stdout.write(`CLAUDE_VERSION: ${claude.stdout.trim() || claude.stderr.trim()}\n`);
54
+ const validation = spawnSync("claude", ["plugin", "validate", "./plugins/lazyclaude"], {
55
+ cwd: root,
56
+ encoding: "utf8",
57
+ });
58
+ if (validation.stdout) process.stdout.write(validation.stdout);
59
+ if (validation.stderr) process.stdout.write(validation.stderr);
60
+ assert.equal(validation.status, 0, "claude plugin validate must pass");
61
+ } else {
62
+ process.stdout.write("CONTROLLED_SKIP: claude executable unavailable for version probe\n");
63
+ }
64
+
65
+ process.stdout.write("VALIDATE_PLUGIN_PASS\n");
66
+ }
67
+
68
+ main().catch((error) => {
69
+ process.stderr.write(`VALIDATE_PLUGIN_FAIL: ${error.message}\n`);
70
+ process.exit(1);
71
+ });