@united-workforce/cli 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -8
- package/dist/__tests__/adapter-json-roundtrip.test.js +1 -1
- package/dist/__tests__/adapter-json-roundtrip.test.js.map +1 -1
- package/dist/__tests__/agent-resolution-llm-free.test.d.ts +2 -0
- package/dist/__tests__/agent-resolution-llm-free.test.d.ts.map +1 -0
- package/dist/__tests__/agent-resolution-llm-free.test.js +30 -0
- package/dist/__tests__/agent-resolution-llm-free.test.js.map +1 -0
- package/dist/__tests__/build-step-entry.test.d.ts +2 -0
- package/dist/__tests__/build-step-entry.test.d.ts.map +1 -0
- package/dist/__tests__/build-step-entry.test.js +173 -0
- package/dist/__tests__/build-step-entry.test.js.map +1 -0
- package/dist/__tests__/clear-thread-failed-attempts.test.d.ts +2 -0
- package/dist/__tests__/clear-thread-failed-attempts.test.d.ts.map +1 -0
- package/dist/__tests__/clear-thread-failed-attempts.test.js +93 -0
- package/dist/__tests__/clear-thread-failed-attempts.test.js.map +1 -0
- package/dist/__tests__/config.test.js +26 -302
- package/dist/__tests__/config.test.js.map +1 -1
- package/dist/__tests__/current-role.test.js +7 -6
- package/dist/__tests__/current-role.test.js.map +1 -1
- package/dist/__tests__/e2e-mock-agent.test.js +20 -23
- package/dist/__tests__/e2e-mock-agent.test.js.map +1 -1
- package/dist/__tests__/issue-180-workflow-ref-removed.test.d.ts +2 -0
- package/dist/__tests__/issue-180-workflow-ref-removed.test.d.ts.map +1 -0
- package/dist/__tests__/issue-180-workflow-ref-removed.test.js +40 -0
- package/dist/__tests__/issue-180-workflow-ref-removed.test.js.map +1 -0
- package/dist/__tests__/moderator-evaluate.test.js +9 -50
- package/dist/__tests__/moderator-evaluate.test.js.map +1 -1
- package/dist/__tests__/pid-recycling.test.d.ts +2 -0
- package/dist/__tests__/pid-recycling.test.d.ts.map +1 -0
- package/dist/__tests__/pid-recycling.test.js +271 -0
- package/dist/__tests__/pid-recycling.test.js.map +1 -0
- package/dist/__tests__/prompt.test.js +321 -0
- package/dist/__tests__/prompt.test.js.map +1 -1
- package/dist/__tests__/resolve-head-hash.test.js +4 -4
- package/dist/__tests__/resolve-head-hash.test.js.map +1 -1
- package/dist/__tests__/setup-agent-discovery.test.js +21 -30
- package/dist/__tests__/setup-agent-discovery.test.js.map +1 -1
- package/dist/__tests__/setup-complexity.test.js +2 -168
- package/dist/__tests__/setup-complexity.test.js.map +1 -1
- package/dist/__tests__/setup-no-llm.test.d.ts +2 -0
- package/dist/__tests__/setup-no-llm.test.d.ts.map +1 -0
- package/dist/__tests__/setup-no-llm.test.js +52 -0
- package/dist/__tests__/setup-no-llm.test.js.map +1 -0
- package/dist/__tests__/solve-issue-tea-worktree.test.js +24 -27
- package/dist/__tests__/solve-issue-tea-worktree.test.js.map +1 -1
- package/dist/__tests__/step-ask.test.d.ts +2 -0
- package/dist/__tests__/step-ask.test.d.ts.map +1 -0
- package/dist/__tests__/step-ask.test.js +499 -0
- package/dist/__tests__/step-ask.test.js.map +1 -0
- package/dist/__tests__/step-show-json.test.js +1 -0
- package/dist/__tests__/step-show-json.test.js.map +1 -1
- package/dist/__tests__/step-timing.test.js +2 -0
- package/dist/__tests__/step-timing.test.js.map +1 -1
- package/dist/__tests__/store-global-cas.test.js +2 -2
- package/dist/__tests__/store-global-cas.test.js.map +1 -1
- package/dist/__tests__/store-unified-threads.test.js +9 -9
- package/dist/__tests__/store-unified-threads.test.js.map +1 -1
- package/dist/__tests__/thread-cancel-status.test.js +6 -6
- package/dist/__tests__/thread-cancel-status.test.js.map +1 -1
- package/dist/__tests__/thread-list-filters.test.js +344 -9
- package/dist/__tests__/thread-list-filters.test.js.map +1 -1
- package/dist/__tests__/thread-poke.test.d.ts +2 -0
- package/dist/__tests__/thread-poke.test.d.ts.map +1 -0
- package/dist/__tests__/thread-poke.test.js +412 -0
- package/dist/__tests__/thread-poke.test.js.map +1 -0
- package/dist/__tests__/thread-resume.test.js +10 -14
- package/dist/__tests__/thread-resume.test.js.map +1 -1
- package/dist/__tests__/thread-show-status.test.js +17 -28
- package/dist/__tests__/thread-show-status.test.js.map +1 -1
- package/dist/__tests__/thread-suspend-step.test.js +8 -14
- package/dist/__tests__/thread-suspend-step.test.js.map +1 -1
- package/dist/__tests__/thread-suspended-display.test.js +10 -22
- package/dist/__tests__/thread-suspended-display.test.js.map +1 -1
- package/dist/__tests__/thread.test.js +4 -4
- package/dist/__tests__/thread.test.js.map +1 -1
- package/dist/__tests__/validate-semantic.test.js +49 -21
- package/dist/__tests__/validate-semantic.test.js.map +1 -1
- package/dist/__tests__/workflow-list-recursive.test.d.ts +2 -0
- package/dist/__tests__/workflow-list-recursive.test.d.ts.map +1 -0
- package/dist/__tests__/workflow-list-recursive.test.js +283 -0
- package/dist/__tests__/workflow-list-recursive.test.js.map +1 -0
- package/dist/__tests__/workflow-resolution.test.js +36 -21
- package/dist/__tests__/workflow-resolution.test.js.map +1 -1
- package/dist/__tests__/workflow-show-resolution.test.d.ts +2 -0
- package/dist/__tests__/workflow-show-resolution.test.d.ts.map +1 -0
- package/dist/__tests__/workflow-show-resolution.test.js +210 -0
- package/dist/__tests__/workflow-show-resolution.test.js.map +1 -0
- package/dist/__tests__/workflow-validate.test.d.ts +2 -0
- package/dist/__tests__/workflow-validate.test.d.ts.map +1 -0
- package/dist/__tests__/workflow-validate.test.js +687 -0
- package/dist/__tests__/workflow-validate.test.js.map +1 -0
- package/dist/background/background.d.ts +22 -1
- package/dist/background/background.d.ts.map +1 -1
- package/dist/background/background.js +83 -6
- package/dist/background/background.js.map +1 -1
- package/dist/background/index.d.ts +1 -1
- package/dist/background/index.d.ts.map +1 -1
- package/dist/background/index.js +1 -1
- package/dist/background/index.js.map +1 -1
- package/dist/background/types.d.ts +1 -0
- package/dist/background/types.d.ts.map +1 -1
- package/dist/cli.js +66 -31
- package/dist/cli.js.map +1 -1
- package/dist/commands/config.d.ts +3 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +7 -33
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/prompt.d.ts.map +1 -1
- package/dist/commands/prompt.js +15 -2
- package/dist/commands/prompt.js.map +1 -1
- package/dist/commands/setup.d.ts +7 -39
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +27 -302
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/step.d.ts +44 -1
- package/dist/commands/step.d.ts.map +1 -1
- package/dist/commands/step.js +255 -11
- package/dist/commands/step.js.map +1 -1
- package/dist/commands/thread.d.ts +16 -3
- package/dist/commands/thread.d.ts.map +1 -1
- package/dist/commands/thread.js +379 -140
- package/dist/commands/thread.js.map +1 -1
- package/dist/commands/workflow.d.ts +9 -1
- package/dist/commands/workflow.d.ts.map +1 -1
- package/dist/commands/workflow.js +130 -6
- package/dist/commands/workflow.js.map +1 -1
- package/dist/moderator/__tests__/evaluate.test.js +31 -17
- package/dist/moderator/__tests__/evaluate.test.js.map +1 -1
- package/dist/moderator/evaluate.d.ts.map +1 -1
- package/dist/moderator/evaluate.js +4 -16
- package/dist/moderator/evaluate.js.map +1 -1
- package/dist/moderator/index.d.ts +1 -2
- package/dist/moderator/index.d.ts.map +1 -1
- package/dist/moderator/index.js +0 -1
- package/dist/moderator/index.js.map +1 -1
- package/dist/moderator/types.d.ts +6 -10
- package/dist/moderator/types.d.ts.map +1 -1
- package/dist/moderator/types.js +1 -3
- package/dist/moderator/types.js.map +1 -1
- package/dist/schemas.d.ts +2 -0
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +5 -3
- package/dist/schemas.js.map +1 -1
- package/dist/store.d.ts +28 -9
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +75 -16
- package/dist/store.js.map +1 -1
- package/dist/validate-semantic.d.ts.map +1 -1
- package/dist/validate-semantic.js +83 -66
- package/dist/validate-semantic.js.map +1 -1
- package/dist/validate.d.ts +6 -0
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +24 -0
- package/dist/validate.js.map +1 -1
- package/package.json +8 -10
- package/src/__tests__/adapter-json-roundtrip.test.ts +1 -1
- package/src/__tests__/agent-resolution-llm-free.test.ts +39 -0
- package/src/__tests__/build-step-entry.test.ts +203 -0
- package/src/__tests__/clear-thread-failed-attempts.test.ts +122 -0
- package/src/__tests__/config.test.ts +33 -321
- package/src/__tests__/current-role.test.ts +7 -6
- package/src/__tests__/e2e-mock-agent.test.ts +20 -23
- package/src/__tests__/fixtures/e2e-count.workflow.yaml +1 -0
- package/src/__tests__/fixtures/e2e-linear.workflow.yaml +1 -0
- package/src/__tests__/fixtures/{e2e-mustache.workflow.yaml → e2e-liquid.workflow.yaml} +3 -2
- package/src/__tests__/fixtures/e2e-loop.workflow.yaml +1 -0
- package/src/__tests__/fixtures/e2e-suspend.mock.yaml +2 -2
- package/src/__tests__/fixtures/e2e-suspend.workflow.yaml +6 -10
- package/src/__tests__/issue-180-workflow-ref-removed.test.ts +43 -0
- package/src/__tests__/moderator-evaluate.test.ts +9 -52
- package/src/__tests__/pid-recycling.test.ts +328 -0
- package/src/__tests__/prompt.test.ts +397 -0
- package/src/__tests__/resolve-head-hash.test.ts +4 -4
- package/src/__tests__/setup-agent-discovery.test.ts +26 -51
- package/src/__tests__/setup-complexity.test.ts +1 -203
- package/src/__tests__/setup-no-llm.test.ts +68 -0
- package/src/__tests__/solve-issue-tea-worktree.test.ts +24 -30
- package/src/__tests__/step-ask.test.ts +670 -0
- package/src/__tests__/step-show-json.test.ts +1 -0
- package/src/__tests__/step-timing.test.ts +2 -0
- package/src/__tests__/store-global-cas.test.ts +2 -2
- package/src/__tests__/store-unified-threads.test.ts +9 -9
- package/src/__tests__/thread-cancel-status.test.ts +6 -6
- package/src/__tests__/thread-list-filters.test.ts +434 -8
- package/src/__tests__/thread-poke.test.ts +545 -0
- package/src/__tests__/thread-resume.test.ts +10 -14
- package/src/__tests__/thread-show-status.test.ts +17 -29
- package/src/__tests__/thread-suspend-step.test.ts +8 -14
- package/src/__tests__/thread-suspended-display.test.ts +10 -22
- package/src/__tests__/thread.test.ts +4 -4
- package/src/__tests__/validate-semantic.test.ts +59 -31
- package/src/__tests__/workflow-list-recursive.test.ts +370 -0
- package/src/__tests__/workflow-resolution.test.ts +39 -21
- package/src/__tests__/workflow-show-resolution.test.ts +285 -0
- package/src/__tests__/workflow-validate.test.ts +806 -0
- package/src/background/background.ts +88 -6
- package/src/background/index.ts +2 -0
- package/src/background/types.ts +1 -0
- package/src/cli.ts +97 -47
- package/src/commands/config.ts +7 -35
- package/src/commands/prompt.ts +15 -2
- package/src/commands/setup.ts +29 -357
- package/src/commands/step.ts +339 -12
- package/src/commands/thread.ts +463 -169
- package/src/commands/workflow.ts +159 -4
- package/src/moderator/__tests__/evaluate.test.ts +34 -17
- package/src/moderator/evaluate.ts +5 -17
- package/src/moderator/index.ts +1 -6
- package/src/moderator/types.ts +6 -14
- package/src/schemas.ts +13 -3
- package/src/store.ts +86 -20
- package/src/validate-semantic.ts +109 -78
- package/src/validate.ts +27 -0
- package/dist/__tests__/setup-validate.test.d.ts +0 -2
- package/dist/__tests__/setup-validate.test.d.ts.map +0 -1
- package/dist/__tests__/setup-validate.test.js +0 -108
- package/dist/__tests__/setup-validate.test.js.map +0 -1
- package/src/__tests__/setup-validate.test.ts +0 -148
- /package/src/__tests__/fixtures/{e2e-mustache.mock.yaml → e2e-liquid.mock.yaml} +0 -0
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { describe, expect, test } from "vitest";
|
|
5
5
|
import {
|
|
6
6
|
_discoverAgents,
|
|
7
7
|
_isBackspace,
|
|
8
8
|
_isTerminator,
|
|
9
9
|
_parseWhichOutput,
|
|
10
|
-
_printModelMenu,
|
|
11
|
-
_printProviderMenu,
|
|
12
|
-
_printValidationResult,
|
|
13
|
-
_resolveModelChoice,
|
|
14
|
-
_resolveProviderChoice,
|
|
15
10
|
_searchPathDirs,
|
|
16
11
|
} from "../commands/setup.js";
|
|
17
12
|
|
|
@@ -172,203 +167,6 @@ describe("_isBackspace", () => {
|
|
|
172
167
|
});
|
|
173
168
|
});
|
|
174
169
|
|
|
175
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
176
|
-
// 3a. _printProviderMenu
|
|
177
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
178
|
-
|
|
179
|
-
describe("_printProviderMenu", () => {
|
|
180
|
-
afterEach(() => {
|
|
181
|
-
vi.restoreAllMocks();
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
const providers = [
|
|
185
|
-
{ name: "openai", label: "OpenAI", baseUrl: "https://api.openai.com/v1" },
|
|
186
|
-
{ name: "xai", label: "xAI", baseUrl: "https://api.x.ai/v1" },
|
|
187
|
-
] as const;
|
|
188
|
-
|
|
189
|
-
test("prints correct number of lines (one per provider + custom)", () => {
|
|
190
|
-
const lines: string[] = [];
|
|
191
|
-
vi.spyOn(console, "log").mockImplementation((msg: string) => {
|
|
192
|
-
lines.push(msg);
|
|
193
|
-
});
|
|
194
|
-
_printProviderMenu(providers);
|
|
195
|
-
// 2 providers + 1 custom = 3 lines
|
|
196
|
-
expect(lines.length).toBe(3);
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
test("custom option number = providers.length + 1", () => {
|
|
200
|
-
const lines: string[] = [];
|
|
201
|
-
vi.spyOn(console, "log").mockImplementation((msg: string) => {
|
|
202
|
-
lines.push(msg);
|
|
203
|
-
});
|
|
204
|
-
_printProviderMenu(providers);
|
|
205
|
-
const lastLine = lines[lines.length - 1] ?? "";
|
|
206
|
-
expect(lastLine).toMatch(/3\)/);
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
test("each provider line contains its label and baseUrl", () => {
|
|
210
|
-
const lines: string[] = [];
|
|
211
|
-
vi.spyOn(console, "log").mockImplementation((msg: string) => {
|
|
212
|
-
lines.push(msg);
|
|
213
|
-
});
|
|
214
|
-
_printProviderMenu(providers);
|
|
215
|
-
expect(lines[0]).toContain("OpenAI");
|
|
216
|
-
expect(lines[0]).toContain("https://api.openai.com/v1");
|
|
217
|
-
expect(lines[1]).toContain("xAI");
|
|
218
|
-
expect(lines[1]).toContain("https://api.x.ai/v1");
|
|
219
|
-
});
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
223
|
-
// 3b. _resolveProviderChoice
|
|
224
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
225
|
-
|
|
226
|
-
describe("_resolveProviderChoice", () => {
|
|
227
|
-
const providers = [
|
|
228
|
-
{ name: "openai", label: "OpenAI", baseUrl: "https://api.openai.com/v1" },
|
|
229
|
-
{ name: "xai", label: "xAI", baseUrl: "https://api.x.ai/v1" },
|
|
230
|
-
{ name: "deepseek", label: "DeepSeek", baseUrl: "https://api.deepseek.com/v1" },
|
|
231
|
-
] as const;
|
|
232
|
-
|
|
233
|
-
test("valid index 1 returns first provider", () => {
|
|
234
|
-
const result = _resolveProviderChoice("1", providers);
|
|
235
|
-
expect(result).toEqual({ providerName: "openai", baseUrl: "https://api.openai.com/v1" });
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
test("valid index N (last preset) returns last provider", () => {
|
|
239
|
-
const result = _resolveProviderChoice("3", providers);
|
|
240
|
-
expect(result).toEqual({ providerName: "deepseek", baseUrl: "https://api.deepseek.com/v1" });
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
test("index providers.length+1 (custom) returns null", () => {
|
|
244
|
-
const result = _resolveProviderChoice("4", providers);
|
|
245
|
-
expect(result).toBeNull();
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
test("non-numeric string returns null", () => {
|
|
249
|
-
expect(_resolveProviderChoice("abc", providers)).toBeNull();
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
test("0 returns null (out of range)", () => {
|
|
253
|
-
expect(_resolveProviderChoice("0", providers)).toBeNull();
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
test("N+2 returns null (out of range)", () => {
|
|
257
|
-
expect(_resolveProviderChoice("5", providers)).toBeNull();
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
test("negative number returns null", () => {
|
|
261
|
-
expect(_resolveProviderChoice("-1", providers)).toBeNull();
|
|
262
|
-
});
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
266
|
-
// 3c. _resolveModelChoice
|
|
267
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
268
|
-
|
|
269
|
-
describe("_resolveModelChoice", () => {
|
|
270
|
-
test("numeric input within range returns model at that index", () => {
|
|
271
|
-
expect(_resolveModelChoice("2", ["a", "b", "c"])).toBe("b");
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
test("numeric input out of range returns input as-is", () => {
|
|
275
|
-
expect(_resolveModelChoice("5", ["a"])).toBe("5");
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
test("non-numeric input returns input as-is", () => {
|
|
279
|
-
expect(_resolveModelChoice("gpt-4o", ["a", "b"])).toBe("gpt-4o");
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
test("numeric input 1 returns first model", () => {
|
|
283
|
-
expect(_resolveModelChoice("1", ["alpha", "beta"])).toBe("alpha");
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
test("empty models list with numeric input returns input as-is", () => {
|
|
287
|
-
expect(_resolveModelChoice("1", [])).toBe("1");
|
|
288
|
-
});
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
292
|
-
// 3d. _printModelMenu
|
|
293
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
294
|
-
|
|
295
|
-
describe("_printModelMenu", () => {
|
|
296
|
-
afterEach(() => {
|
|
297
|
-
vi.restoreAllMocks();
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
test("prints all models — each model name appears in output", () => {
|
|
301
|
-
const output: string[] = [];
|
|
302
|
-
vi.spyOn(console, "log").mockImplementation((msg: string) => {
|
|
303
|
-
output.push(msg);
|
|
304
|
-
});
|
|
305
|
-
const models = ["model-a", "model-b", "model-c"];
|
|
306
|
-
_printModelMenu(models, 100);
|
|
307
|
-
const combined = output.join("\n");
|
|
308
|
-
for (const m of models) {
|
|
309
|
-
expect(combined).toContain(m);
|
|
310
|
-
}
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
test("single column when termCols is very small", () => {
|
|
314
|
-
const output: string[] = [];
|
|
315
|
-
vi.spyOn(console, "log").mockImplementation((msg: string) => {
|
|
316
|
-
output.push(msg);
|
|
317
|
-
});
|
|
318
|
-
_printModelMenu(["a", "b", "c"], 1);
|
|
319
|
-
// Each model on its own row → 3 lines
|
|
320
|
-
expect(output.length).toBe(3);
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
test("wide terminal fits multiple columns", () => {
|
|
324
|
-
const output: string[] = [];
|
|
325
|
-
vi.spyOn(console, "log").mockImplementation((msg: string) => {
|
|
326
|
-
output.push(msg);
|
|
327
|
-
});
|
|
328
|
-
const models = Array.from({ length: 6 }, (_, i) => `m${i}`);
|
|
329
|
-
_printModelMenu(models, 200);
|
|
330
|
-
// With wide terminal and short names, should fit in fewer than 6 rows
|
|
331
|
-
expect(output.length).toBeLessThan(6);
|
|
332
|
-
});
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
336
|
-
// 3e. _printValidationResult
|
|
337
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
338
|
-
|
|
339
|
-
describe("_printValidationResult", () => {
|
|
340
|
-
afterEach(() => {
|
|
341
|
-
vi.restoreAllMocks();
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
test("ok=true prints success message containing '✓'", () => {
|
|
345
|
-
const lines: string[] = [];
|
|
346
|
-
vi.spyOn(console, "log").mockImplementation((msg: string) => {
|
|
347
|
-
lines.push(msg);
|
|
348
|
-
});
|
|
349
|
-
_printValidationResult({ ok: true, error: null });
|
|
350
|
-
expect(lines.join("\n")).toContain("✓");
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
test("ok=false prints warning message containing '⚠'", () => {
|
|
354
|
-
const lines: string[] = [];
|
|
355
|
-
vi.spyOn(console, "log").mockImplementation((msg: string) => {
|
|
356
|
-
lines.push(msg);
|
|
357
|
-
});
|
|
358
|
-
_printValidationResult({ ok: false, error: "HTTP 401" });
|
|
359
|
-
expect(lines.join("\n")).toContain("⚠");
|
|
360
|
-
});
|
|
361
|
-
|
|
362
|
-
test("ok=false includes the error string in output", () => {
|
|
363
|
-
const lines: string[] = [];
|
|
364
|
-
vi.spyOn(console, "log").mockImplementation((msg: string) => {
|
|
365
|
-
lines.push(msg);
|
|
366
|
-
});
|
|
367
|
-
_printValidationResult({ ok: false, error: "HTTP 401" });
|
|
368
|
-
expect(lines.join("\n")).toContain("HTTP 401");
|
|
369
|
-
});
|
|
370
|
-
});
|
|
371
|
-
|
|
372
170
|
// ──────────────────────────────────────────────────────────────────────────────
|
|
373
171
|
// 4. Regression
|
|
374
172
|
// ──────────────────────────────────────────────────────────────────────────────
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { afterEach, describe, expect, test } from "vitest";
|
|
5
|
+
import { parse } from "yaml";
|
|
6
|
+
import { cmdSetup } from "../commands/setup.js";
|
|
7
|
+
|
|
8
|
+
describe("cmdSetup — non-interactive, no LLM args (issue #143)", () => {
|
|
9
|
+
let tempDir: string;
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
if (tempDir) rmSync(tempDir, { recursive: true, force: true });
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test("writes config.yaml with only agents + defaultAgent", async () => {
|
|
15
|
+
tempDir = mkdtempSync(join(tmpdir(), "uwf-setup-"));
|
|
16
|
+
await cmdSetup({ agent: "hermes", storageRoot: tempDir });
|
|
17
|
+
const cfg = parse(readFileSync(join(tempDir, "config.yaml"), "utf8")) as Record<
|
|
18
|
+
string,
|
|
19
|
+
unknown
|
|
20
|
+
>;
|
|
21
|
+
expect(cfg.defaultAgent).toBe("hermes");
|
|
22
|
+
expect(cfg.agents).toBeDefined();
|
|
23
|
+
expect(cfg.providers).toBeUndefined();
|
|
24
|
+
expect(cfg.models).toBeUndefined();
|
|
25
|
+
expect(cfg.defaultModel).toBeUndefined();
|
|
26
|
+
expect(cfg.modelOverrides).toBeUndefined();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("preserves existing agentOverrides on rewrite", async () => {
|
|
30
|
+
tempDir = mkdtempSync(join(tmpdir(), "uwf-setup-"));
|
|
31
|
+
writeFileSync(
|
|
32
|
+
join(tempDir, "config.yaml"),
|
|
33
|
+
"agents:\n hermes: { command: uwf-hermes, args: [] }\ndefaultAgent: hermes\nagentOverrides:\n solve-issue:\n coder: claude-code\n",
|
|
34
|
+
"utf8",
|
|
35
|
+
);
|
|
36
|
+
await cmdSetup({ agent: "hermes", storageRoot: tempDir });
|
|
37
|
+
const cfg = parse(readFileSync(join(tempDir, "config.yaml"), "utf8")) as Record<
|
|
38
|
+
string,
|
|
39
|
+
unknown
|
|
40
|
+
>;
|
|
41
|
+
expect(cfg.agentOverrides).toEqual({ "solve-issue": { coder: "claude-code" } });
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("creates a default agent entry when missing", async () => {
|
|
45
|
+
tempDir = mkdtempSync(join(tmpdir(), "uwf-setup-"));
|
|
46
|
+
await cmdSetup({ agent: "claude-code", storageRoot: tempDir });
|
|
47
|
+
const cfg = parse(readFileSync(join(tempDir, "config.yaml"), "utf8")) as Record<
|
|
48
|
+
string,
|
|
49
|
+
unknown
|
|
50
|
+
>;
|
|
51
|
+
expect(cfg.defaultAgent).toBe("claude-code");
|
|
52
|
+
const agents = cfg.agents as Record<string, unknown>;
|
|
53
|
+
expect(agents["claude-code"]).toEqual({ command: "uwf-claude-code", args: [] });
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe("cmdSetup public surface — provider/model helpers removed (issue #143)", () => {
|
|
58
|
+
test("module does not export validateModel / provider menus / model menus", async () => {
|
|
59
|
+
const mod = (await import("../commands/setup.js")) as Record<string, unknown>;
|
|
60
|
+
expect(mod.validateModel).toBeUndefined();
|
|
61
|
+
expect(mod.resolvePresetBaseUrl).toBeUndefined();
|
|
62
|
+
expect(mod._printProviderMenu).toBeUndefined();
|
|
63
|
+
expect(mod._resolveProviderChoice).toBeUndefined();
|
|
64
|
+
expect(mod._printModelMenu).toBeUndefined();
|
|
65
|
+
expect(mod._resolveModelChoice).toBeUndefined();
|
|
66
|
+
expect(mod._printValidationResult).toBeUndefined();
|
|
67
|
+
});
|
|
68
|
+
});
|
|
@@ -21,11 +21,11 @@ describe("solve-issue workflow: Gitea API PR creation", () => {
|
|
|
21
21
|
"..",
|
|
22
22
|
"..",
|
|
23
23
|
"..",
|
|
24
|
-
"
|
|
24
|
+
"examples",
|
|
25
25
|
"solve-issue.yaml",
|
|
26
26
|
);
|
|
27
27
|
|
|
28
|
-
test("committer procedure should
|
|
28
|
+
test("committer procedure should create PR via tea pr create", async () => {
|
|
29
29
|
const yamlContent = await readFile(workflowPath, "utf-8");
|
|
30
30
|
const workflow = parse(yamlContent) as WorkflowPayload;
|
|
31
31
|
|
|
@@ -33,25 +33,22 @@ describe("solve-issue workflow: Gitea API PR creation", () => {
|
|
|
33
33
|
const committerProcedure = workflow.roles.committer?.procedure;
|
|
34
34
|
expect(committerProcedure).toBeDefined();
|
|
35
35
|
|
|
36
|
-
// Verify the procedure uses
|
|
37
|
-
expect(committerProcedure).toContain("
|
|
38
|
-
expect(committerProcedure).toContain("
|
|
39
|
-
expect(committerProcedure).toContain("
|
|
40
|
-
|
|
41
|
-
// Verify it explicitly warns against tea pr create
|
|
42
|
-
expect(committerProcedure).toMatch(/do NOT use.*tea pr create/i);
|
|
36
|
+
// Verify the procedure uses tea pr create for PR creation
|
|
37
|
+
expect(committerProcedure).toContain("tea pr create");
|
|
38
|
+
expect(committerProcedure).toContain("git push");
|
|
39
|
+
expect(committerProcedure).toContain("Fixes #N");
|
|
43
40
|
});
|
|
44
41
|
|
|
45
|
-
test("committer procedure should
|
|
42
|
+
test("committer procedure should extract owner/repo from git remote", async () => {
|
|
46
43
|
const yamlContent = await readFile(workflowPath, "utf-8");
|
|
47
44
|
const workflow = parse(yamlContent) as WorkflowPayload;
|
|
48
45
|
|
|
49
46
|
const committerProcedure = workflow.roles.committer?.procedure;
|
|
50
47
|
expect(committerProcedure).toBeDefined();
|
|
51
48
|
|
|
52
|
-
// Verify the procedure
|
|
53
|
-
expect(committerProcedure).
|
|
54
|
-
expect(committerProcedure).
|
|
49
|
+
// Verify the procedure extracts owner/repo from remote
|
|
50
|
+
expect(committerProcedure).toContain("git remote get-url origin");
|
|
51
|
+
expect(committerProcedure).toContain("hook_failed");
|
|
55
52
|
});
|
|
56
53
|
|
|
57
54
|
test("committer procedure should include error handling for curl failures", async () => {
|
|
@@ -100,45 +97,42 @@ describe("solve-issue workflow: Gitea API PR creation", () => {
|
|
|
100
97
|
expect(committedVariant.required).toContain("$status");
|
|
101
98
|
});
|
|
102
99
|
|
|
103
|
-
test("developer procedure should include
|
|
100
|
+
test("developer procedure should include worktree setup", async () => {
|
|
104
101
|
const yamlContent = await readFile(workflowPath, "utf-8");
|
|
105
102
|
const workflow = parse(yamlContent) as WorkflowPayload;
|
|
106
103
|
|
|
107
104
|
const developerProcedure = workflow.roles.developer?.procedure;
|
|
108
105
|
expect(developerProcedure).toBeDefined();
|
|
109
106
|
|
|
110
|
-
// Verify the procedure includes
|
|
111
|
-
expect(developerProcedure).toContain("
|
|
112
|
-
expect(developerProcedure).toContain("git
|
|
113
|
-
expect(developerProcedure).toContain("
|
|
114
|
-
expect(developerProcedure).toMatch(/ls -la|verify.*exist/i);
|
|
107
|
+
// Verify the procedure includes worktree setup
|
|
108
|
+
expect(developerProcedure).toContain("IMPORTANT");
|
|
109
|
+
expect(developerProcedure).toContain("git worktree add");
|
|
110
|
+
expect(developerProcedure).toContain("pnpm install");
|
|
115
111
|
});
|
|
116
112
|
|
|
117
|
-
test("reviewer procedure should
|
|
113
|
+
test("reviewer procedure should verify branch and run checks", async () => {
|
|
118
114
|
const yamlContent = await readFile(workflowPath, "utf-8");
|
|
119
115
|
const workflow = parse(yamlContent) as WorkflowPayload;
|
|
120
116
|
|
|
121
117
|
const reviewerProcedure = workflow.roles.reviewer?.procedure;
|
|
122
118
|
expect(reviewerProcedure).toBeDefined();
|
|
123
119
|
|
|
124
|
-
// Verify the procedure includes
|
|
125
|
-
expect(reviewerProcedure).toContain("
|
|
126
|
-
expect(reviewerProcedure).
|
|
127
|
-
expect(reviewerProcedure).toContain(
|
|
128
|
-
"Do NOT report results without running the actual commands",
|
|
129
|
-
);
|
|
120
|
+
// Verify the procedure includes branch verification and build checks
|
|
121
|
+
expect(reviewerProcedure).toContain("git branch --show-current");
|
|
122
|
+
expect(reviewerProcedure).toContain("pnpm run build");
|
|
123
|
+
expect(reviewerProcedure).toContain("pnpm run check");
|
|
130
124
|
});
|
|
131
125
|
|
|
132
|
-
test("developer procedure should include
|
|
126
|
+
test("developer procedure should include changeset and failure handling", async () => {
|
|
133
127
|
const yamlContent = await readFile(workflowPath, "utf-8");
|
|
134
128
|
const workflow = parse(yamlContent) as WorkflowPayload;
|
|
135
129
|
|
|
136
130
|
const developerProcedure = workflow.roles.developer?.procedure;
|
|
137
131
|
expect(developerProcedure).toBeDefined();
|
|
138
132
|
|
|
139
|
-
// Verify the procedure includes
|
|
140
|
-
expect(developerProcedure).
|
|
141
|
-
expect(developerProcedure).toMatch(/3 test cycles|after 3 attempts/i);
|
|
133
|
+
// Verify the procedure includes changeset requirement and failure path
|
|
134
|
+
expect(developerProcedure).toContain(".changeset/");
|
|
142
135
|
expect(developerProcedure).toContain("$status=failed");
|
|
136
|
+
expect(developerProcedure).toContain("pnpm test");
|
|
143
137
|
});
|
|
144
138
|
});
|