@moreih29/nexus-core 0.13.0 → 0.14.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 (158) hide show
  1. package/README.md +34 -0
  2. package/dist/assets/hooks/agent-bootstrap/handler.d.ts +4 -0
  3. package/dist/assets/hooks/agent-bootstrap/handler.d.ts.map +1 -0
  4. package/dist/assets/hooks/agent-bootstrap/handler.js +100 -0
  5. package/dist/assets/hooks/agent-bootstrap/handler.js.map +1 -0
  6. package/dist/assets/hooks/agent-finalize/handler.d.ts +4 -0
  7. package/dist/assets/hooks/agent-finalize/handler.d.ts.map +1 -0
  8. package/dist/assets/hooks/agent-finalize/handler.js +63 -0
  9. package/dist/assets/hooks/agent-finalize/handler.js.map +1 -0
  10. package/dist/assets/hooks/post-tool-telemetry/handler.d.ts +4 -0
  11. package/dist/assets/hooks/post-tool-telemetry/handler.d.ts.map +1 -0
  12. package/dist/assets/hooks/post-tool-telemetry/handler.js +40 -0
  13. package/dist/assets/hooks/post-tool-telemetry/handler.js.map +1 -0
  14. package/dist/assets/hooks/prompt-router/handler.d.ts +4 -0
  15. package/dist/assets/hooks/prompt-router/handler.d.ts.map +1 -0
  16. package/dist/assets/hooks/prompt-router/handler.js +204 -0
  17. package/dist/assets/hooks/prompt-router/handler.js.map +1 -0
  18. package/dist/assets/hooks/session-init/handler.d.ts +4 -0
  19. package/dist/assets/hooks/session-init/handler.d.ts.map +1 -0
  20. package/dist/assets/hooks/session-init/handler.js +23 -0
  21. package/dist/assets/hooks/session-init/handler.js.map +1 -0
  22. package/dist/hooks/agent-bootstrap.js +105 -0
  23. package/dist/hooks/agent-finalize.js +164 -0
  24. package/dist/hooks/post-tool-telemetry.js +55 -0
  25. package/dist/hooks/prompt-router.js +7300 -0
  26. package/dist/hooks/session-init.js +21 -0
  27. package/dist/manifests/claude-hooks.json +52 -0
  28. package/dist/manifests/codex-hooks.json +28 -0
  29. package/dist/manifests/opencode-manifest.json +44 -0
  30. package/dist/manifests/portability-report.json +87 -0
  31. package/dist/scripts/build-agents.d.ts +157 -0
  32. package/dist/scripts/build-agents.d.ts.map +1 -0
  33. package/dist/scripts/build-agents.js +737 -0
  34. package/dist/scripts/build-agents.js.map +1 -0
  35. package/dist/scripts/build-hooks.d.ts +16 -0
  36. package/dist/scripts/build-hooks.d.ts.map +1 -0
  37. package/dist/scripts/build-hooks.js +388 -0
  38. package/dist/scripts/build-hooks.js.map +1 -0
  39. package/dist/scripts/cli.d.ts +54 -0
  40. package/dist/scripts/cli.d.ts.map +1 -0
  41. package/dist/scripts/cli.js +467 -0
  42. package/dist/scripts/cli.js.map +1 -0
  43. package/dist/src/hooks/opencode-mount.d.ts.map +1 -0
  44. package/dist/{hooks → src/hooks}/opencode-mount.js +26 -6
  45. package/dist/src/hooks/opencode-mount.js.map +1 -0
  46. package/dist/src/hooks/runtime.d.ts.map +1 -0
  47. package/dist/src/hooks/runtime.js.map +1 -0
  48. package/dist/src/hooks/types.d.ts.map +1 -0
  49. package/dist/src/hooks/types.js.map +1 -0
  50. package/dist/src/lsp/cache.d.ts.map +1 -0
  51. package/dist/src/lsp/cache.js.map +1 -0
  52. package/dist/src/lsp/client.d.ts.map +1 -0
  53. package/dist/src/lsp/client.js.map +1 -0
  54. package/dist/src/lsp/detect.d.ts.map +1 -0
  55. package/dist/src/lsp/detect.js.map +1 -0
  56. package/dist/src/mcp/server.d.ts.map +1 -0
  57. package/dist/src/mcp/server.js.map +1 -0
  58. package/dist/src/mcp/tools/artifact.d.ts.map +1 -0
  59. package/dist/src/mcp/tools/artifact.js.map +1 -0
  60. package/dist/src/mcp/tools/history.d.ts.map +1 -0
  61. package/dist/src/mcp/tools/history.js.map +1 -0
  62. package/dist/src/mcp/tools/lsp.d.ts.map +1 -0
  63. package/dist/src/mcp/tools/lsp.js.map +1 -0
  64. package/dist/src/mcp/tools/plan.d.ts.map +1 -0
  65. package/dist/src/mcp/tools/plan.js.map +1 -0
  66. package/dist/src/mcp/tools/task.d.ts.map +1 -0
  67. package/dist/src/mcp/tools/task.js.map +1 -0
  68. package/dist/src/shared/invocations.d.ts.map +1 -0
  69. package/dist/src/shared/invocations.js.map +1 -0
  70. package/dist/src/shared/json-store.d.ts.map +1 -0
  71. package/dist/src/shared/json-store.js.map +1 -0
  72. package/dist/src/shared/mcp-utils.d.ts.map +1 -0
  73. package/dist/src/shared/mcp-utils.js.map +1 -0
  74. package/dist/src/shared/paths.d.ts.map +1 -0
  75. package/dist/src/shared/paths.js.map +1 -0
  76. package/dist/src/shared/tool-log.d.ts.map +1 -0
  77. package/dist/src/shared/tool-log.js.map +1 -0
  78. package/dist/src/types/state.d.ts.map +1 -0
  79. package/dist/src/types/state.js.map +1 -0
  80. package/docs/plugin-guide.md +36 -0
  81. package/package.json +25 -17
  82. package/dist/hooks/opencode-mount.d.ts.map +0 -1
  83. package/dist/hooks/opencode-mount.js.map +0 -1
  84. package/dist/hooks/runtime.d.ts.map +0 -1
  85. package/dist/hooks/runtime.js.map +0 -1
  86. package/dist/hooks/types.d.ts.map +0 -1
  87. package/dist/hooks/types.js.map +0 -1
  88. package/dist/lsp/cache.d.ts.map +0 -1
  89. package/dist/lsp/cache.js.map +0 -1
  90. package/dist/lsp/client.d.ts.map +0 -1
  91. package/dist/lsp/client.js.map +0 -1
  92. package/dist/lsp/detect.d.ts.map +0 -1
  93. package/dist/lsp/detect.js.map +0 -1
  94. package/dist/mcp/server.d.ts.map +0 -1
  95. package/dist/mcp/server.js.map +0 -1
  96. package/dist/mcp/tools/artifact.d.ts.map +0 -1
  97. package/dist/mcp/tools/artifact.js.map +0 -1
  98. package/dist/mcp/tools/history.d.ts.map +0 -1
  99. package/dist/mcp/tools/history.js.map +0 -1
  100. package/dist/mcp/tools/lsp.d.ts.map +0 -1
  101. package/dist/mcp/tools/lsp.js.map +0 -1
  102. package/dist/mcp/tools/plan.d.ts.map +0 -1
  103. package/dist/mcp/tools/plan.js.map +0 -1
  104. package/dist/mcp/tools/task.d.ts.map +0 -1
  105. package/dist/mcp/tools/task.js.map +0 -1
  106. package/dist/shared/invocations.d.ts.map +0 -1
  107. package/dist/shared/invocations.js.map +0 -1
  108. package/dist/shared/json-store.d.ts.map +0 -1
  109. package/dist/shared/json-store.js.map +0 -1
  110. package/dist/shared/mcp-utils.d.ts.map +0 -1
  111. package/dist/shared/mcp-utils.js.map +0 -1
  112. package/dist/shared/paths.d.ts.map +0 -1
  113. package/dist/shared/paths.js.map +0 -1
  114. package/dist/shared/tool-log.d.ts.map +0 -1
  115. package/dist/shared/tool-log.js.map +0 -1
  116. package/dist/types/state.d.ts.map +0 -1
  117. package/dist/types/state.js.map +0 -1
  118. package/scripts/build-agents.test.ts +0 -1279
  119. package/scripts/build-agents.ts +0 -978
  120. package/scripts/build-hooks.test.ts +0 -1385
  121. package/scripts/build-hooks.ts +0 -584
  122. package/scripts/cli.test.ts +0 -367
  123. package/scripts/cli.ts +0 -547
  124. /package/dist/{hooks → src/hooks}/opencode-mount.d.ts +0 -0
  125. /package/dist/{hooks → src/hooks}/runtime.d.ts +0 -0
  126. /package/dist/{hooks → src/hooks}/runtime.js +0 -0
  127. /package/dist/{hooks → src/hooks}/types.d.ts +0 -0
  128. /package/dist/{hooks → src/hooks}/types.js +0 -0
  129. /package/dist/{lsp → src/lsp}/cache.d.ts +0 -0
  130. /package/dist/{lsp → src/lsp}/cache.js +0 -0
  131. /package/dist/{lsp → src/lsp}/client.d.ts +0 -0
  132. /package/dist/{lsp → src/lsp}/client.js +0 -0
  133. /package/dist/{lsp → src/lsp}/detect.d.ts +0 -0
  134. /package/dist/{lsp → src/lsp}/detect.js +0 -0
  135. /package/dist/{mcp → src/mcp}/server.d.ts +0 -0
  136. /package/dist/{mcp → src/mcp}/server.js +0 -0
  137. /package/dist/{mcp → src/mcp}/tools/artifact.d.ts +0 -0
  138. /package/dist/{mcp → src/mcp}/tools/artifact.js +0 -0
  139. /package/dist/{mcp → src/mcp}/tools/history.d.ts +0 -0
  140. /package/dist/{mcp → src/mcp}/tools/history.js +0 -0
  141. /package/dist/{mcp → src/mcp}/tools/lsp.d.ts +0 -0
  142. /package/dist/{mcp → src/mcp}/tools/lsp.js +0 -0
  143. /package/dist/{mcp → src/mcp}/tools/plan.d.ts +0 -0
  144. /package/dist/{mcp → src/mcp}/tools/plan.js +0 -0
  145. /package/dist/{mcp → src/mcp}/tools/task.d.ts +0 -0
  146. /package/dist/{mcp → src/mcp}/tools/task.js +0 -0
  147. /package/dist/{shared → src/shared}/invocations.d.ts +0 -0
  148. /package/dist/{shared → src/shared}/invocations.js +0 -0
  149. /package/dist/{shared → src/shared}/json-store.d.ts +0 -0
  150. /package/dist/{shared → src/shared}/json-store.js +0 -0
  151. /package/dist/{shared → src/shared}/mcp-utils.d.ts +0 -0
  152. /package/dist/{shared → src/shared}/mcp-utils.js +0 -0
  153. /package/dist/{shared → src/shared}/paths.d.ts +0 -0
  154. /package/dist/{shared → src/shared}/paths.js +0 -0
  155. /package/dist/{shared → src/shared}/tool-log.d.ts +0 -0
  156. /package/dist/{shared → src/shared}/tool-log.js +0 -0
  157. /package/dist/{types → src/types}/state.d.ts +0 -0
  158. /package/dist/{types → src/types}/state.js +0 -0
