@namzu/cli 2.0.0 → 2.2.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 (176) hide show
  1. package/dist/tui/App.d.ts.map +1 -1
  2. package/dist/tui/App.js +22 -2
  3. package/dist/tui/App.js.map +1 -1
  4. package/dist/tui/agent.d.ts +10 -0
  5. package/dist/tui/agent.d.ts.map +1 -1
  6. package/dist/tui/agent.js +10 -0
  7. package/dist/tui/agent.js.map +1 -1
  8. package/dist/tui/slashCommands.d.ts +83 -0
  9. package/dist/tui/slashCommands.d.ts.map +1 -1
  10. package/dist/tui/slashCommands.js +157 -0
  11. package/dist/tui/slashCommands.js.map +1 -1
  12. package/package.json +11 -6
  13. package/dist/__tests__/environment-reaches-the-turn.test.d.ts +0 -17
  14. package/dist/__tests__/environment-reaches-the-turn.test.d.ts.map +0 -1
  15. package/dist/__tests__/environment-reaches-the-turn.test.js +0 -128
  16. package/dist/__tests__/environment-reaches-the-turn.test.js.map +0 -1
  17. package/dist/__tests__/headless-trust-gate.test.d.ts +0 -23
  18. package/dist/__tests__/headless-trust-gate.test.d.ts.map +0 -1
  19. package/dist/__tests__/headless-trust-gate.test.js +0 -227
  20. package/dist/__tests__/headless-trust-gate.test.js.map +0 -1
  21. package/dist/__tests__/mcp-servers-reach-the-session.test.d.ts +0 -17
  22. package/dist/__tests__/mcp-servers-reach-the-session.test.d.ts.map +0 -1
  23. package/dist/__tests__/mcp-servers-reach-the-session.test.js +0 -171
  24. package/dist/__tests__/mcp-servers-reach-the-session.test.js.map +0 -1
  25. package/dist/__tests__/permission-rules-reach-the-turn.test.d.ts +0 -31
  26. package/dist/__tests__/permission-rules-reach-the-turn.test.d.ts.map +0 -1
  27. package/dist/__tests__/permission-rules-reach-the-turn.test.js +0 -132
  28. package/dist/__tests__/permission-rules-reach-the-turn.test.js.map +0 -1
  29. package/dist/__tests__/project-instructions-reach-the-turn.test.d.ts +0 -24
  30. package/dist/__tests__/project-instructions-reach-the-turn.test.d.ts.map +0 -1
  31. package/dist/__tests__/project-instructions-reach-the-turn.test.js +0 -153
  32. package/dist/__tests__/project-instructions-reach-the-turn.test.js.map +0 -1
  33. package/dist/cli.test.d.ts +0 -2
  34. package/dist/cli.test.d.ts.map +0 -1
  35. package/dist/cli.test.js +0 -108
  36. package/dist/cli.test.js.map +0 -1
  37. package/dist/commands/__tests__/eval.test.d.ts +0 -2
  38. package/dist/commands/__tests__/eval.test.d.ts.map +0 -1
  39. package/dist/commands/__tests__/eval.test.js +0 -165
  40. package/dist/commands/__tests__/eval.test.js.map +0 -1
  41. package/dist/commands/__tests__/passthrough-help.test.d.ts +0 -2
  42. package/dist/commands/__tests__/passthrough-help.test.d.ts.map +0 -1
  43. package/dist/commands/__tests__/passthrough-help.test.js +0 -96
  44. package/dist/commands/__tests__/passthrough-help.test.js.map +0 -1
  45. package/dist/commands/__tests__/resume.test.d.ts +0 -15
  46. package/dist/commands/__tests__/resume.test.d.ts.map +0 -1
  47. package/dist/commands/__tests__/resume.test.js +0 -116
  48. package/dist/commands/__tests__/resume.test.js.map +0 -1
  49. package/dist/commands/__tests__/run-exit-code.test.d.ts +0 -2
  50. package/dist/commands/__tests__/run-exit-code.test.d.ts.map +0 -1
  51. package/dist/commands/__tests__/run-exit-code.test.js +0 -100
  52. package/dist/commands/__tests__/run-exit-code.test.js.map +0 -1
  53. package/dist/commands/__tests__/run-flags.test.d.ts +0 -11
  54. package/dist/commands/__tests__/run-flags.test.d.ts.map +0 -1
  55. package/dist/commands/__tests__/run-flags.test.js +0 -238
  56. package/dist/commands/__tests__/run-flags.test.js.map +0 -1
  57. package/dist/commands/__tests__/run-stream-flags.test.d.ts +0 -2
  58. package/dist/commands/__tests__/run-stream-flags.test.d.ts.map +0 -1
  59. package/dist/commands/__tests__/run-stream-flags.test.js +0 -295
  60. package/dist/commands/__tests__/run-stream-flags.test.js.map +0 -1
  61. package/dist/commands/doctor.test.d.ts +0 -2
  62. package/dist/commands/doctor.test.d.ts.map +0 -1
  63. package/dist/commands/doctor.test.js +0 -82
  64. package/dist/commands/doctor.test.js.map +0 -1
  65. package/dist/config/load.test.d.ts +0 -2
  66. package/dist/config/load.test.d.ts.map +0 -1
  67. package/dist/config/load.test.js +0 -57
  68. package/dist/config/load.test.js.map +0 -1
  69. package/dist/context/__tests__/environment.test.d.ts +0 -10
  70. package/dist/context/__tests__/environment.test.d.ts.map +0 -1
  71. package/dist/context/__tests__/environment.test.js +0 -84
  72. package/dist/context/__tests__/environment.test.js.map +0 -1
  73. package/dist/context/__tests__/project.test.d.ts +0 -12
  74. package/dist/context/__tests__/project.test.d.ts.map +0 -1
  75. package/dist/context/__tests__/project.test.js +0 -201
  76. package/dist/context/__tests__/project.test.js.map +0 -1
  77. package/dist/doctor/checks/credentials.test.d.ts +0 -10
  78. package/dist/doctor/checks/credentials.test.d.ts.map +0 -1
  79. package/dist/doctor/checks/credentials.test.js +0 -47
  80. package/dist/doctor/checks/credentials.test.js.map +0 -1
  81. package/dist/doctor/checks/sandbox.test.d.ts +0 -2
  82. package/dist/doctor/checks/sandbox.test.d.ts.map +0 -1
  83. package/dist/doctor/checks/sandbox.test.js +0 -59
  84. package/dist/doctor/checks/sandbox.test.js.map +0 -1
  85. package/dist/doctor/registry.test.d.ts +0 -7
  86. package/dist/doctor/registry.test.d.ts.map +0 -1
  87. package/dist/doctor/registry.test.js +0 -379
  88. package/dist/doctor/registry.test.js.map +0 -1
  89. package/dist/integrations/mcp/__tests__/connect.test.d.ts +0 -11
  90. package/dist/integrations/mcp/__tests__/connect.test.d.ts.map +0 -1
  91. package/dist/integrations/mcp/__tests__/connect.test.js +0 -231
  92. package/dist/integrations/mcp/__tests__/connect.test.js.map +0 -1
  93. package/dist/integrations/providers/discover.test.d.ts +0 -2
  94. package/dist/integrations/providers/discover.test.d.ts.map +0 -1
  95. package/dist/integrations/providers/discover.test.js +0 -93
  96. package/dist/integrations/providers/discover.test.js.map +0 -1
  97. package/dist/integrations/providers/keychain.test.d.ts +0 -2
  98. package/dist/integrations/providers/keychain.test.d.ts.map +0 -1
  99. package/dist/integrations/providers/keychain.test.js +0 -21
  100. package/dist/integrations/providers/keychain.test.js.map +0 -1
  101. package/dist/integrations/providers/oauth.test.d.ts +0 -2
  102. package/dist/integrations/providers/oauth.test.d.ts.map +0 -1
  103. package/dist/integrations/providers/oauth.test.js +0 -86
  104. package/dist/integrations/providers/oauth.test.js.map +0 -1
  105. package/dist/integrations/providers/preferences.test.d.ts +0 -2
  106. package/dist/integrations/providers/preferences.test.d.ts.map +0 -1
  107. package/dist/integrations/providers/preferences.test.js +0 -76
  108. package/dist/integrations/providers/preferences.test.js.map +0 -1
  109. package/dist/integrations/sessions/__tests__/archived-workspace.test.d.ts +0 -21
  110. package/dist/integrations/sessions/__tests__/archived-workspace.test.d.ts.map +0 -1
  111. package/dist/integrations/sessions/__tests__/archived-workspace.test.js +0 -62
  112. package/dist/integrations/sessions/__tests__/archived-workspace.test.js.map +0 -1
  113. package/dist/integrations/subagents/__tests__/delegation-trace.test.d.ts +0 -2
  114. package/dist/integrations/subagents/__tests__/delegation-trace.test.d.ts.map +0 -1
  115. package/dist/integrations/subagents/__tests__/delegation-trace.test.js +0 -114
  116. package/dist/integrations/subagents/__tests__/delegation-trace.test.js.map +0 -1
  117. package/dist/integrations/trust/store.test.d.ts +0 -2
  118. package/dist/integrations/trust/store.test.d.ts.map +0 -1
  119. package/dist/integrations/trust/store.test.js +0 -50
  120. package/dist/integrations/trust/store.test.js.map +0 -1
  121. package/dist/memory/store.test.d.ts +0 -2
  122. package/dist/memory/store.test.d.ts.map +0 -1
  123. package/dist/memory/store.test.js +0 -63
  124. package/dist/memory/store.test.js.map +0 -1
  125. package/dist/output/formatter.test.d.ts +0 -2
  126. package/dist/output/formatter.test.d.ts.map +0 -1
  127. package/dist/output/formatter.test.js +0 -88
  128. package/dist/output/formatter.test.js.map +0 -1
  129. package/dist/output/rendered-payload.test.d.ts +0 -2
  130. package/dist/output/rendered-payload.test.d.ts.map +0 -1
  131. package/dist/output/rendered-payload.test.js +0 -61
  132. package/dist/output/rendered-payload.test.js.map +0 -1
  133. package/dist/permissions/__tests__/mode.test.d.ts +0 -10
  134. package/dist/permissions/__tests__/mode.test.d.ts.map +0 -1
  135. package/dist/permissions/__tests__/mode.test.js +0 -115
  136. package/dist/permissions/__tests__/mode.test.js.map +0 -1
  137. package/dist/permissions/__tests__/rules.test.d.ts +0 -10
  138. package/dist/permissions/__tests__/rules.test.d.ts.map +0 -1
  139. package/dist/permissions/__tests__/rules.test.js +0 -196
  140. package/dist/permissions/__tests__/rules.test.js.map +0 -1
  141. package/dist/skills/store.test.d.ts +0 -2
  142. package/dist/skills/store.test.d.ts.map +0 -1
  143. package/dist/skills/store.test.js +0 -80
  144. package/dist/skills/store.test.js.map +0 -1
  145. package/dist/tui/__tests__/context-gauge.test.d.ts +0 -2
  146. package/dist/tui/__tests__/context-gauge.test.d.ts.map +0 -1
  147. package/dist/tui/__tests__/context-gauge.test.js +0 -83
  148. package/dist/tui/__tests__/context-gauge.test.js.map +0 -1
  149. package/dist/tui/__tests__/deferred-tool-discovery.test.d.ts +0 -24
  150. package/dist/tui/__tests__/deferred-tool-discovery.test.d.ts.map +0 -1
  151. package/dist/tui/__tests__/deferred-tool-discovery.test.js +0 -111
  152. package/dist/tui/__tests__/deferred-tool-discovery.test.js.map +0 -1
  153. package/dist/tui/__tests__/to-agent-event.test.d.ts +0 -2
  154. package/dist/tui/__tests__/to-agent-event.test.d.ts.map +0 -1
  155. package/dist/tui/__tests__/to-agent-event.test.js +0 -230
  156. package/dist/tui/__tests__/to-agent-event.test.js.map +0 -1
  157. package/dist/tui/__tests__/working-directory.test.d.ts +0 -13
  158. package/dist/tui/__tests__/working-directory.test.d.ts.map +0 -1
  159. package/dist/tui/__tests__/working-directory.test.js +0 -109
  160. package/dist/tui/__tests__/working-directory.test.js.map +0 -1
  161. package/dist/tui/agent.test.d.ts +0 -2
  162. package/dist/tui/agent.test.d.ts.map +0 -1
  163. package/dist/tui/agent.test.js +0 -225
  164. package/dist/tui/agent.test.js.map +0 -1
  165. package/dist/tui/markdownParser.test.d.ts +0 -2
  166. package/dist/tui/markdownParser.test.d.ts.map +0 -1
  167. package/dist/tui/markdownParser.test.js +0 -90
  168. package/dist/tui/markdownParser.test.js.map +0 -1
  169. package/dist/tui/mentions.test.d.ts +0 -2
  170. package/dist/tui/mentions.test.d.ts.map +0 -1
  171. package/dist/tui/mentions.test.js +0 -35
  172. package/dist/tui/mentions.test.js.map +0 -1
  173. package/dist/tui/slashCommands.test.d.ts +0 -2
  174. package/dist/tui/slashCommands.test.d.ts.map +0 -1
  175. package/dist/tui/slashCommands.test.js +0 -114
  176. package/dist/tui/slashCommands.test.js.map +0 -1
