@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,370 @@
1
+ /**
2
+ * cli.js — Honcho memory skill CLI dispatcher
3
+ *
4
+ * Subcommands:
5
+ * status — print connection status, memory count, enabled flags
6
+ * save <text> — save an explicit memory, print the ID
7
+ * search <query> — search memories (peer-scoped), print top-N formatted
8
+ * list — list memories for the current session (sha256(CWD)[:16])
9
+ * forget <id> — soft-delete memory via PUT metadata.deleted=true; exit 1 if no ID
10
+ *
11
+ * Env vars:
12
+ * HONCHO_DRY_RUN=1 — skip real Honcho calls; emit simulated output
13
+ * HONCHO_BASE_URL — override base URL from config
14
+ * HONCHO_TIMEOUT_MS — override timeout in ms
15
+ *
16
+ * Exit codes:
17
+ * 0 — success
18
+ * 1 — error (e.g. forget without ID, unknown subcommand, fatal)
19
+ *
20
+ * API key is never printed to stdout/stderr.
21
+ */
22
+
23
+ import { createHash } from "crypto";
24
+ import { createClient, loadConfig } from "../lib/honcho-client.js";
25
+
26
+ const DRY_RUN = process.env.HONCHO_DRY_RUN === "1";
27
+
28
+ /** Derive session ID from CWD: sha256(CWD)[:16] */
29
+ function deriveSessionId(cwd) {
30
+ return createHash("sha256").update(cwd).digest("hex").slice(0, 16);
31
+ }
32
+
33
+ function log(msg) {
34
+ process.stdout.write(msg + "\n");
35
+ }
36
+
37
+ function warn(msg) {
38
+ process.stderr.write("HONCHO_WARN: " + msg + "\n");
39
+ }
40
+
41
+ /** Build effective config from file + env overrides. Returns null if missing/invalid. */
42
+ function getEffectiveConfig() {
43
+ const cfg = loadConfig();
44
+
45
+ if (process.env.HONCHO_BASE_URL) {
46
+ return {
47
+ apiKey: cfg?.apiKey ?? "dry-run-key",
48
+ peerName: cfg?.peerName ?? "elton",
49
+ workspace: cfg?.workspace ?? "claude_code",
50
+ endpoint: { baseUrl: process.env.HONCHO_BASE_URL },
51
+ enabled: cfg?.enabled !== false,
52
+ topN: cfg?.topN ?? 5,
53
+ timeoutMs: process.env.HONCHO_TIMEOUT_MS
54
+ ? parseInt(process.env.HONCHO_TIMEOUT_MS, 10)
55
+ : (cfg?.timeoutMs ?? 450),
56
+ inferenceEnabled: cfg?.inferenceEnabled ?? false,
57
+ };
58
+ }
59
+
60
+ if (!cfg) return null;
61
+
62
+ if (process.env.HONCHO_TIMEOUT_MS) {
63
+ cfg.timeoutMs = parseInt(process.env.HONCHO_TIMEOUT_MS, 10);
64
+ }
65
+
66
+ return cfg;
67
+ }
68
+
69
+ // ---------------------------------------------------------------------------
70
+ // Subcommand handlers
71
+ // ---------------------------------------------------------------------------
72
+
73
+ async function cmdStatus() {
74
+ if (DRY_RUN) {
75
+ const cfg = loadConfig();
76
+ log("connection: DRY_RUN");
77
+ log("memories: 0");
78
+ log(`enabled: ${cfg?.enabled !== false ? "true" : "false"}`);
79
+ log(`inferenceEnabled: ${cfg?.inferenceEnabled === true ? "true" : "false"}`);
80
+ process.exit(0);
81
+ }
82
+
83
+ const cfg = getEffectiveConfig();
84
+ if (!cfg) {
85
+ log("connection: FAIL");
86
+ log("memories: 0");
87
+ log("enabled: false");
88
+ log("inferenceEnabled: false");
89
+ process.exit(0);
90
+ }
91
+
92
+ const client = createClient({
93
+ baseUrl: cfg.endpoint.baseUrl,
94
+ apiKey: cfg.apiKey,
95
+ timeoutMs: cfg.timeoutMs ?? 450,
96
+ });
97
+
98
+ const workspace = cfg.workspace ?? "claude_code";
99
+ const cwd = process.cwd();
100
+ const sessionId = deriveSessionId(cwd);
101
+
102
+ // Test connectivity by attempting to get/create app
103
+ const appResult = await client.getOrCreateApp(workspace);
104
+ const connected = appResult !== null;
105
+
106
+ // Count memories for the current session
107
+ let memCount = 0;
108
+ if (connected) {
109
+ const listResult = await client.listMemories(workspace, sessionId, {});
110
+ if (listResult && Array.isArray(listResult.items)) {
111
+ memCount = listResult.items.length;
112
+ }
113
+ }
114
+
115
+ log(`connection: ${connected ? "OK" : "FAIL"}`);
116
+ log(`memories: ${memCount}`);
117
+ log(`enabled: ${cfg.enabled !== false ? "true" : "false"}`);
118
+ log(`inferenceEnabled: ${cfg.inferenceEnabled === true ? "true" : "false"}`);
119
+ process.exit(0);
120
+ }
121
+
122
+ async function cmdSave(text) {
123
+ const cwd = process.cwd();
124
+ const sessionId = deriveSessionId(cwd);
125
+ const project = cwd.split(/[/\\]/).pop() ?? "unknown";
126
+
127
+ if (DRY_RUN) {
128
+ const dryId = `dry-${Date.now()}`;
129
+ log(JSON.stringify({
130
+ dryRun: true,
131
+ action: "save",
132
+ id: dryId,
133
+ content: (text ?? "").slice(0, 100),
134
+ }));
135
+ process.exit(0);
136
+ }
137
+
138
+ const cfg = getEffectiveConfig();
139
+ if (!cfg) {
140
+ warn("No valid config found — cannot save memory");
141
+ process.exit(0);
142
+ }
143
+
144
+ const workspace = cfg.workspace ?? "claude_code";
145
+ const peerId = cfg.peerName ?? "elton";
146
+
147
+ const client = createClient({
148
+ baseUrl: cfg.endpoint.baseUrl,
149
+ apiKey: cfg.apiKey,
150
+ timeoutMs: cfg.timeoutMs ?? 450,
151
+ });
152
+
153
+ const result = await client.saveMemory(workspace, sessionId, peerId, text ?? "", {
154
+ type: "explicit",
155
+ source: "user",
156
+ project,
157
+ directory: cwd,
158
+ timestamp: new Date().toISOString(),
159
+ });
160
+
161
+ if (result) {
162
+ const id = result.id ?? result.items?.[0]?.id ?? "unknown";
163
+ log(`Saved memory. ID: ${id}`);
164
+ } else {
165
+ warn("Failed to save memory — Honcho may be unreachable");
166
+ }
167
+ process.exit(0);
168
+ }
169
+
170
+ async function cmdList() {
171
+ const cwd = process.cwd();
172
+ const sessionId = deriveSessionId(cwd);
173
+
174
+ if (DRY_RUN) {
175
+ log(JSON.stringify({
176
+ dryRun: true,
177
+ action: "list",
178
+ sessionId,
179
+ items: [],
180
+ }));
181
+ process.exit(0);
182
+ }
183
+
184
+ const cfg = getEffectiveConfig();
185
+ if (!cfg) {
186
+ warn("No valid config found — cannot list memories");
187
+ process.exit(0);
188
+ }
189
+
190
+ const workspace = cfg.workspace ?? "claude_code";
191
+
192
+ const client = createClient({
193
+ baseUrl: cfg.endpoint.baseUrl,
194
+ apiKey: cfg.apiKey,
195
+ timeoutMs: cfg.timeoutMs ?? 450,
196
+ });
197
+
198
+ const result = await client.listMemories(workspace, sessionId, {});
199
+ if (!result) {
200
+ warn("Failed to list memories — Honcho may be unreachable");
201
+ process.exit(0);
202
+ }
203
+
204
+ const items = result.items ?? [];
205
+ if (items.length === 0) {
206
+ log("No memories found for current session.");
207
+ process.exit(0);
208
+ }
209
+
210
+ for (let i = 0; i < items.length; i++) {
211
+ const m = items[i];
212
+ const meta = m.metadata ?? {};
213
+ const ts = meta.timestamp ?? "";
214
+ const type = meta.type ?? "unknown";
215
+ log(`[${i + 1}] id:${m.id ?? "?"} type:${type} ts:${ts}`);
216
+ log(` ${m.content ?? ""}`);
217
+ }
218
+ process.exit(0);
219
+ }
220
+
221
+ async function cmdSearch(query) {
222
+ const cfg = getEffectiveConfig();
223
+ const cwd = process.cwd();
224
+
225
+ if (DRY_RUN) {
226
+ log(JSON.stringify({
227
+ dryRun: true,
228
+ action: "search",
229
+ query: (query ?? "").slice(0, 100),
230
+ items: [],
231
+ }));
232
+ process.exit(0);
233
+ }
234
+
235
+ if (!cfg) {
236
+ warn("No valid config found — cannot search memories");
237
+ process.exit(0);
238
+ }
239
+
240
+ const workspace = cfg.workspace ?? "claude_code";
241
+ const peerId = cfg.peerName ?? "elton";
242
+ const topN = cfg.topN ?? 5;
243
+
244
+ const client = createClient({
245
+ baseUrl: cfg.endpoint.baseUrl,
246
+ apiKey: cfg.apiKey,
247
+ timeoutMs: cfg.timeoutMs ?? 450,
248
+ });
249
+
250
+ const result = await client.searchMemories(workspace, peerId, query ?? "", topN);
251
+ if (!result) {
252
+ warn("Failed to search memories — Honcho may be unreachable");
253
+ process.exit(0);
254
+ }
255
+
256
+ const items = result.items ?? [];
257
+ if (items.length === 0) {
258
+ log("No memories found matching your query.");
259
+ process.exit(0);
260
+ }
261
+
262
+ for (let i = 0; i < items.length; i++) {
263
+ const m = items[i];
264
+ const meta = m.metadata ?? {};
265
+ const type = meta.type ?? "unknown";
266
+ const score = m.score != null ? ` score:${m.score.toFixed(3)}` : "";
267
+ log(`[${i + 1}] id:${m.id ?? "?"} type:${type}${score}`);
268
+ log(` ${m.content ?? ""}`);
269
+ }
270
+ process.exit(0);
271
+ }
272
+
273
+ async function cmdForget(id) {
274
+ if (!id) {
275
+ process.stderr.write("Error: forget requires a memory ID. Usage: cli.js forget <id>\n");
276
+ process.exit(1);
277
+ }
278
+
279
+ const cwd = process.cwd();
280
+ const sessionId = deriveSessionId(cwd);
281
+
282
+ if (DRY_RUN) {
283
+ log(JSON.stringify({
284
+ dryRun: true,
285
+ action: "forget",
286
+ method: "PUT",
287
+ id,
288
+ sessionId,
289
+ metadata: { deleted: true },
290
+ }));
291
+ process.exit(0);
292
+ }
293
+
294
+ const cfg = getEffectiveConfig();
295
+ if (!cfg) {
296
+ warn("No valid config found — cannot forget memory");
297
+ process.exit(0);
298
+ }
299
+
300
+ const workspace = cfg.workspace ?? "claude_code";
301
+
302
+ const client = createClient({
303
+ baseUrl: cfg.endpoint.baseUrl,
304
+ apiKey: cfg.apiKey,
305
+ timeoutMs: cfg.timeoutMs ?? 450,
306
+ });
307
+
308
+ const result = await client.softDeleteMemory(workspace, sessionId, id);
309
+ if (result) {
310
+ log(JSON.stringify({
311
+ action: "forget",
312
+ method: "PUT",
313
+ id,
314
+ result,
315
+ }));
316
+ } else {
317
+ warn(`Failed to soft-delete memory id=${id} — Honcho may be unreachable or ID not found`);
318
+ }
319
+ process.exit(0);
320
+ }
321
+
322
+ // ---------------------------------------------------------------------------
323
+ // Main dispatcher
324
+ // ---------------------------------------------------------------------------
325
+
326
+ async function main() {
327
+ const [subcommand, ...rest] = process.argv.slice(2);
328
+
329
+ switch (subcommand) {
330
+ case "status":
331
+ await cmdStatus();
332
+ break;
333
+
334
+ case "save":
335
+ await cmdSave(rest.join(" ") || undefined);
336
+ break;
337
+
338
+ case "list":
339
+ await cmdList();
340
+ break;
341
+
342
+ case "search":
343
+ await cmdSearch(rest.join(" ") || undefined);
344
+ break;
345
+
346
+ case "forget":
347
+ await cmdForget(rest[0]);
348
+ break;
349
+
350
+ default:
351
+ if (!subcommand) {
352
+ process.stderr.write(
353
+ "Usage: cli.js <subcommand> [args]\n" +
354
+ "Subcommands: status, save <text>, list, search <query>, forget <id>\n"
355
+ );
356
+ } else {
357
+ process.stderr.write(
358
+ `Unknown subcommand: "${subcommand}"\n` +
359
+ "Usage: cli.js <subcommand> [args]\n" +
360
+ "Subcommands: status, save <text>, list, search <query>, forget <id>\n"
361
+ );
362
+ }
363
+ process.exit(1);
364
+ }
365
+ }
366
+
367
+ main().catch((err) => {
368
+ warn("Unexpected error: " + (err?.message ?? String(err)));
369
+ process.exit(1);
370
+ });
@@ -0,0 +1,109 @@
1
+ /**
2
+ * setup.js — Honcho memory skill setup wizard
3
+ *
4
+ * Verifies connection to Honcho, checks config validity, and optionally
5
+ * migrates legacy memory/*.md files to Honcho.
6
+ *
7
+ * Usage:
8
+ * bun run scripts/setup.js # interactive wizard
9
+ * bun run scripts/setup.js --dry-run # non-interactive verification only
10
+ *
11
+ * Exit codes:
12
+ * 0 — success or graceful degradation
13
+ * 1 — fatal error (missing bun, config parse error, etc.)
14
+ */
15
+
16
+ import { existsSync, readdirSync } from "fs";
17
+ import { join, resolve } from "path";
18
+ import { createClient, loadConfig } from "../lib/honcho-client.js";
19
+
20
+ const DRY_RUN = process.argv.includes("--dry-run");
21
+ const CONFIG_PATH = "C:\\Users\\elton\\.honcho\\config.json";
22
+
23
+ function log(msg) {
24
+ process.stdout.write(msg + "\n");
25
+ }
26
+
27
+ function warn(msg) {
28
+ process.stderr.write("HONCHO_WARN: " + msg + "\n");
29
+ }
30
+
31
+ async function checkConnection(cfg) {
32
+ const client = createClient({
33
+ baseUrl: cfg.endpoint.baseUrl,
34
+ apiKey: cfg.apiKey,
35
+ timeoutMs: cfg.timeoutMs ?? 450,
36
+ });
37
+
38
+ // Use the workspace from config to test connectivity
39
+ const workspaceId = cfg.hosts?.claude_code?.workspace ?? "claude_code";
40
+ const result = await client.getOrCreateApp(workspaceId);
41
+ return result !== null;
42
+ }
43
+
44
+ function countMemoryFiles(cwd) {
45
+ const memDir = join(cwd, "memory");
46
+ if (!existsSync(memDir)) return 0;
47
+ try {
48
+ return readdirSync(memDir).filter((f) => f.endsWith(".md")).length;
49
+ } catch {
50
+ return 0;
51
+ }
52
+ }
53
+
54
+ async function main() {
55
+ // Step 1: verify config exists and is parseable
56
+ if (!existsSync(CONFIG_PATH)) {
57
+ warn(`Config file not found: ${CONFIG_PATH}`);
58
+ log("Config: MISSING");
59
+ log("Connection: FAIL");
60
+ if (DRY_RUN) {
61
+ log("DRY_RUN: config missing, cannot proceed");
62
+ }
63
+ process.exit(0); // graceful degradation
64
+ }
65
+
66
+ const cfg = loadConfig();
67
+ if (!cfg) {
68
+ warn("Config file exists but failed to parse or is missing required fields");
69
+ log("Config: INVALID");
70
+ log("Connection: FAIL");
71
+ if (DRY_RUN) {
72
+ log("DRY_RUN: config invalid, cannot proceed");
73
+ }
74
+ process.exit(0); // graceful degradation
75
+ }
76
+
77
+ log("Config valid");
78
+
79
+ // Step 2: check connection
80
+ const connected = await checkConnection(cfg);
81
+
82
+ if (connected) {
83
+ log("Connection OK");
84
+ } else {
85
+ warn("Could not reach Honcho at " + cfg.endpoint.baseUrl);
86
+ log("Connection FAIL");
87
+ }
88
+
89
+ // Step 3: dry-run mode — report memory files and exit
90
+ if (DRY_RUN) {
91
+ const cwd = process.cwd();
92
+ const memCount = countMemoryFiles(cwd);
93
+ if (memCount > 0) {
94
+ log(`DRY_RUN: would migrate ${memCount} files`);
95
+ } else {
96
+ log("DRY_RUN: no memory files found");
97
+ }
98
+ process.exit(0);
99
+ }
100
+
101
+ // Step 4: interactive mode (future — not implemented in Sprint 0)
102
+ log("Setup complete. Run with --dry-run for non-interactive verification.");
103
+ process.exit(0);
104
+ }
105
+
106
+ main().catch((err) => {
107
+ warn("Unexpected error in setup: " + (err?.message ?? String(err)));
108
+ process.exit(0); // graceful degradation
109
+ });
@@ -0,0 +1,89 @@
1
+ /**
2
+ * T-001: Verify Honcho v3 endpoints documented correctly
3
+ *
4
+ * Failing tests to be written BEFORE implementation.
5
+ * These tests confirm the api-endpoints-verified.md file:
6
+ * - exists
7
+ * - contains a table with 6+ endpoints
8
+ * - contains a verifiedAt ISO-8601 field
9
+ * - each endpoint row has method, path, and verified status
10
+ */
11
+
12
+ import { existsSync, readFileSync } from "fs";
13
+ import { join } from "path";
14
+
15
+ const SKILL_DIR = new URL("../", import.meta.url).pathname.replace(/^\/([A-Za-z]:)/, "$1");
16
+ const DOCS_DIR = join(SKILL_DIR, "docs");
17
+ const TARGET_FILE = join(DOCS_DIR, "api-endpoints-verified.md");
18
+
19
+ function readFile() {
20
+ return readFileSync(TARGET_FILE, "utf8");
21
+ }
22
+
23
+ // Test 1: file must exist
24
+ const test1 = () => {
25
+ if (!existsSync(TARGET_FILE)) {
26
+ throw new Error(`api-endpoints-verified.md does not exist at: ${TARGET_FILE}`);
27
+ }
28
+ console.log("PASS: api-endpoints-verified.md exists");
29
+ };
30
+
31
+ // Test 2: must contain verifiedAt ISO-8601
32
+ const test2 = () => {
33
+ const content = readFile();
34
+ const iso8601Pattern = /verifiedAt[:\s]+\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/;
35
+ if (!iso8601Pattern.test(content)) {
36
+ throw new Error("api-endpoints-verified.md missing verifiedAt ISO-8601 field");
37
+ }
38
+ console.log("PASS: verifiedAt ISO-8601 present");
39
+ };
40
+
41
+ // Test 3: must have markdown table with 6+ endpoint rows
42
+ const test3 = () => {
43
+ const content = readFile();
44
+ // Count lines that look like markdown table rows with | separators
45
+ const tableRows = content
46
+ .split("\n")
47
+ .filter((line) => line.trim().startsWith("|") && !line.includes("---") && !line.includes("Operação") && !line.includes("Operation") && !line.includes("Method") && !line.includes("Método"));
48
+ if (tableRows.length < 6) {
49
+ throw new Error(`Expected 6+ endpoint rows in table, found ${tableRows.length}`);
50
+ }
51
+ console.log(`PASS: table contains ${tableRows.length} endpoint rows (>= 6)`);
52
+ };
53
+
54
+ // Test 4: must contain expected operations
55
+ const test4 = () => {
56
+ const content = readFile();
57
+ const requiredOps = ["getOrCreateApp", "getOrCreateSession", "saveMemory", "searchMemories", "listMemories", "deleteMemory"];
58
+ const missing = requiredOps.filter((op) => !content.includes(op));
59
+ if (missing.length > 0) {
60
+ throw new Error(`Missing operations in doc: ${missing.join(", ")}`);
61
+ }
62
+ console.log("PASS: all 6 required operations documented");
63
+ };
64
+
65
+ // Test 5: must contain HTTP methods GET/POST/DELETE
66
+ const test5 = () => {
67
+ const content = readFile();
68
+ for (const method of ["GET", "POST", "DELETE"]) {
69
+ if (!content.includes(method)) {
70
+ throw new Error(`Missing HTTP method ${method} in documentation`);
71
+ }
72
+ }
73
+ console.log("PASS: HTTP methods GET, POST, DELETE present");
74
+ };
75
+
76
+ // Run all tests
77
+ let failed = 0;
78
+ const tests = [test1, test2, test3, test4, test5];
79
+ for (const t of tests) {
80
+ try {
81
+ t();
82
+ } catch (e) {
83
+ console.error(`FAIL: ${e.message}`);
84
+ failed++;
85
+ }
86
+ }
87
+
88
+ console.log(`\nResults: ${tests.length - failed}/${tests.length} passed`);
89
+ process.exit(failed > 0 ? 1 : 0);
@@ -0,0 +1,97 @@
1
+ /**
2
+ * T-002: Verify package.json + directory structure
3
+ *
4
+ * Failing tests to be written BEFORE implementation.
5
+ * Verifies:
6
+ * - package.json exists with "type": "module" (ESM)
7
+ * - lib/, hooks/, scripts/ directories exist
8
+ * - bun install succeeds (exit code 0)
9
+ */
10
+
11
+ import { existsSync, readFileSync } from "fs";
12
+ import { join } from "path";
13
+ import { execSync } from "child_process";
14
+
15
+ const SKILL_DIR = new URL("../", import.meta.url).pathname.replace(/^\/([A-Za-z]:)/, "$1");
16
+ const PKG_FILE = join(SKILL_DIR, "package.json");
17
+
18
+ function readPkg() {
19
+ return JSON.parse(readFileSync(PKG_FILE, "utf8"));
20
+ }
21
+
22
+ // Test 1: package.json must exist
23
+ const test1 = () => {
24
+ if (!existsSync(PKG_FILE)) {
25
+ throw new Error(`package.json does not exist at: ${PKG_FILE}`);
26
+ }
27
+ console.log("PASS: package.json exists");
28
+ };
29
+
30
+ // Test 2: package.json must have "type": "module"
31
+ const test2 = () => {
32
+ const pkg = readPkg();
33
+ if (pkg.type !== "module") {
34
+ throw new Error(`Expected "type": "module" in package.json, got: "${pkg.type}"`);
35
+ }
36
+ console.log('PASS: package.json has "type": "module"');
37
+ };
38
+
39
+ // Test 3: package.json must have a name field
40
+ const test3 = () => {
41
+ const pkg = readPkg();
42
+ if (!pkg.name) {
43
+ throw new Error("package.json missing 'name' field");
44
+ }
45
+ console.log(`PASS: package.json name = "${pkg.name}"`);
46
+ };
47
+
48
+ // Test 4: lib/ directory must exist
49
+ const test4 = () => {
50
+ const libDir = join(SKILL_DIR, "lib");
51
+ if (!existsSync(libDir)) {
52
+ throw new Error(`lib/ directory does not exist at: ${libDir}`);
53
+ }
54
+ console.log("PASS: lib/ directory exists");
55
+ };
56
+
57
+ // Test 5: hooks/ directory must exist
58
+ const test5 = () => {
59
+ const hooksDir = join(SKILL_DIR, "hooks");
60
+ if (!existsSync(hooksDir)) {
61
+ throw new Error(`hooks/ directory does not exist at: ${hooksDir}`);
62
+ }
63
+ console.log("PASS: hooks/ directory exists");
64
+ };
65
+
66
+ // Test 6: scripts/ directory must exist
67
+ const test6 = () => {
68
+ const scriptsDir = join(SKILL_DIR, "scripts");
69
+ if (!existsSync(scriptsDir)) {
70
+ throw new Error(`scripts/ directory does not exist at: ${scriptsDir}`);
71
+ }
72
+ console.log("PASS: scripts/ directory exists");
73
+ };
74
+
75
+ // Test 7: package.json scripts must include "test"
76
+ const test7 = () => {
77
+ const pkg = readPkg();
78
+ if (!pkg.scripts || !pkg.scripts.test) {
79
+ throw new Error("package.json missing scripts.test");
80
+ }
81
+ console.log(`PASS: package.json scripts.test = "${pkg.scripts.test}"`);
82
+ };
83
+
84
+ // Run all tests
85
+ let failed = 0;
86
+ const tests = [test1, test2, test3, test4, test5, test6, test7];
87
+ for (const t of tests) {
88
+ try {
89
+ t();
90
+ } catch (e) {
91
+ console.error(`FAIL: ${e.message}`);
92
+ failed++;
93
+ }
94
+ }
95
+
96
+ console.log(`\nResults: ${tests.length - failed}/${tests.length} passed`);
97
+ process.exit(failed > 0 ? 1 : 0);