@eltonssouza/development-utility-kit 1.0.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 (137) hide show
  1. package/.claude/agents/analyst.md +198 -0
  2. package/.claude/agents/backend-developer.md +126 -0
  3. package/.claude/agents/brain-keeper.md +229 -0
  4. package/.claude/agents/code-reviewer.md +181 -0
  5. package/.claude/agents/database-engineer.md +94 -0
  6. package/.claude/agents/devops-engineer.md +141 -0
  7. package/.claude/agents/frontend-developer.md +97 -0
  8. package/.claude/agents/gate-keeper.md +118 -0
  9. package/.claude/agents/migrator.md +291 -0
  10. package/.claude/agents/mobile-developer.md +80 -0
  11. package/.claude/agents/n8n-specialist.md +94 -0
  12. package/.claude/agents/product-owner.md +115 -0
  13. package/.claude/agents/qa-engineer.md +232 -0
  14. package/.claude/agents/release-engineer.md +204 -0
  15. package/.claude/agents/scaffold.md +87 -0
  16. package/.claude/agents/security-engineer.md +199 -0
  17. package/.claude/agents/sprint-runner.md +44 -0
  18. package/.claude/agents/stack-resolver.md +84 -0
  19. package/.claude/agents/tech-lead.md +182 -0
  20. package/.claude/agents/update-template.md +54 -0
  21. package/.claude/agents/ux-designer.md +118 -0
  22. package/.claude/settings.json +44 -0
  23. package/.claude/skills/README.md +332 -0
  24. package/.claude/skills/active-project/SKILL.md +129 -0
  25. package/.claude/skills/api-integration-test/SKILL.md +64 -0
  26. package/.claude/skills/auto-test-guard/SKILL.md +237 -0
  27. package/.claude/skills/auto-test-guard/resources/backend-tests.md +20 -0
  28. package/.claude/skills/auto-test-guard/resources/e2e-tests.md +24 -0
  29. package/.claude/skills/auto-test-guard/resources/execution-report.md +49 -0
  30. package/.claude/skills/auto-test-guard/resources/frontend-tests.md +18 -0
  31. package/.claude/skills/auto-test-guard/resources/initial-setup.md +108 -0
  32. package/.claude/skills/auto-test-guard/resources/run-suite.md +48 -0
  33. package/.claude/skills/auto-test-guard/resources/senior-gate.md +19 -0
  34. package/.claude/skills/brain-keeper/SKILL.md +60 -0
  35. package/.claude/skills/brain-keeper/obsidian/app.json +9 -0
  36. package/.claude/skills/brain-keeper/obsidian/appearance.json +4 -0
  37. package/.claude/skills/brain-keeper/obsidian/core-plugins.json +20 -0
  38. package/.claude/skills/brain-keeper/obsidian/daily-notes.json +5 -0
  39. package/.claude/skills/brain-keeper/obsidian/graph.json +32 -0
  40. package/.claude/skills/brain-keeper/obsidian/snippets/folder-colors.css +90 -0
  41. package/.claude/skills/brain-keeper/obsidian/templates.json +5 -0
  42. package/.claude/skills/brain-keeper/templates/README.md +51 -0
  43. package/.claude/skills/brain-keeper/templates/adr.md +40 -0
  44. package/.claude/skills/brain-keeper/templates/bug.md +35 -0
  45. package/.claude/skills/brain-keeper/templates/daily.md +38 -0
  46. package/.claude/skills/brain-keeper/templates/feature.md +62 -0
  47. package/.claude/skills/brain-keeper/templates/meeting.md +34 -0
  48. package/.claude/skills/brain-keeper/templates/tech-debt.md +21 -0
  49. package/.claude/skills/caveman/SKILL.md +187 -0
  50. package/.claude/skills/create-stack-pack/SKILL.md +281 -0
  51. package/.claude/skills/grill-me/SKILL.md +79 -0
  52. package/.claude/skills/honcho-memory/SKILL.md +207 -0
  53. package/.claude/skills/honcho-memory/docs/api-endpoints-verified.md +75 -0
  54. package/.claude/skills/honcho-memory/hooks/on-prompt-submit.js +221 -0
  55. package/.claude/skills/honcho-memory/hooks/on-stop.js +193 -0
  56. package/.claude/skills/honcho-memory/lib/honcho-client.js +363 -0
  57. package/.claude/skills/honcho-memory/lib/memory-injector.js +93 -0
  58. package/.claude/skills/honcho-memory/package.json +32 -0
  59. package/.claude/skills/honcho-memory/scripts/cli.js +370 -0
  60. package/.claude/skills/honcho-memory/scripts/setup.js +109 -0
  61. package/.claude/skills/honcho-memory/tests/t001-api-endpoints-verified.test.js +89 -0
  62. package/.claude/skills/honcho-memory/tests/t002-structure.test.js +97 -0
  63. package/.claude/skills/honcho-memory/tests/t003-honcho-client.test.js +162 -0
  64. package/.claude/skills/honcho-memory/tests/t004-soft-delete.test.js +259 -0
  65. package/.claude/skills/honcho-memory/tests/t005-memory-injector.test.js +175 -0
  66. package/.claude/skills/honcho-memory/tests/t006-on-prompt-submit.test.js +215 -0
  67. package/.claude/skills/honcho-memory/tests/t007-on-stop.test.js +165 -0
  68. package/.claude/skills/honcho-memory/tests/t008-cli.test.js +214 -0
  69. package/.claude/skills/honcho-memory/tests/t009-setup.test.js +232 -0
  70. package/.claude/skills/honcho-memory/tests/t010-skill-md.test.js +114 -0
  71. package/.claude/skills/honcho-memory/tests/t011-settings-hooks.test.js +105 -0
  72. package/.claude/skills/honcho-memory/tests/t012-docs-update.test.js +106 -0
  73. package/.claude/skills/honcho-memory/tests/t013-smoke-e2e.test.js +90 -0
  74. package/.claude/skills/pair-debug/SKILL.md +288 -0
  75. package/.claude/skills/prd-ready-check/SKILL.md +58 -0
  76. package/.claude/skills/project-manager/SKILL.md +167 -0
  77. package/.claude/skills/quality-standards/SKILL.md +201 -0
  78. package/.claude/skills/quick-feature/SKILL.md +264 -0
  79. package/.claude/skills/run-sprint/SKILL.md +342 -0
  80. package/.claude/skills/scaffold/SKILL.md +58 -0
  81. package/.claude/skills/stack-discovery/SKILL.md +159 -0
  82. package/.claude/skills/test-coverage-auditor/SKILL.md +59 -0
  83. package/.claude/skills/to-issues/SKILL.md +163 -0
  84. package/.claude/skills/to-prd/SKILL.md +130 -0
  85. package/.claude/skills/update-template/SKILL.md +254 -0
  86. package/.claude/stacks/CODEOWNERS +30 -0
  87. package/.claude/stacks/README.md +88 -0
  88. package/.claude/stacks/_template.md +116 -0
  89. package/.claude/stacks/java/spring-boot-3.md +376 -0
  90. package/.claude/stacks/java/spring-boot-4.md +438 -0
  91. package/.claude/stacks/typescript/angular-18.md +420 -0
  92. package/.claude/stacks/typescript/angular-19.md +397 -0
  93. package/.claude/stacks/typescript/angular-21.md +494 -0
  94. package/CLAUDE.md +453 -0
  95. package/README.md +391 -0
  96. package/bin/cli.js +773 -0
  97. package/bin/lib/backup.js +62 -0
  98. package/bin/lib/detect-stack.js +476 -0
  99. package/bin/lib/help.js +233 -0
  100. package/bin/lib/identity.js +108 -0
  101. package/bin/lib/local-dir.js +69 -0
  102. package/bin/lib/manifest.js +236 -0
  103. package/bin/lib/sync-all.js +394 -0
  104. package/bin/lib/version-check.js +398 -0
  105. package/dashboard/db.js +199 -0
  106. package/dashboard/package.json +22 -0
  107. package/dashboard/public/app.js +709 -0
  108. package/dashboard/public/content/docs/agents-reference.en.md +911 -0
  109. package/dashboard/public/content/docs/architecture-overview.en.md +260 -0
  110. package/dashboard/public/content/docs/autonomy-matrix.en.md +186 -0
  111. package/dashboard/public/content/docs/git-flow.en.md +525 -0
  112. package/dashboard/public/content/docs/honcho-memory.en.md +394 -0
  113. package/dashboard/public/content/docs/hooks-reference.en.md +420 -0
  114. package/dashboard/public/content/docs/pipeline.en.md +400 -0
  115. package/dashboard/public/content/docs/quality-gate.en.md +315 -0
  116. package/dashboard/public/content/docs/skills-reference.en.md +500 -0
  117. package/dashboard/public/content/docs/stack-rules.en.md +362 -0
  118. package/dashboard/public/content/docs/troubleshooting.en.md +637 -0
  119. package/dashboard/public/content/manifest.json +102 -0
  120. package/dashboard/public/content/manual/backend.en.md +1138 -0
  121. package/dashboard/public/content/manual/existing-project.en.md +831 -0
  122. package/dashboard/public/content/manual/frontend.en.md +1065 -0
  123. package/dashboard/public/content/manual/fullstack.en.md +1508 -0
  124. package/dashboard/public/content/manual/mobile.en.md +866 -0
  125. package/dashboard/public/index.html +108 -0
  126. package/dashboard/public/style.css +610 -0
  127. package/dashboard/public/vendor/marked.min.js +69 -0
  128. package/dashboard/rtk.js +143 -0
  129. package/dashboard/server-app.js +403 -0
  130. package/dashboard/server.js +104 -0
  131. package/dashboard/test/sprint1.test.js +406 -0
  132. package/dashboard/test/sprint2.test.js +571 -0
  133. package/dashboard/test/sprint3.test.js +560 -0
  134. package/package.json +33 -0
  135. package/scripts/hooks/subagent-telemetry.sh +14 -0
  136. package/scripts/hooks/telemetry-writer.js +250 -0
  137. package/scripts/latest-versions.json +56 -0