@@ -1,379 +0,0 @@
1
- /**
2
- * Ratified in ses_007-probe-and-doctor §9 (agent working memory, gitignored).
3
- * D4 = registerDoctorCheck + plugin auto-discovery + standalone-CLI /
4
- * embedded-runDoctor split. D5 = sysexits exit codes (0/1/2/70).
5
- */
6
- import { describe, expect, it } from 'vitest';
7
- import { createDoctorRegistry, runDoctor } from './registry.js';
8
- function check(id, result, category = 'custom') {
9
- return {
10
- id,
11
- category,
12
- run: async () => result,
13
- };
14
- }
15
- describe('DoctorRegistry — registration', () => {
16
- it('register + list returns the registered check', () => {
17
- const reg = createDoctorRegistry();
18
- const c = check('a', { status: 'pass' });
19
- reg.register(c);
20
- expect(reg.list()).toEqual([c]);
21
- });
22
- it('throws when registering a duplicate id without unregister', () => {
23
- const reg = createDoctorRegistry();
24
- reg.register(check('dup', { status: 'pass' }));
25
- expect(() => reg.register(check('dup', { status: 'pass' }))).toThrow(/already registered/);
26
- });
27
- it('unregister removes the check', () => {
28
- const reg = createDoctorRegistry();
29
- reg.register(check('x', { status: 'pass' }));
30
- expect(reg.unregister('x')).toBe(true);
31
- expect(reg.list()).toEqual([]);
32
- });
33
- it('clear removes everything', () => {
34
- const reg = createDoctorRegistry();
35
- reg.register(check('a', { status: 'pass' }));
36
- reg.register(check('b', { status: 'fail' }));
37
- reg.clear();
38
- expect(reg.list()).toEqual([]);
39
- });
40
- });
41
- describe('runDoctor — aggregation + summary', () => {
42
- it('aggregates check results into a DoctorReport with the right summary', async () => {
43
- const reg = createDoctorRegistry();
44
- reg.register(check('a', { status: 'pass' }));
45
- reg.register(check('b', { status: 'fail', message: 'broken' }));
46
- reg.register(check('c', { status: 'inconclusive' }));
47
- reg.register(check('d', { status: 'warn' }));
48
- const report = await runDoctor({ registry: reg, version: '0.0.1' });
49
- expect(report.summary).toEqual({
50
- pass: 1,
51
- fail: 1,
52
- inconclusive: 1,
53
- warn: 1,
54
- total: 4,
55
- });
56
- expect(report.checks).toHaveLength(4);
57
- expect(report.version).toBe('0.0.1');
58
- });
59
- it('exit = 0 when all pass / no fail', async () => {
60
- const reg = createDoctorRegistry();
61
- reg.register(check('a', { status: 'pass' }));
62
- reg.register(check('b', { status: 'inconclusive' }));
63
- reg.register(check('c', { status: 'warn' }));
64
- const report = await runDoctor({ registry: reg });
65
- expect(report.exit).toBe(0);
66
- });
67
- it('exit = 1 when any check fails', async () => {
68
- const reg = createDoctorRegistry();
69
- reg.register(check('a', { status: 'pass' }));
70
- reg.register(check('b', { status: 'fail' }));
71
- const report = await runDoctor({ registry: reg });
72
- expect(report.exit).toBe(1);
73
- });
74
- it('exit = 2 (no config) when no checks registered', async () => {
75
- const reg = createDoctorRegistry();
76
- const report = await runDoctor({ registry: reg });
77
- expect(report.exit).toBe(2);
78
- expect(report.summary.total).toBe(0);
79
- });
80
- it('inconclusive + warn do not affect exit code', async () => {
81
- const reg = createDoctorRegistry();
82
- reg.register(check('a', { status: 'inconclusive' }));
83
- reg.register(check('b', { status: 'warn' }));
84
- const report = await runDoctor({ registry: reg });
85
- expect(report.exit).toBe(0);
86
- });
87
- });
88
- describe('runDoctor — failure isolation', () => {
89
- it('a throwing check is reported as fail; other checks still run', async () => {
90
- const reg = createDoctorRegistry();
91
- reg.register({
92
- id: 'thrower',
93
- category: 'custom',
94
- run: async () => {
95
- throw new Error('boom');
96
- },
97
- });
98
- reg.register(check('ok', { status: 'pass' }));
99
- const report = await runDoctor({ registry: reg });
100
- expect(report.summary.total).toBe(2);
101
- expect(report.summary.fail).toBe(1);
102
- expect(report.summary.pass).toBe(1);
103
- const thrower = report.checks.find((r) => r.id === 'thrower');
104
- expect(thrower?.status).toBe('fail');
105
- expect(thrower?.message).toMatch(/boom/);
106
- });
107
- it('a slow check that exceeds perCheckTimeoutMs is recorded as inconclusive', async () => {
108
- const reg = createDoctorRegistry();
109
- reg.register({
110
- id: 'slow',
111
- category: 'custom',
112
- run: () => new Promise((resolve) => setTimeout(() => resolve({ status: 'pass' }), 200)),
113
- });
114
- const report = await runDoctor({ registry: reg, perCheckTimeoutMs: 30 });
115
- expect(report.summary.total).toBe(1);
116
- const slow = report.checks[0];
117
- expect(slow?.status).toBe('inconclusive');
118
- expect(slow?.message).toMatch(/did not return within 30ms/);
119
- });
120
- });
121
- describe('runDoctor — wall-clock timeout preserves completed records (ses_013 C5 fix)', () => {
122
- it('fast pass + slow check exceeding wall budget → 1 pass + 1 inconclusive (NOT 2 inconclusive)', async () => {
123
- const reg = createDoctorRegistry();
124
- reg.register({
125
- id: 'fast',
126
- category: 'custom',
127
- run: async () => ({ status: 'pass', message: 'instantly done' }),
128
- });
129
- reg.register({
130
- id: 'slow',
131
- category: 'custom',
132
- run: () => new Promise((resolve) => setTimeout(() => resolve({ status: 'pass' }), 200)),
133
- });
134
- const report = await runDoctor({
135
- registry: reg,
136
- wallClockTimeoutMs: 50,
137
- perCheckTimeoutMs: 1000,
138
- });
139
- expect(report.summary.total).toBe(2);
140
- expect(report.summary.pass).toBe(1);
141
- expect(report.summary.inconclusive).toBe(1);
142
- const fast = report.checks.find((r) => r.id === 'fast');
143
- const slow = report.checks.find((r) => r.id === 'slow');
144
- expect(fast?.status).toBe('pass');
145
- expect(fast?.message).toBe('instantly done');
146
- expect(slow?.status).toBe('inconclusive');
147
- expect(slow?.message).toMatch(/wall-clock timeout/);
148
- expect(slow?.message).toMatch(/before this check completed/);
149
- });
150
- it('all checks finish before wall-clock budget → all preserved (no overwrite)', async () => {
151
- const reg = createDoctorRegistry();
152
- reg.register(check('a', { status: 'pass', message: 'first' }));
153
- reg.register(check('b', { status: 'fail', message: 'second' }));
154
- reg.register(check('c', { status: 'warn', message: 'third' }));
155
- const report = await runDoctor({
156
- registry: reg,
157
- wallClockTimeoutMs: 5_000,
158
- });
159
- expect(report.summary.total).toBe(3);
160
- expect(report.checks.find((r) => r.id === 'a')?.message).toBe('first');
161
- expect(report.checks.find((r) => r.id === 'b')?.message).toBe('second');
162
- expect(report.checks.find((r) => r.id === 'c')?.message).toBe('third');
163
- });
164
- it('mixed: 2 fast pass + 1 fast fail + 1 slow → preserves 3 + 1 inconclusive on wall timeout', async () => {
165
- const reg = createDoctorRegistry();
166
- reg.register(check('a', { status: 'pass' }));
167
- reg.register(check('b', { status: 'pass' }));
168
- reg.register(check('c', { status: 'fail', message: 'expected fail' }));
169
- reg.register({
170
- id: 'd',
171
- category: 'custom',
172
- run: () => new Promise((resolve) => setTimeout(() => resolve({ status: 'pass' }), 300)),
173
- });
174
- const report = await runDoctor({
175
- registry: reg,
176
- wallClockTimeoutMs: 50,
177
- perCheckTimeoutMs: 1000,
178
- });
179
- expect(report.summary.pass).toBe(2);
180
- expect(report.summary.fail).toBe(1);
181
- expect(report.summary.inconclusive).toBe(1);
182
- expect(report.summary.total).toBe(4);
183
- // exit code respects: fail > 0 → 1 (not affected by inconclusive)
184
- expect(report.exit).toBe(1);
185
- expect(report.checks.find((r) => r.id === 'd')?.status).toBe('inconclusive');
186
- });
187
- });
188
- describe('runDoctor — double-fire defense (ses_013 C4)', () => {
189
- it('a check whose per-check timeout fires after the check resolved produces exactly one record', async () => {
190
- // This timing is fragile by nature; the test asserts the contract
191
- // "exactly one record per id" which holds regardless of which side
192
- // of the race wins.
193
- const reg = createDoctorRegistry();
194
- reg.register({
195
- id: 'racer',
196
- category: 'custom',
197
- run: () => new Promise((resolve) => setTimeout(() => resolve({ status: 'pass' }), 25)),
198
- });
199
- const report = await runDoctor({
200
- registry: reg,
201
- perCheckTimeoutMs: 25, // intentionally close to the check's 25ms
202
- wallClockTimeoutMs: 1000,
203
- });
204
- expect(report.summary.total).toBe(1);
205
- expect(report.checks).toHaveLength(1);
206
- const racer = report.checks[0];
207
- // Whichever side won, exactly ONE record exists (no duplicate).
208
- expect(['pass', 'inconclusive']).toContain(racer?.status);
209
- });
210
- });
211
- describe('runDoctor — category filter', () => {
212
- it('only runs checks matching the requested category', async () => {
213
- const reg = createDoctorRegistry();
214
- reg.register(check('a', { status: 'pass' }, 'sandbox'));
215
- reg.register(check('b', { status: 'pass' }, 'providers'));
216
- reg.register(check('c', { status: 'pass' }, 'sandbox'));
217
- const report = await runDoctor({ registry: reg, categories: ['sandbox'] });
218
- expect(report.summary.total).toBe(2);
219
- expect(report.checks.every((r) => r.category === 'sandbox')).toBe(true);
220
- });
221
- });
222
- describe('runDoctor — context plumbing', () => {
223
- it('passes cwd / env / projectRoot to the check', async () => {
224
- const reg = createDoctorRegistry();
225
- let observedCwd;
226
- let observedRoot;
227
- reg.register({
228
- id: 'context-probe',
229
- category: 'custom',
230
- run: async (ctx) => {
231
- observedCwd = ctx.cwd;
232
- observedRoot = ctx.projectRoot;
233
- return { status: 'pass' };
234
- },
235
- });
236
- await runDoctor({
237
- registry: reg,
238
- cwd: '/tmp/fake',
239
- projectRoot: '/projects/x',
240
- });
241
- expect(observedCwd).toBe('/tmp/fake');
242
- expect(observedRoot).toBe('/projects/x');
243
- });
244
- });
245
- describe('runDoctor — report shape', () => {
246
- it('produces a frozen report with timestamp', async () => {
247
- const reg = createDoctorRegistry();
248
- reg.register(check('a', { status: 'pass' }));
249
- const report = await runDoctor({ registry: reg });
250
- expect(Object.isFrozen(report)).toBe(true);
251
- expect(report.timestamp).toMatch(/^\d{4}-\d{2}-\d{2}T/);
252
- });
253
- });
254
- describe('runDoctor — onCheckStart / onCheckComplete callbacks (ses_013 Phase 1)', () => {
255
- it('onCheckStart fires before onCheckComplete for the same id', async () => {
256
- const reg = createDoctorRegistry();
257
- reg.register(check('a', { status: 'pass' }));
258
- reg.register(check('b', { status: 'fail', message: 'broken' }));
259
- const events = [];
260
- await runDoctor({
261
- registry: reg,
262
- onCheckStart: (c) => events.push(`start:${c.id}`),
263
- onCheckComplete: (r) => events.push(`done:${r.id}`),
264
- });
265
- // Independently per id, start must precede done.
266
- const startA = events.indexOf('start:a');
267
- const doneA = events.indexOf('done:a');
268
- const startB = events.indexOf('start:b');
269
- const doneB = events.indexOf('done:b');
270
- expect(startA).toBeGreaterThanOrEqual(0);
271
- expect(doneA).toBeGreaterThan(startA);
272
- expect(startB).toBeGreaterThanOrEqual(0);
273
- expect(doneB).toBeGreaterThan(startB);
274
- });
275
- it('both callbacks fire exactly once per check, even when per-check timeout races', async () => {
276
- const reg = createDoctorRegistry();
277
- reg.register({
278
- id: 'racer',
279
- category: 'custom',
280
- run: () => new Promise((resolve) => setTimeout(() => resolve({ status: 'pass' }), 25)),
281
- });
282
- const startCount = {};
283
- const doneCount = {};
284
- await runDoctor({
285
- registry: reg,
286
- perCheckTimeoutMs: 25,
287
- onCheckStart: (c) => {
288
- startCount[c.id] = (startCount[c.id] ?? 0) + 1;
289
- },
290
- onCheckComplete: (r) => {
291
- doneCount[r.id] = (doneCount[r.id] ?? 0) + 1;
292
- },
293
- });
294
- expect(startCount.racer).toBe(1);
295
- expect(doneCount.racer).toBe(1);
296
- });
297
- it('a throwing onCheckStart does NOT affect the DoctorReport (ses_013 C3)', async () => {
298
- const reg = createDoctorRegistry();
299
- reg.register(check('a', { status: 'pass', message: 'still here' }));
300
- reg.register(check('b', { status: 'fail', message: 'still failed' }));
301
- const report = await runDoctor({
302
- registry: reg,
303
- onCheckStart: () => {
304
- throw new Error('start handler exploded');
305
- },
306
- });
307
- expect(report.summary.total).toBe(2);
308
- expect(report.summary.pass).toBe(1);
309
- expect(report.summary.fail).toBe(1);
310
- expect(report.checks.find((r) => r.id === 'a')?.message).toBe('still here');
311
- });
312
- it('a throwing onCheckComplete does NOT affect the DoctorReport (ses_013 C3)', async () => {
313
- const reg = createDoctorRegistry();
314
- reg.register(check('a', { status: 'pass' }));
315
- const report = await runDoctor({
316
- registry: reg,
317
- onCheckComplete: () => {
318
- throw new Error('complete handler exploded');
319
- },
320
- });
321
- expect(report.summary.total).toBe(1);
322
- expect(report.summary.pass).toBe(1);
323
- expect(report.exit).toBe(0);
324
- });
325
- });
326
- describe('runDoctor — signal abort (ses_013 Phase 1)', () => {
327
- it('signal already aborted before run → all checks marked inconclusive immediately', async () => {
328
- const reg = createDoctorRegistry();
329
- reg.register(check('a', { status: 'pass' }));
330
- reg.register(check('b', { status: 'pass' }));
331
- const controller = new AbortController();
332
- controller.abort();
333
- const report = await runDoctor({
334
- registry: reg,
335
- signal: controller.signal,
336
- perCheckTimeoutMs: 5_000,
337
- wallClockTimeoutMs: 5_000,
338
- });
339
- expect(report.summary.total).toBe(2);
340
- // Either all inconclusive (abort wins the race), OR some completed
341
- // if the synchronous check resolved before the race. The contract is
342
- // "no checks should hang indefinitely" — the report should return
343
- // promptly, not wait 5s.
344
- expect(report.summary.fail).toBe(0);
345
- expect(report.checks.every((r) => ['pass', 'inconclusive'].includes(r.status))).toBe(true);
346
- // Inconclusive records carry the "aborted by signal" message.
347
- const inconclusiveOnes = report.checks.filter((r) => r.status === 'inconclusive');
348
- for (const r of inconclusiveOnes) {
349
- expect(r.message).toMatch(/aborted by signal/);
350
- }
351
- });
352
- it('signal aborted mid-run → completed checks preserved, in-flight marked aborted-inconclusive', async () => {
353
- const reg = createDoctorRegistry();
354
- reg.register(check('fast', { status: 'pass', message: 'finished' }));
355
- reg.register({
356
- id: 'slow',
357
- category: 'custom',
358
- run: () => new Promise((resolve) => setTimeout(() => resolve({ status: 'pass' }), 500)),
359
- });
360
- const controller = new AbortController();
361
- // Abort after the fast check has had time to finish but before the
362
- // slow check resolves.
363
- setTimeout(() => controller.abort(), 50);
364
- const report = await runDoctor({
365
- registry: reg,
366
- signal: controller.signal,
367
- perCheckTimeoutMs: 5_000,
368
- wallClockTimeoutMs: 5_000,
369
- });
370
- expect(report.summary.total).toBe(2);
371
- const fast = report.checks.find((r) => r.id === 'fast');
372
- const slow = report.checks.find((r) => r.id === 'slow');
373
- expect(fast?.status).toBe('pass');
374
- expect(fast?.message).toBe('finished');
375
- expect(slow?.status).toBe('inconclusive');
376
- expect(slow?.message).toMatch(/aborted by signal/);
377
- });
378
- });
379
- //# sourceMappingURL=registry.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"registry.test.js","sourceRoot":"","sources":["../../src/doctor/registry.test.ts"],"names":[],"mappings":"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"}
@@ -1,11 +0,0 @@
1
- /**
2
- * An external tool server declared in the config is actually reachable.
3
- *
4
- * The server here is a REAL child process speaking real JSON-RPC over stdio,
5
- * written to a temp file and spawned by the shipped transport. A stubbed
6
- * transport would prove the adapter agrees with itself and would say nothing
7
- * about the thing that actually breaks: a process that spawns, or does not, and
8
- * a handshake that answers, or does not.
9
- */
10
- export {};
11
- //# sourceMappingURL=connect.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"connect.test.d.ts","sourceRoot":"","sources":["../../../../src/integrations/mcp/__tests__/connect.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -1,231 +0,0 @@
1
- /**
2
- * An external tool server declared in the config is actually reachable.
3
- *
4
- * The server here is a REAL child process speaking real JSON-RPC over stdio,
5
- * written to a temp file and spawned by the shipped transport. A stubbed
6
- * transport would prove the adapter agrees with itself and would say nothing
7
- * about the thing that actually breaks: a process that spawns, or does not, and
8
- * a handshake that answers, or does not.
9
- */
10
- import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
11
- import { tmpdir } from 'node:os';
12
- import { join } from 'node:path';
13
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
14
- import { connectMcpServers, transportFor } from '../servers.js';
15
- let dir;
16
- beforeEach(() => {
17
- dir = mkdtempSync(join(tmpdir(), 'namzu-mcp-'));
18
- });
19
- afterEach(async () => {
20
- // A child's working directory is the temp directory, and `close()` sends
21
- // SIGTERM without waiting for the exit — so on Windows the directory is
22
- // still held for a moment after the last assertion. Retried rather than
23
- // ignored: a directory that never frees would mean a process that never
24
- // died, which is the failure `close()` exists to prevent.
25
- for (let attempt = 0; attempt < 20; attempt++) {
26
- try {
27
- rmSync(dir, { recursive: true, force: true });
28
- return;
29
- }
30
- catch {
31
- await new Promise((resolve) => setTimeout(resolve, 50));
32
- }
33
- }
34
- rmSync(dir, { recursive: true, force: true });
35
- });
36
- /**
37
- * Resolves once the process is gone, or throws after the deadline.
38
- *
39
- * This asserts the SYMPTOM — the pid no longer exists — and not the mechanism,
40
- * and that distinction is worth stating because the same shape can be sound
41
- * about the wrong thing: a child that would have exited on its own the moment
42
- * its stdin pipe closed would satisfy this whether or not anything killed it,
43
- * and the test would report that `close()` works while `close()` did nothing.
44
- *
45
- * MEASURED, not reasoned about. With `close()` replaced by an early `return`,
46
- * this test fails with "process N was still alive after 5000ms" — so the child
47
- * does not go away by itself here, and the pid disappearing is caused by the
48
- * shutdown path under test. The symptom is the right claim for this package:
49
- * whether the runtime also REAPS the child is the transport's business, and
50
- * "no process left behind" is what a user is owed.
51
- */
52
- async function waitForExit(pid, deadlineMs = 5_000) {
53
- const until = Date.now() + deadlineMs;
54
- for (;;) {
55
- try {
56
- // Signal 0 tests for existence without delivering anything.
57
- process.kill(pid, 0);
58
- }
59
- catch {
60
- return;
61
- }
62
- if (Date.now() > until)
63
- throw new Error(`process ${pid} was still alive after ${deadlineMs}ms`);
64
- await new Promise((resolve) => setTimeout(resolve, 50));
65
- }
66
- }
67
- /**
68
- * The smallest server that satisfies the protocol: initialize, tools/list,
69
- * tools/call. Newline-delimited JSON-RPC on stdio, which is the wire the
70
- * shipped `StdioTransport` speaks.
71
- */
72
- function writeServer(name, body) {
73
- const path = join(dir, name);
74
- writeFileSync(path, body);
75
- return path;
76
- }
77
- const WORKING_SERVER = `
78
- if (process.argv[2]) require('node:fs').writeFileSync(process.argv[2], String(process.pid))
79
- let buf = ''
80
- process.stdin.on('data', (chunk) => {
81
- buf += chunk
82
- let i
83
- while ((i = buf.indexOf('\\n')) >= 0) {
84
- const line = buf.slice(0, i)
85
- buf = buf.slice(i + 1)
86
- if (!line.trim()) continue
87
- const msg = JSON.parse(line)
88
- if (msg.method === 'initialize') {
89
- send({ jsonrpc: '2.0', id: msg.id, result: {
90
- protocolVersion: msg.params.protocolVersion,
91
- serverInfo: { name: 'tickets', version: '1' },
92
- capabilities: { tools: {} },
93
- }})
94
- } else if (msg.method === 'tools/list') {
95
- send({ jsonrpc: '2.0', id: msg.id, result: { tools: [
96
- { name: 'create', description: 'Open a ticket', inputSchema: {
97
- type: 'object', properties: { title: { type: 'string' } }, required: ['title'] } },
98
- { name: 'close', description: 'Close a ticket', inputSchema: {
99
- type: 'object', properties: { id: { type: 'string' } }, required: ['id'] } },
100
- ]}})
101
- } else if (msg.method === 'tools/call') {
102
- send({ jsonrpc: '2.0', id: msg.id, result: {
103
- content: [{ type: 'text', text: 'opened ' + msg.params.arguments.title }],
104
- }})
105
- } else if (msg.id !== undefined) {
106
- send({ jsonrpc: '2.0', id: msg.id, result: {} })
107
- }
108
- }
109
- })
110
- function send(o) { process.stdout.write(JSON.stringify(o) + '\\n') }
111
- `;
112
- /** Starts, and never answers. The case a request timeout cannot cover. */
113
- const SILENT_SERVER = 'setInterval(() => {}, 1000)\n';
114
- describe('a declared server', () => {
115
- it('brings its tools, named after it', async () => {
116
- const server = writeServer('tickets.js', WORKING_SERVER);
117
- const mcp = await connectMcpServers({ tickets: { command: process.execPath, args: [server] } }, { cwd: dir });
118
- try {
119
- expect(mcp.failed).toEqual([]);
120
- expect(mcp.connected).toEqual([{ name: 'tickets', toolCount: 2 }]);
121
- // Prefixed with the server name so two servers offering `create` do
122
- // not collide and the transcript says where a call went.
123
- expect(mcp.tools.map((t) => t.name)).toEqual(['mcp_tickets_create', 'mcp_tickets_close']);
124
- }
125
- finally {
126
- await mcp.close();
127
- }
128
- });
129
- it('produces tools that actually call the server', async () => {
130
- // The tool objects existing is not the feature. Registering something the
131
- // model can see and cannot successfully invoke is worse than having
132
- // nothing, because the failure arrives mid-task.
133
- const server = writeServer('tickets.js', WORKING_SERVER);
134
- const mcp = await connectMcpServers({ tickets: { command: process.execPath, args: [server] } }, { cwd: dir });
135
- try {
136
- const create = mcp.tools.find((t) => t.name === 'mcp_tickets_create');
137
- const result = await create?.execute({ title: 'the build is red' }, {});
138
- expect(result?.success).toBe(true);
139
- expect(JSON.stringify(result?.output)).toContain('opened the build is red');
140
- }
141
- finally {
142
- await mcp.close();
143
- }
144
- });
145
- it('leaves no child process behind when the session closes', async () => {
146
- // The reason `close()` exists. A stdio server is a child process and
147
- // nothing else in this package owns one, so before this there was no
148
- // shutdown path at all: every TUI session and every one-shot left its
149
- // servers running.
150
- const server = writeServer('tickets.js', WORKING_SERVER);
151
- const pidFile = join(dir, 'server.pid');
152
- const mcp = await connectMcpServers({ tickets: { command: process.execPath, args: [server, pidFile] } }, { cwd: dir });
153
- const pid = Number(readFileSync(pidFile, 'utf8'));
154
- expect(Number.isInteger(pid), 'the server must have actually started').toBe(true);
155
- expect(() => process.kill(pid, 0), 'and must be alive before the close').not.toThrow();
156
- await mcp.close();
157
- await waitForExit(pid);
158
- }, 20_000);
159
- it('is absent from the roster when nothing is configured', async () => {
160
- const mcp = await connectMcpServers(undefined, { cwd: dir });
161
- expect(mcp.tools).toEqual([]);
162
- expect(mcp.connected).toEqual([]);
163
- expect(mcp.failed).toEqual([]);
164
- await mcp.close();
165
- });
166
- });
167
- describe('a server that does not work is named, never merely absent', () => {
168
- it('reports a command that cannot be spawned', async () => {
169
- const mcp = await connectMcpServers({ tickets: { command: join(dir, 'no-such-executable') } }, { cwd: dir });
170
- expect(mcp.connected).toEqual([]);
171
- expect(mcp.failed).toHaveLength(1);
172
- expect(mcp.failed[0]?.name).toBe('tickets');
173
- expect(mcp.failed[0]?.reason.length).toBeGreaterThan(0);
174
- await mcp.close();
175
- });
176
- it('reports a server that starts and never answers, rather than hanging', async () => {
177
- // The client's per-request timeout cannot cover this: the process is up,
178
- // the pipe is open, and nothing is coming. Without the connect deadline a
179
- // single wedged server holds the whole session open before the first turn
180
- // — no error, no failure, just a namzu that does not start.
181
- const server = writeServer('silent.js', SILENT_SERVER);
182
- const started = Date.now();
183
- const mcp = await connectMcpServers({ quiet: { command: process.execPath, args: [server] } }, { cwd: dir });
184
- expect(mcp.failed[0]?.name).toBe('quiet');
185
- expect(mcp.failed[0]?.reason).toContain('did not answer');
186
- expect(Date.now() - started, 'the deadline has to actually bound it').toBeLessThan(30_000);
187
- await mcp.close();
188
- }, 40_000);
189
- it('does not let one broken server take the working ones with it', async () => {
190
- const good = writeServer('tickets.js', WORKING_SERVER);
191
- const mcp = await connectMcpServers({
192
- broken: { command: join(dir, 'no-such-executable') },
193
- tickets: { command: process.execPath, args: [good] },
194
- }, { cwd: dir });
195
- try {
196
- expect(mcp.failed.map((f) => f.name)).toEqual(['broken']);
197
- expect(mcp.connected.map((c) => c.name)).toEqual(['tickets']);
198
- }
199
- finally {
200
- await mcp.close();
201
- }
202
- });
203
- });
204
- describe('a spec that is not a server', () => {
205
- it('refuses one that names neither a command nor a url', () => {
206
- expect(transportFor({}, dir)).toContain('neither a command nor a url');
207
- });
208
- it('refuses one that names both, rather than picking', () => {
209
- // An operator who edited a url into an entry that already had a command
210
- // meant one of them. Choosing for them runs something they did not ask
211
- // to run.
212
- expect(transportFor({ command: 'x', url: 'https://y' }, dir)).toContain('both');
213
- });
214
- it('reports a bad spec by name, alongside the servers that worked', async () => {
215
- const good = writeServer('tickets.js', WORKING_SERVER);
216
- const mcp = await connectMcpServers({ nonsense: {}, tickets: { command: process.execPath, args: [good] } }, { cwd: dir });
217
- try {
218
- expect(mcp.failed[0]?.name).toBe('nonsense');
219
- expect(mcp.connected.map((c) => c.name)).toEqual(['tickets']);
220
- }
221
- finally {
222
- await mcp.close();
223
- }
224
- });
225
- it('defaults a stdio server to the agent working directory', () => {
226
- const transport = transportFor({ command: 'node' }, dir);
227
- expect(typeof transport).not.toBe('string');
228
- expect(transport.cwd).toBe(dir);
229
- });
230
- });
231
- //# sourceMappingURL=connect.test.js.map