@@ -1,367 +0,0 @@
1
- /**
2
- * scripts/cli.test.ts
3
- *
4
- * Unit tests for scripts/cli.ts
5
- *
6
- * Scenarios:
7
- * (1) parseFlags — flag parsing for all recognized flags
8
- * (2) main() routing — each subcommand dispatches correctly
9
- * (3) runList() — returns correct agent/skill/hook counts
10
- * (4) runValidateSync() — passes on real assets
11
- * (5) runValidateSync() — catches missing required fields
12
- * (6) main() unknown command — exits with error
13
- */
14
-
15
- import { describe, test, expect, beforeEach, afterEach, mock } from "bun:test";
16
- import {
17
- mkdirSync,
18
- mkdtempSync,
19
- rmSync,
20
- writeFileSync,
21
- } from "node:fs";
22
- import { join } from "node:path";
23
- import { tmpdir } from "node:os";
24
-
25
- import {
26
- parseFlags,
27
- collectListEntries,
28
- runValidateSync,
29
- main,
30
- ROOT,
31
- type ParsedFlags,
32
- } from "./cli.js";
33
-
34
- // ---------------------------------------------------------------------------
35
- // (1) parseFlags
36
- // ---------------------------------------------------------------------------
37
-
38
- describe("parseFlags", () => {
39
- test("defaults when no args", () => {
40
- const flags = parseFlags([]);
41
- expect(flags.dryRun).toBe(false);
42
- expect(flags.force).toBe(false);
43
- expect(flags.strict).toBe(false);
44
- expect(flags.help).toBe(false);
45
- expect(flags.harness).toBeUndefined();
46
- expect(flags.target).toBeUndefined();
47
- expect(flags.only).toBeUndefined();
48
- expect(flags.remaining).toEqual([]);
49
- });
50
-
51
- test("--dry-run", () => {
52
- const flags = parseFlags(["--dry-run"]);
53
- expect(flags.dryRun).toBe(true);
54
- });
55
-
56
- test("--force", () => {
57
- const flags = parseFlags(["--force"]);
58
- expect(flags.force).toBe(true);
59
- });
60
-
61
- test("--strict", () => {
62
- const flags = parseFlags(["--strict"]);
63
- expect(flags.strict).toBe(true);
64
- });
65
-
66
- test("--help", () => {
67
- const flags = parseFlags(["--help"]);
68
- expect(flags.help).toBe(true);
69
- });
70
-
71
- test("-h short alias", () => {
72
- const flags = parseFlags(["-h"]);
73
- expect(flags.help).toBe(true);
74
- });
75
-
76
- test("--harness=claude", () => {
77
- const flags = parseFlags(["--harness=claude"]);
78
- expect(flags.harness).toBe("claude");
79
- });
80
-
81
- test("--target resolves to absolute path", () => {
82
- const flags = parseFlags(["--target=/tmp/test-dir"]);
83
- expect(flags.target).toBe("/tmp/test-dir");
84
- });
85
-
86
- test("--only=engineer", () => {
87
- const flags = parseFlags(["--only=engineer"]);
88
- expect(flags.only).toBe("engineer");
89
- });
90
-
91
- test("unknown args go to remaining", () => {
92
- const flags = parseFlags(["--unknown-flag", "positional"]);
93
- expect(flags.remaining).toContain("--unknown-flag");
94
- expect(flags.remaining).toContain("positional");
95
- });
96
-
97
- test("multiple flags together", () => {
98
- const flags = parseFlags([
99
- "--harness=opencode",
100
- "--target=/tmp/out",
101
- "--dry-run",
102
- "--force",
103
- "--strict",
104
- "--only=architect",
105
- ]);
106
- expect(flags.harness).toBe("opencode");
107
- expect(flags.target).toBe("/tmp/out");
108
- expect(flags.dryRun).toBe(true);
109
- expect(flags.force).toBe(true);
110
- expect(flags.strict).toBe(true);
111
- expect(flags.only).toBe("architect");
112
- });
113
- });
114
-
115
- // ---------------------------------------------------------------------------
116
- // (2) main() routing — help messages
117
- // ---------------------------------------------------------------------------
118
-
119
- describe("main() routing", () => {
120
- test("--help prints help without error", async () => {
121
- const lines: string[] = [];
122
- const origLog = console.log;
123
- console.log = (...args: unknown[]) => lines.push(args.join(" "));
124
-
125
- try {
126
- await main(["--help"]);
127
- } finally {
128
- console.log = origLog;
129
- }
130
-
131
- const output = lines.join("\n");
132
- expect(output).toContain("nexus-core");
133
- expect(output).toContain("sync");
134
- expect(output).toContain("init");
135
- expect(output).toContain("list");
136
- expect(output).toContain("validate");
137
- expect(output).toContain("mcp");
138
- });
139
-
140
- test("no args prints help without error", async () => {
141
- const lines: string[] = [];
142
- const origLog = console.log;
143
- console.log = (...args: unknown[]) => lines.push(args.join(" "));
144
-
145
- try {
146
- await main([]);
147
- } finally {
148
- console.log = origLog;
149
- }
150
-
151
- expect(lines.join("\n")).toContain("nexus-core");
152
- });
153
-
154
- test("sync --help prints sync help", async () => {
155
- const lines: string[] = [];
156
- const origLog = console.log;
157
- console.log = (...args: unknown[]) => lines.push(args.join(" "));
158
-
159
- try {
160
- await main(["sync", "--help"]);
161
- } finally {
162
- console.log = origLog;
163
- }
164
-
165
- const output = lines.join("\n");
166
- expect(output).toContain("--harness");
167
- expect(output).toContain("--target");
168
- expect(output).toContain("--dry-run");
169
- });
170
-
171
- test("init --help prints init help", async () => {
172
- const lines: string[] = [];
173
- const origLog = console.log;
174
- console.log = (...args: unknown[]) => lines.push(args.join(" "));
175
-
176
- try {
177
- await main(["init", "--help"]);
178
- } finally {
179
- console.log = origLog;
180
- }
181
-
182
- expect(lines.join("\n")).toContain("--target");
183
- });
184
-
185
- test("list --help prints list help", async () => {
186
- const lines: string[] = [];
187
- const origLog = console.log;
188
- console.log = (...args: unknown[]) => lines.push(args.join(" "));
189
-
190
- try {
191
- await main(["list", "--help"]);
192
- } finally {
193
- console.log = origLog;
194
- }
195
-
196
- expect(lines.join("\n")).toContain("list");
197
- });
198
-
199
- test("validate --help prints validate help", async () => {
200
- const lines: string[] = [];
201
- const origLog = console.log;
202
- console.log = (...args: unknown[]) => lines.push(args.join(" "));
203
-
204
- try {
205
- await main(["validate", "--help"]);
206
- } finally {
207
- console.log = origLog;
208
- }
209
-
210
- expect(lines.join("\n")).toContain("validate");
211
- });
212
-
213
- test("mcp --help prints mcp help", async () => {
214
- const lines: string[] = [];
215
- const origLog = console.log;
216
- console.log = (...args: unknown[]) => lines.push(args.join(" "));
217
-
218
- try {
219
- await main(["mcp", "--help"]);
220
- } finally {
221
- console.log = origLog;
222
- }
223
-
224
- expect(lines.join("\n")).toContain("mcp");
225
- });
226
-
227
- test("unknown command exits with code 1", async () => {
228
- const origExit = process.exit;
229
- let exitCode: number | undefined;
230
- // @ts-ignore — mock process.exit
231
- process.exit = (code?: number) => {
232
- exitCode = code;
233
- throw new Error(`process.exit(${code})`);
234
- };
235
-
236
- try {
237
- await main(["unknowncmd"]);
238
- } catch {
239
- // expected
240
- } finally {
241
- process.exit = origExit;
242
- }
243
-
244
- expect(exitCode).toBe(1);
245
- });
246
- });
247
-
248
- // ---------------------------------------------------------------------------
249
- // (3) collectListEntries — real assets
250
- // ---------------------------------------------------------------------------
251
-
252
- describe("collectListEntries (real assets)", () => {
253
- test("returns 10 agents from assets/agents/", () => {
254
- const entries = collectListEntries();
255
- const agents = entries.filter((e) => e.kind === "agent");
256
- expect(agents.length).toBe(10);
257
- });
258
-
259
- test("returns 4 skills from assets/skills/", () => {
260
- const entries = collectListEntries();
261
- const skills = entries.filter((e) => e.kind === "skill");
262
- expect(skills.length).toBe(4);
263
- });
264
-
265
- test("returns hooks from assets/hooks/", () => {
266
- const entries = collectListEntries();
267
- const hooks = entries.filter((e) => e.kind === "hook");
268
- expect(hooks.length).toBeGreaterThan(0);
269
- });
270
-
271
- test("each agent entry has a name and description", () => {
272
- const entries = collectListEntries();
273
- const agents = entries.filter((e) => e.kind === "agent");
274
- for (const a of agents) {
275
- expect(a.name.length).toBeGreaterThan(0);
276
- expect(typeof a.description).toBe("string");
277
- }
278
- });
279
-
280
- test("known agent 'engineer' is present", () => {
281
- const entries = collectListEntries();
282
- const engineer = entries.find((e) => e.kind === "agent" && e.name === "engineer");
283
- expect(engineer).toBeDefined();
284
- expect(engineer?.description).toContain("Implementation");
285
- });
286
- });
287
-
288
- // ---------------------------------------------------------------------------
289
- // (4) runValidateSync — real assets pass
290
- // ---------------------------------------------------------------------------
291
-
292
- describe("runValidateSync (real assets)", () => {
293
- test("passes with no errors on current assets", () => {
294
- const result = runValidateSync();
295
- expect(result.errors).toEqual([]);
296
- expect(result.ok).toBe(true);
297
- expect(result.checked).toBeGreaterThan(0);
298
- });
299
-
300
- test("checked count equals agents + skills + 2 YAML files", () => {
301
- const result = runValidateSync();
302
- // 9 agents + 4 skills + capability-matrix.yml + tool-name-map.yml = 15
303
- expect(result.checked).toBeGreaterThanOrEqual(15);
304
- });
305
- });
306
-
307
- // ---------------------------------------------------------------------------
308
- // (5) runValidateSync — error detection on bad assets
309
- // ---------------------------------------------------------------------------
310
-
311
- describe("runValidateSync (bad assets in tmp)", () => {
312
- let tmpDir: string;
313
-
314
- beforeEach(() => {
315
- tmpDir = mkdtempSync(join(tmpdir(), "nexus-cli-validate-"));
316
- });
317
-
318
- afterEach(() => {
319
- rmSync(tmpDir, { recursive: true, force: true });
320
- });
321
-
322
- test("detects missing frontmatter in agent body.md", () => {
323
- // Create a fake agents dir entry with malformed body.md
324
- const agentsDir = join(tmpDir, "agents", "bad-agent");
325
- mkdirSync(agentsDir, { recursive: true });
326
- writeFileSync(join(agentsDir, "body.md"), "no frontmatter here\n");
327
-
328
- // We test the parseFrontmatterRaw logic indirectly by verifying
329
- // that a real body.md without --- delimiters is detected as invalid
330
- const { parseFrontmatterRaw: _unused, ...rest } = {
331
- parseFrontmatterRaw: null,
332
- };
333
-
334
- // Validate using real assets — the real check should still pass
335
- const result = runValidateSync();
336
- expect(result.ok).toBe(true);
337
- });
338
-
339
- test("runValidateSync passes when no errors on real repo", () => {
340
- const result = runValidateSync();
341
- expect(result.ok).toBe(true);
342
- expect(result.errors.length).toBe(0);
343
- });
344
- });
345
-
346
- // ---------------------------------------------------------------------------
347
- // (6) runList output
348
- // ---------------------------------------------------------------------------
349
-
350
- describe("runList output", () => {
351
- test("prints agents header with count 9", async () => {
352
- const lines: string[] = [];
353
- const origLog = console.log;
354
- console.log = (...args: unknown[]) => lines.push(args.join(" "));
355
-
356
- try {
357
- await main(["list"]);
358
- } finally {
359
- console.log = origLog;
360
- }
361
-
362
- const output = lines.join("\n");
363
- expect(output).toContain("Agents (10)");
364
- expect(output).toContain("Skills (4)");
365
- expect(output).toContain("Hooks");
366
- });
367
- });