@@ -0,0 +1,232 @@
1
+ /**
2
+ * T-009: Verify scripts/setup.js — wizard + migration of memory/*.md
3
+ *
4
+ * Tests written BEFORE implementation (TDD RED phase).
5
+ *
6
+ * DoD assertions:
7
+ * - `bun run scripts/setup.js --dry-run` → exit 0, stdout contains "DRY_RUN:"
8
+ * - When no memory/*.md files exist → stdout contains "DRY_RUN: no memory files found"
9
+ * - When memory/*.md files exist → stdout contains "DRY_RUN: would migrate N files"
10
+ * - Two consecutive --dry-run calls both return exit 0 (idempotence)
11
+ * - Config missing → still exits 0 (graceful degradation), stdout contains "DRY_RUN:"
12
+ */
13
+
14
+ import { existsSync, mkdirSync, writeFileSync, rmSync } from "fs";
15
+ import { join } from "path";
16
+ import { spawnSync } from "child_process";
17
+ import { tmpdir } from "os";
18
+
19
+ const SKILL_DIR = new URL("../", import.meta.url).pathname.replace(/^\/([A-Za-z]:)/, "$1");
20
+ const SETUP_FILE = join(SKILL_DIR, "scripts", "setup.js");
21
+ const BUN_EXE = "C:\\Users\\elton\\.bun\\bin\\bun.exe";
22
+
23
+ function runSetup(args, cwd, env = {}) {
24
+ const result = spawnSync(
25
+ BUN_EXE,
26
+ ["run", SETUP_FILE, ...args],
27
+ {
28
+ encoding: "utf8",
29
+ timeout: 15000,
30
+ cwd: cwd ?? process.cwd(),
31
+ env: { ...process.env, ...env },
32
+ }
33
+ );
34
+ return {
35
+ exitCode: result.status,
36
+ stdout: result.stdout ?? "",
37
+ stderr: result.stderr ?? "",
38
+ timedOut: result.error?.code === "ETIMEDOUT",
39
+ };
40
+ }
41
+
42
+ /** Create a temp directory with optional memory/*.md files */
43
+ function makeTempDir(withMemoryFiles = false) {
44
+ const dir = join(tmpdir(), `honcho-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
45
+ mkdirSync(dir, { recursive: true });
46
+ if (withMemoryFiles) {
47
+ mkdirSync(join(dir, "memory"), { recursive: true });
48
+ writeFileSync(join(dir, "memory", "test1.md"), "# Memory 1\nThis is a test memory.");
49
+ writeFileSync(join(dir, "memory", "test2.md"), "# Memory 2\nAnother test memory.");
50
+ }
51
+ return dir;
52
+ }
53
+
54
+ // Test 1: scripts/setup.js must exist
55
+ const test1 = () => {
56
+ if (!existsSync(SETUP_FILE)) {
57
+ throw new Error(`scripts/setup.js does not exist at: ${SETUP_FILE}`);
58
+ }
59
+ console.log("PASS: scripts/setup.js exists");
60
+ };
61
+
62
+ // Test 2: --dry-run → exit 0
63
+ const test2 = () => {
64
+ const dir = makeTempDir(false);
65
+ try {
66
+ const { exitCode, stderr } = runSetup(["--dry-run"], dir);
67
+ if (exitCode !== 0) {
68
+ throw new Error(`--dry-run: expected exit 0, got ${exitCode}. stderr: ${stderr}`);
69
+ }
70
+ } finally {
71
+ rmSync(dir, { recursive: true, force: true });
72
+ }
73
+ console.log("PASS: --dry-run → exit 0");
74
+ };
75
+
76
+ // Test 3: --dry-run stdout contains "DRY_RUN:"
77
+ const test3 = () => {
78
+ const dir = makeTempDir(false);
79
+ try {
80
+ const { stdout, stderr } = runSetup(["--dry-run"], dir);
81
+ if (!stdout.includes("DRY_RUN:")) {
82
+ throw new Error(`--dry-run: stdout missing "DRY_RUN:". stdout: ${stdout}, stderr: ${stderr}`);
83
+ }
84
+ } finally {
85
+ rmSync(dir, { recursive: true, force: true });
86
+ }
87
+ console.log("PASS: --dry-run stdout contains \"DRY_RUN:\"");
88
+ };
89
+
90
+ // Test 4: --dry-run with NO memory files → stdout contains "no memory files found"
91
+ const test4 = () => {
92
+ const dir = makeTempDir(false); // no memory/ dir
93
+ try {
94
+ const { stdout } = runSetup(["--dry-run"], dir);
95
+ if (!stdout.includes("no memory files found")) {
96
+ throw new Error(`--dry-run no files: stdout missing "no memory files found". stdout: ${stdout}`);
97
+ }
98
+ } finally {
99
+ rmSync(dir, { recursive: true, force: true });
100
+ }
101
+ console.log("PASS: --dry-run (no files) stdout contains \"no memory files found\"");
102
+ };
103
+
104
+ // Test 5: --dry-run with memory files → stdout contains "would migrate N files"
105
+ const test5 = () => {
106
+ const dir = makeTempDir(true); // creates 2 .md files
107
+ try {
108
+ const { stdout } = runSetup(["--dry-run"], dir);
109
+ if (!stdout.includes("would migrate")) {
110
+ throw new Error(`--dry-run with files: stdout missing "would migrate". stdout: ${stdout}`);
111
+ }
112
+ if (!stdout.includes("2 files") && !stdout.includes("2")) {
113
+ throw new Error(`--dry-run with files: stdout should mention count 2. stdout: ${stdout}`);
114
+ }
115
+ } finally {
116
+ rmSync(dir, { recursive: true, force: true });
117
+ }
118
+ console.log("PASS: --dry-run (with 2 files) stdout contains \"would migrate 2 files\"");
119
+ };
120
+
121
+ // Test 6: --dry-run is idempotent — two calls both exit 0
122
+ const test6 = () => {
123
+ const dir = makeTempDir(false);
124
+ try {
125
+ const { exitCode: exit1 } = runSetup(["--dry-run"], dir);
126
+ const { exitCode: exit2 } = runSetup(["--dry-run"], dir);
127
+ if (exit1 !== 0) {
128
+ throw new Error(`idempotence: first call exit ${exit1}, expected 0`);
129
+ }
130
+ if (exit2 !== 0) {
131
+ throw new Error(`idempotence: second call exit ${exit2}, expected 0`);
132
+ }
133
+ } finally {
134
+ rmSync(dir, { recursive: true, force: true });
135
+ }
136
+ console.log("PASS: two consecutive --dry-run calls both exit 0 (idempotent)");
137
+ };
138
+
139
+ // Test 7: --dry-run is idempotent with memory files
140
+ const test7 = () => {
141
+ const dir = makeTempDir(true);
142
+ try {
143
+ const { exitCode: exit1, stdout: out1 } = runSetup(["--dry-run"], dir);
144
+ const { exitCode: exit2, stdout: out2 } = runSetup(["--dry-run"], dir);
145
+ if (exit1 !== 0) {
146
+ throw new Error(`idempotence with files: first call exit ${exit1}, expected 0`);
147
+ }
148
+ if (exit2 !== 0) {
149
+ throw new Error(`idempotence with files: second call exit ${exit2}, expected 0. stdout: ${out2}`);
150
+ }
151
+ if (!out1.includes("DRY_RUN:") || !out2.includes("DRY_RUN:")) {
152
+ throw new Error(`idempotence: both calls must contain "DRY_RUN:". out1: ${out1}, out2: ${out2}`);
153
+ }
154
+ } finally {
155
+ rmSync(dir, { recursive: true, force: true });
156
+ }
157
+ console.log("PASS: two consecutive --dry-run (with files) calls both exit 0 and contain DRY_RUN:");
158
+ };
159
+
160
+ // Test 8: missing config → still exits 0 with graceful degradation
161
+ const test8 = () => {
162
+ const dir = makeTempDir(false);
163
+ try {
164
+ // Override config path to something that does not exist
165
+ const { exitCode, stdout, stderr } = runSetup(
166
+ ["--dry-run"],
167
+ dir,
168
+ { HONCHO_CONFIG_PATH: join(dir, "nonexistent-config.json") }
169
+ );
170
+ if (exitCode !== 0) {
171
+ throw new Error(`missing config: expected exit 0, got ${exitCode}. stderr: ${stderr}`);
172
+ }
173
+ // Must still output DRY_RUN: line
174
+ if (!stdout.includes("DRY_RUN:")) {
175
+ throw new Error(`missing config: stdout missing "DRY_RUN:". stdout: ${stdout}`);
176
+ }
177
+ } finally {
178
+ rmSync(dir, { recursive: true, force: true });
179
+ }
180
+ console.log("PASS: missing config → exit 0 with graceful degradation, DRY_RUN: in stdout");
181
+ };
182
+
183
+ // Test 9: --dry-run completes in < 5s (connection attempt should timeout fast)
184
+ const test9 = () => {
185
+ const dir = makeTempDir(false);
186
+ try {
187
+ const start = Date.now();
188
+ const { exitCode, timedOut } = runSetup(["--dry-run"], dir);
189
+ const elapsed = Date.now() - start;
190
+ if (timedOut) {
191
+ throw new Error("--dry-run timed out at 15s");
192
+ }
193
+ if (elapsed >= 5000) {
194
+ throw new Error(`--dry-run took ${elapsed}ms, expected < 5000ms`);
195
+ }
196
+ } finally {
197
+ rmSync(dir, { recursive: true, force: true });
198
+ }
199
+ console.log("PASS: --dry-run completes in < 5s");
200
+ };
201
+
202
+ // Test 10: --dry-run with 1 .md file → mentions 1 file
203
+ const test10 = () => {
204
+ const dir = makeTempDir(false);
205
+ try {
206
+ mkdirSync(join(dir, "memory"), { recursive: true });
207
+ writeFileSync(join(dir, "memory", "single.md"), "# Single memory\nContent here.");
208
+ const { stdout } = runSetup(["--dry-run"], dir);
209
+ if (!stdout.includes("would migrate") || !stdout.includes("1")) {
210
+ throw new Error(`1-file case: stdout should mention 1 file. stdout: ${stdout}`);
211
+ }
212
+ } finally {
213
+ rmSync(dir, { recursive: true, force: true });
214
+ }
215
+ console.log("PASS: --dry-run with 1 file → stdout mentions 1 file");
216
+ };
217
+
218
+ // Run all tests
219
+ let failed = 0;
220
+ const tests = [test1, test2, test3, test4, test5, test6, test7, test8, test9, test10];
221
+
222
+ for (const t of tests) {
223
+ try {
224
+ await t();
225
+ } catch (e) {
226
+ console.error(`FAIL: ${e.message}`);
227
+ failed++;
228
+ }
229
+ }
230
+
231
+ console.log(`\nT-009 Results: ${tests.length - failed}/${tests.length} passed`);
232
+ process.exit(failed > 0 ? 1 : 0);
@@ -0,0 +1,114 @@
1
+ /**
2
+ * T-010 — Tests for .claude/skills/honcho-memory/SKILL.md
3
+ * DoD:
4
+ * - file exists
5
+ * - contains `name: honcho-memory` in frontmatter
6
+ * - body contains `[HONCHO MEMORY]`
7
+ * - body contains `graceful`
8
+ * - body contains note about forget using soft-delete via PUT
9
+ */
10
+
11
+ import { readFileSync, existsSync } from 'fs';
12
+ import { join, dirname } from 'path';
13
+ import { fileURLToPath } from 'url';
14
+
15
+ const __filename = fileURLToPath(import.meta.url);
16
+ const __dirname = dirname(__filename);
17
+ const SKILL_MD_PATH = join(__dirname, '..', 'SKILL.md');
18
+
19
+ // --- helpers ---
20
+ function readSkillMd() {
21
+ if (!existsSync(SKILL_MD_PATH)) {
22
+ return null;
23
+ }
24
+ return readFileSync(SKILL_MD_PATH, 'utf8');
25
+ }
26
+
27
+ function parseFrontmatter(content) {
28
+ const match = content.match(/^---\s*\n([\s\S]*?)\n---/);
29
+ if (!match) return null;
30
+ return match[1];
31
+ }
32
+
33
+ // --- tests ---
34
+ let passed = 0;
35
+ let failed = 0;
36
+
37
+ function assert(condition, label) {
38
+ if (condition) {
39
+ console.log(` PASS: ${label}`);
40
+ passed++;
41
+ } else {
42
+ console.error(` FAIL: ${label}`);
43
+ failed++;
44
+ }
45
+ }
46
+
47
+ console.log('\n=== T-010: SKILL.md ===\n');
48
+
49
+ const content = readSkillMd();
50
+
51
+ assert(content !== null, 'SKILL.md exists');
52
+
53
+ if (content !== null) {
54
+ const frontmatter = parseFrontmatter(content);
55
+ assert(frontmatter !== null, 'Has YAML frontmatter delimited by ---');
56
+ assert(
57
+ frontmatter !== null && frontmatter.includes('name: honcho-memory'),
58
+ 'Frontmatter contains name: honcho-memory'
59
+ );
60
+
61
+ assert(
62
+ content.includes('[HONCHO MEMORY]'),
63
+ 'Body contains [HONCHO MEMORY] block marker'
64
+ );
65
+
66
+ assert(
67
+ content.includes('graceful'),
68
+ 'Body contains "graceful" (degradation graceful)'
69
+ );
70
+
71
+ assert(
72
+ content.includes('PUT') && content.toLowerCase().includes('soft-delete') ||
73
+ content.includes('PUT') && content.includes('soft delete'),
74
+ 'Body contains soft-delete via PUT note for forget command'
75
+ );
76
+
77
+ // trigger coverage
78
+ const triggers = [
79
+ 'honcho memory',
80
+ 'memória honcho',
81
+ 'lembra que',
82
+ 'remember that',
83
+ 'memoriza',
84
+ '/honcho save',
85
+ '/honcho search',
86
+ '/honcho list',
87
+ '/honcho forget',
88
+ '/honcho status',
89
+ '/honcho setup',
90
+ ];
91
+ for (const trigger of triggers) {
92
+ const found = content.toLowerCase().includes(trigger.toLowerCase());
93
+ assert(found, `Contains trigger: "${trigger}"`);
94
+ }
95
+
96
+ // subcommands documented
97
+ const subcmds = ['save', 'search', 'list', 'forget', 'status', 'setup'];
98
+ for (const cmd of subcmds) {
99
+ assert(content.includes(cmd), `Documents subcommand: ${cmd}`);
100
+ }
101
+
102
+ assert(
103
+ content.includes('config.json'),
104
+ 'References config.json location'
105
+ );
106
+
107
+ assert(
108
+ content.includes('setup.js') || content.includes('setup'),
109
+ 'References setup script'
110
+ );
111
+ }
112
+
113
+ console.log(`\nResults: ${passed} passed, ${failed} failed`);
114
+ process.exit(failed > 0 ? 1 : 0);
@@ -0,0 +1,105 @@
1
+ /**
2
+ * T-011 — Tests for hooks registration in C:/Users/elton/.claude/settings.json
3
+ * DoD:
4
+ * - settings.json is valid JSON (exit 0 on parse)
5
+ * - hooks.UserPromptSubmit is present and contains on-prompt-submit.js command
6
+ * - hooks.Stop is present and contains on-stop.js command
7
+ * - commands use forward slashes (IR-006)
8
+ * - commands point to the harness path (Option B — C:/development/tools/development-utility-kit/...)
9
+ * - rest of the file is preserved (permissions key still exists)
10
+ */
11
+
12
+ import { readFileSync, existsSync } from 'fs';
13
+
14
+ const SETTINGS_PATH = 'C:/Users/elton/.claude/settings.json';
15
+
16
+ let passed = 0;
17
+ let failed = 0;
18
+
19
+ function assert(condition, label) {
20
+ if (condition) {
21
+ console.log(` PASS: ${label}`);
22
+ passed++;
23
+ } else {
24
+ console.error(` FAIL: ${label}`);
25
+ failed++;
26
+ }
27
+ }
28
+
29
+ console.log('\n=== T-011: settings.json hooks registration ===\n');
30
+
31
+ assert(existsSync(SETTINGS_PATH), 'settings.json exists');
32
+
33
+ let settings = null;
34
+ try {
35
+ settings = JSON.parse(readFileSync(SETTINGS_PATH, 'utf8'));
36
+ assert(true, 'settings.json is valid JSON');
37
+ } catch (e) {
38
+ assert(false, `settings.json is valid JSON (error: ${e.message})`);
39
+ }
40
+
41
+ if (settings) {
42
+ // Existing content preserved
43
+ assert(
44
+ settings.permissions !== undefined,
45
+ 'permissions key preserved (existing content intact)'
46
+ );
47
+
48
+ // hooks key exists
49
+ assert(settings.hooks !== undefined, 'hooks key exists in settings.json');
50
+
51
+ if (settings.hooks) {
52
+ // UserPromptSubmit
53
+ const ups = settings.hooks.UserPromptSubmit;
54
+ assert(Array.isArray(ups) && ups.length > 0, 'hooks.UserPromptSubmit is a non-empty array');
55
+
56
+ if (Array.isArray(ups) && ups.length > 0) {
57
+ const allCommands = ups.flatMap(entry =>
58
+ (entry.hooks || []).map(h => h.command || '')
59
+ );
60
+ const hasPromptHook = allCommands.some(cmd => cmd.includes('on-prompt-submit.js'));
61
+ assert(hasPromptHook, 'UserPromptSubmit contains on-prompt-submit.js command');
62
+
63
+ const usesHarnessPath = allCommands.some(cmd =>
64
+ cmd.includes('C:/development/tools/development-utility-kit') ||
65
+ cmd.includes('development-utility-kit')
66
+ );
67
+ assert(usesHarnessPath, 'UserPromptSubmit command uses harness path (Option B)');
68
+
69
+ const usesForwardSlashes = allCommands.some(cmd =>
70
+ cmd.includes('on-prompt-submit.js') && !cmd.includes('\\')
71
+ );
72
+ assert(usesForwardSlashes, 'UserPromptSubmit command uses forward slashes (IR-006)');
73
+
74
+ // Check matcher exists
75
+ const hasMatcher = ups.some(entry => entry.matcher !== undefined);
76
+ assert(hasMatcher, 'UserPromptSubmit entry has matcher field');
77
+ }
78
+
79
+ // Stop
80
+ const stop = settings.hooks.Stop;
81
+ assert(Array.isArray(stop) && stop.length > 0, 'hooks.Stop is a non-empty array');
82
+
83
+ if (Array.isArray(stop) && stop.length > 0) {
84
+ const allCmds = stop.flatMap(entry =>
85
+ (entry.hooks || []).map(h => h.command || '')
86
+ );
87
+ const hasStopHook = allCmds.some(cmd => cmd.includes('on-stop.js'));
88
+ assert(hasStopHook, 'Stop contains on-stop.js command');
89
+
90
+ const usesHarnessPathStop = allCmds.some(cmd =>
91
+ cmd.includes('C:/development/tools/development-utility-kit') ||
92
+ cmd.includes('development-utility-kit')
93
+ );
94
+ assert(usesHarnessPathStop, 'Stop command uses harness path (Option B)');
95
+
96
+ const usesForwardSlashesStop = allCmds.some(cmd =>
97
+ cmd.includes('on-stop.js') && !cmd.includes('\\')
98
+ );
99
+ assert(usesForwardSlashesStop, 'Stop command uses forward slashes (IR-006)');
100
+ }
101
+ }
102
+ }
103
+
104
+ console.log(`\nResults: ${passed} passed, ${failed} failed`);
105
+ process.exit(failed > 0 ? 1 : 0);
@@ -0,0 +1,106 @@
1
+ /**
2
+ * T-012 — Tests for CLAUDE.md and .claude/skills/README.md updates
3
+ * DoD:
4
+ * - CLAUDE.md contains "honcho-memory"
5
+ * - .claude/skills/README.md contains "honcho-memory"
6
+ * - Both files reference honcho-memory skill entry with triggers and output description
7
+ */
8
+
9
+ import { readFileSync, existsSync } from 'fs';
10
+ import { join } from 'path';
11
+
12
+ const HARNESS_ROOT = 'C:/development/tools/development-utility-kit';
13
+ const CLAUDE_MD_PATH = join(HARNESS_ROOT, 'CLAUDE.md');
14
+ const README_PATH = join(HARNESS_ROOT, '.claude/skills/README.md');
15
+
16
+ let passed = 0;
17
+ let failed = 0;
18
+
19
+ function assert(condition, label) {
20
+ if (condition) {
21
+ console.log(` PASS: ${label}`);
22
+ passed++;
23
+ } else {
24
+ console.error(` FAIL: ${label}`);
25
+ failed++;
26
+ }
27
+ }
28
+
29
+ console.log('\n=== T-012: CLAUDE.md + README.md documentation update ===\n');
30
+
31
+ // --- CLAUDE.md checks ---
32
+ assert(existsSync(CLAUDE_MD_PATH), 'CLAUDE.md exists');
33
+
34
+ let claudeMd = null;
35
+ try {
36
+ claudeMd = readFileSync(CLAUDE_MD_PATH, 'utf8');
37
+ assert(true, 'CLAUDE.md is readable');
38
+ } catch (e) {
39
+ assert(false, `CLAUDE.md is readable (error: ${e.message})`);
40
+ }
41
+
42
+ if (claudeMd) {
43
+ assert(
44
+ claudeMd.includes('honcho-memory'),
45
+ 'CLAUDE.md contains honcho-memory'
46
+ );
47
+
48
+ // Should have it in the skills table
49
+ const linesWithHoncho = claudeMd.split('\n').filter(l => l.includes('honcho-memory'));
50
+ assert(
51
+ linesWithHoncho.length > 0,
52
+ 'CLAUDE.md skills table row contains honcho-memory'
53
+ );
54
+
55
+ // The row should mention triggers
56
+ const tableRow = linesWithHoncho.find(l => l.includes('|'));
57
+ assert(
58
+ tableRow !== undefined,
59
+ 'honcho-memory appears in a table row (pipe-delimited)'
60
+ );
61
+
62
+ // The row should reference some trigger
63
+ const hasTrigger = linesWithHoncho.some(l =>
64
+ l.includes('lembra que') ||
65
+ l.includes('/honcho') ||
66
+ l.includes('remember that') ||
67
+ l.includes('honcho')
68
+ );
69
+ assert(hasTrigger, 'honcho-memory row references triggers');
70
+ }
71
+
72
+ // --- README.md checks ---
73
+ assert(existsSync(README_PATH), '.claude/skills/README.md exists');
74
+
75
+ let readmeMd = null;
76
+ try {
77
+ readmeMd = readFileSync(README_PATH, 'utf8');
78
+ assert(true, '.claude/skills/README.md is readable');
79
+ } catch (e) {
80
+ assert(false, `.claude/skills/README.md is readable (error: ${e.message})`);
81
+ }
82
+
83
+ if (readmeMd) {
84
+ assert(
85
+ readmeMd.includes('honcho-memory'),
86
+ '.claude/skills/README.md contains honcho-memory'
87
+ );
88
+
89
+ // Should have a link to SKILL.md
90
+ assert(
91
+ readmeMd.includes('honcho-memory/SKILL.md') ||
92
+ readmeMd.includes('honcho-memory'),
93
+ 'README.md references honcho-memory skill entry'
94
+ );
95
+
96
+ // Table row with pipe
97
+ const linesWithHoncho = readmeMd.split('\n').filter(l => l.includes('honcho-memory'));
98
+ const tableRow = linesWithHoncho.find(l => l.includes('|'));
99
+ assert(
100
+ tableRow !== undefined,
101
+ 'honcho-memory appears in README.md table row'
102
+ );
103
+ }
104
+
105
+ console.log(`\nResults: ${passed} passed, ${failed} failed`);
106
+ process.exit(failed > 0 ? 1 : 0);
@@ -0,0 +1,90 @@
1
+ /**
2
+ * T-013 — Smoke test E2E
3
+ * DoD:
4
+ * 1. `bun run scripts/cli.js status` → exit 0, stdout contains `connection: OK` or `connection: FAIL`
5
+ * 2. `bun run scripts/cli.js forget testId` → exit 0, stdout does NOT contain `DELETE` (confirms soft-delete via PUT)
6
+ * 3. `HONCHO_DRY_RUN=1 bun run hooks/on-prompt-submit.js` with generic stdin → exit 0
7
+ */
8
+
9
+ import { spawnSync } from 'child_process';
10
+ import { join, dirname } from 'path';
11
+ import { fileURLToPath } from 'url';
12
+
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = dirname(__filename);
15
+ const SKILL_ROOT = join(__dirname, '..');
16
+ const BUN = 'C:/Users/elton/.bun/bin/bun.exe';
17
+
18
+ let passed = 0;
19
+ let failed = 0;
20
+
21
+ function assert(condition, label) {
22
+ if (condition) {
23
+ console.log(` PASS: ${label}`);
24
+ passed++;
25
+ } else {
26
+ console.error(` FAIL: ${label}`);
27
+ failed++;
28
+ }
29
+ }
30
+
31
+ function runBun(args, env = {}, input = null) {
32
+ const result = spawnSync(BUN, ['run', ...args], {
33
+ cwd: SKILL_ROOT,
34
+ env: { ...process.env, ...env },
35
+ input: input ? input : undefined,
36
+ encoding: 'utf8',
37
+ timeout: 15000,
38
+ });
39
+ return {
40
+ exitCode: result.status ?? 1,
41
+ stdout: result.stdout ?? '',
42
+ stderr: result.stderr ?? '',
43
+ };
44
+ }
45
+
46
+ console.log('\n=== T-013: Smoke test E2E ===\n');
47
+
48
+ // --- Check 1: cli.js status ---
49
+ console.log('Check 1: cli.js status');
50
+ {
51
+ const r = runBun(['scripts/cli.js', 'status'], { HONCHO_DRY_RUN: '1' });
52
+ assert(r.exitCode === 0, 'cli.js status exits 0');
53
+ const combined = r.stdout + r.stderr;
54
+ const hasConnectionStatus =
55
+ combined.includes('connection: OK') ||
56
+ combined.includes('connection: FAIL') ||
57
+ combined.includes('connection:');
58
+ assert(hasConnectionStatus, 'cli.js status stdout/stderr contains "connection:"');
59
+ }
60
+
61
+ // --- Check 2: cli.js forget testId — soft-delete via PUT (no DELETE) ---
62
+ console.log('\nCheck 2: cli.js forget testId (soft-delete via PUT)');
63
+ {
64
+ const r = runBun(['scripts/cli.js', 'forget', 'testId'], { HONCHO_DRY_RUN: '1' });
65
+ assert(r.exitCode === 0, 'cli.js forget testId exits 0');
66
+ // stdout must NOT contain HTTP method "DELETE" as a method value
67
+ // (verifies soft-delete via PUT, not HTTP DELETE)
68
+ // Note: "deleted":true in JSON is acceptable — only "method":"DELETE" would indicate wrong implementation
69
+ const stdoutHasDeleteMethod =
70
+ r.stdout.includes('"method": "DELETE"') ||
71
+ r.stdout.includes('"method":"DELETE"');
72
+ assert(!stdoutHasDeleteMethod, 'cli.js forget stdout does NOT contain "method":"DELETE" (soft-delete via PUT confirmed)');
73
+ // stdout should confirm PUT method
74
+ const hasPutMethod = r.stdout.includes('"method": "PUT"') || r.stdout.includes('"method":"PUT"');
75
+ assert(hasPutMethod, 'cli.js forget stdout contains "method": "PUT"');
76
+ }
77
+
78
+ // --- Check 3: on-prompt-submit.js in dry-run with generic stdin ---
79
+ console.log('\nCheck 3: on-prompt-submit.js dry-run with generic stdin');
80
+ {
81
+ const r = runBun(
82
+ ['hooks/on-prompt-submit.js'],
83
+ { HONCHO_DRY_RUN: '1' },
84
+ JSON.stringify({ prompt: 'What is the capital of France?' })
85
+ );
86
+ assert(r.exitCode === 0, 'on-prompt-submit.js dry-run exits 0');
87
+ }
88
+
89
+ console.log(`\nResults: ${passed} passed, ${failed} failed`);
90
+ process.exit(failed > 0 ? 1 : 0);