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.
- package/LICENSE +21 -0
- package/README.md +176 -0
- package/REFERENCE.md +21 -0
- package/RELEASE_CHECKLIST.md +86 -0
- package/bin/lazyclaude-ai.js +215 -0
- package/docs/agents.md +31 -0
- package/docs/hooks.md +60 -0
- package/docs/lsp.md +35 -0
- package/docs/migration.md +57 -0
- package/package.json +36 -0
- package/plugins/lazyclaude/.claude-plugin/plugin.json +25 -0
- package/plugins/lazyclaude/.lsp.json +13 -0
- package/plugins/lazyclaude/.mcp.json +9 -0
- package/plugins/lazyclaude/agents/boulder-executor.md +12 -0
- package/plugins/lazyclaude/agents/librarian-researcher.md +11 -0
- package/plugins/lazyclaude/agents/oracle-verifier.md +12 -0
- package/plugins/lazyclaude/agents/prometheus-planner.md +13 -0
- package/plugins/lazyclaude/agents/qa-runner.md +12 -0
- package/plugins/lazyclaude/agents/quality-reviewer.md +12 -0
- package/plugins/lazyclaude/bin/lazyclaude-hook.js +67 -0
- package/plugins/lazyclaude/bin/lazyclaude-lsp-doctor.js +15 -0
- package/plugins/lazyclaude/bin/lazyclaude-mcp.js +70 -0
- package/plugins/lazyclaude/hooks/hooks.json +54 -0
- package/plugins/lazyclaude/skills/lsp/SKILL.md +13 -0
- package/plugins/lazyclaude/skills/programming/SKILL.md +14 -0
- package/plugins/lazyclaude/skills/review-work/SKILL.md +13 -0
- package/plugins/lazyclaude/skills/rules/SKILL.md +13 -0
- package/plugins/lazyclaude/skills/start-work/SKILL.md +19 -0
- package/plugins/lazyclaude/skills/ulw-loop/SKILL.md +14 -0
- package/plugins/lazyclaude/skills/ulw-plan/SKILL.md +18 -0
- package/scripts/audit-plan-checkboxes.mjs +36 -0
- package/scripts/doctor.mjs +27 -0
- package/scripts/inspect-agent-tools.mjs +27 -0
- package/scripts/qa-claude-plugin-smoke.sh +60 -0
- package/scripts/qa-portable-install.sh +80 -0
- 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
|
+
});
|