@minicor/mcp-server 4.10.0 → 4.12.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 +17 -4
- package/dist/__tests__/agent-harness-tools.test.d.ts +2 -0
- package/dist/__tests__/agent-harness-tools.test.d.ts.map +1 -0
- package/dist/__tests__/agent-harness-tools.test.js +86 -0
- package/dist/__tests__/agent-harness-tools.test.js.map +1 -0
- package/dist/__tests__/blueprints-tools.test.js +137 -70
- package/dist/__tests__/blueprints-tools.test.js.map +1 -1
- package/dist/__tests__/jobs-tools.test.js +228 -0
- package/dist/__tests__/jobs-tools.test.js.map +1 -1
- package/dist/agent-service-client.d.ts +7 -1
- package/dist/agent-service-client.d.ts.map +1 -1
- package/dist/agent-service-client.js +24 -5
- package/dist/agent-service-client.js.map +1 -1
- package/dist/server-surface.d.ts.map +1 -1
- package/dist/server-surface.js +16 -1
- package/dist/server-surface.js.map +1 -1
- package/dist/tools/agent-harness.d.ts +3 -0
- package/dist/tools/agent-harness.d.ts.map +1 -0
- package/dist/tools/agent-harness.js +143 -0
- package/dist/tools/agent-harness.js.map +1 -0
- package/dist/tools/blueprints.d.ts +4 -0
- package/dist/tools/blueprints.d.ts.map +1 -1
- package/dist/tools/blueprints.js +32 -18
- package/dist/tools/blueprints.js.map +1 -1
- package/dist/tools/jobs.d.ts.map +1 -1
- package/dist/tools/jobs.js +50 -11
- package/dist/tools/jobs.js.map +1 -1
- package/package.json +1 -1
|
@@ -53,7 +53,7 @@ function routedFetch(routes) {
|
|
|
53
53
|
/** A GET /blueprints/:id response (Blueprint & BlueprintStateInfo). */
|
|
54
54
|
function bpFixture(overrides = {}) {
|
|
55
55
|
return {
|
|
56
|
-
id: "
|
|
56
|
+
id: "5668a1ae-3912-4713-b269-f98817b9ccd9",
|
|
57
57
|
workspaceId: 11,
|
|
58
58
|
name: "COI intake",
|
|
59
59
|
document: { goal: "", steps: [], openQuestions: [] },
|
|
@@ -87,6 +87,73 @@ describe("blueprint tools", () => {
|
|
|
87
87
|
process.env.MIDDLEWARE_SERVICE_URL = savedMwUrl;
|
|
88
88
|
vi.unstubAllGlobals();
|
|
89
89
|
});
|
|
90
|
+
// ── uuid validation (F2: hallucinated ids reached prod as 500s) ──
|
|
91
|
+
it("rejects an integer blueprintId client-side without calling the service (ws 264 incident shape)", async () => {
|
|
92
|
+
const fetchMock = vi.fn();
|
|
93
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
94
|
+
const { client, embedded } = await startServer();
|
|
95
|
+
try {
|
|
96
|
+
const result = await client.callTool({
|
|
97
|
+
name: "blueprint_get",
|
|
98
|
+
arguments: { workspaceId: 11, blueprintId: "75" },
|
|
99
|
+
});
|
|
100
|
+
expect(result.isError).toBe(true);
|
|
101
|
+
expect(result.content[0].text).toContain("blueprintId must be a uuid; call blueprint_list to get real ids");
|
|
102
|
+
expect(fetchMock).not.toHaveBeenCalled();
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
await client.close();
|
|
106
|
+
await embedded.close();
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
it("rejects a spliced non-uuid blueprintId (ws 277 incident shape)", async () => {
|
|
110
|
+
const fetchMock = vi.fn();
|
|
111
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
112
|
+
const { client, embedded } = await startServer();
|
|
113
|
+
try {
|
|
114
|
+
const result = await client.callTool({
|
|
115
|
+
name: "blueprint_add_entry",
|
|
116
|
+
arguments: {
|
|
117
|
+
workspaceId: 11,
|
|
118
|
+
// Two real uuids mis-spliced at a shared hex token, verbatim from
|
|
119
|
+
// the prod incident. 36+ chars of valid hex, still not a uuid.
|
|
120
|
+
blueprintId: "be9b3716-a487-4eac-886d-e632faadfd2c01d9",
|
|
121
|
+
kind: "note",
|
|
122
|
+
title: "n",
|
|
123
|
+
text: "t",
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
expect(result.isError).toBe(true);
|
|
127
|
+
expect(result.content[0].text).toContain("blueprintId must be a uuid; call blueprint_list to get real ids");
|
|
128
|
+
expect(fetchMock).not.toHaveBeenCalled();
|
|
129
|
+
}
|
|
130
|
+
finally {
|
|
131
|
+
await client.close();
|
|
132
|
+
await embedded.close();
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
it("rejects a non-uuid entryId with a blueprint_list_entries hint", async () => {
|
|
136
|
+
const fetchMock = vi.fn();
|
|
137
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
138
|
+
const { client, embedded } = await startServer();
|
|
139
|
+
try {
|
|
140
|
+
const result = await client.callTool({
|
|
141
|
+
name: "blueprint_list_entries",
|
|
142
|
+
arguments: {
|
|
143
|
+
workspaceId: 11,
|
|
144
|
+
blueprintId: "5668a1ae-3912-4713-b269-f98817b9ccd9",
|
|
145
|
+
entryId: "e1",
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
expect(result.isError).toBe(true);
|
|
149
|
+
expect(result.content[0].text).toContain("entryId must be a uuid; call blueprint_list_entries to get real ids");
|
|
150
|
+
expect(fetchMock).not.toHaveBeenCalled();
|
|
151
|
+
}
|
|
152
|
+
finally {
|
|
153
|
+
await client.close();
|
|
154
|
+
await embedded.close();
|
|
155
|
+
}
|
|
156
|
+
});
|
|
90
157
|
// ── baseVersion CAS ────────────────────────────────────────
|
|
91
158
|
it("blueprint_update surfaces the baseVersion CAS 409 as a structured version_conflict", async () => {
|
|
92
159
|
const fetchMock = vi.fn(async (_input, _init) => jsonResponse({ message: "Blueprint has moved to version 7 (edit was based on 4)" }, 409));
|
|
@@ -97,13 +164,13 @@ describe("blueprint tools", () => {
|
|
|
97
164
|
name: "blueprint_update",
|
|
98
165
|
arguments: {
|
|
99
166
|
workspaceId: 11,
|
|
100
|
-
blueprintId: "
|
|
167
|
+
blueprintId: "5668a1ae-3912-4713-b269-f98817b9ccd9",
|
|
101
168
|
patch: { goal: "New goal" },
|
|
102
169
|
baseVersion: 4,
|
|
103
170
|
},
|
|
104
171
|
});
|
|
105
172
|
const [url, init] = fetchMock.mock.calls[0];
|
|
106
|
-
expect(String(url)).toBe(`${MW_BASE}${BP}/
|
|
173
|
+
expect(String(url)).toBe(`${MW_BASE}${BP}/5668a1ae-3912-4713-b269-f98817b9ccd9`);
|
|
107
174
|
expect(init.method).toBe("PATCH");
|
|
108
175
|
expect(JSON.parse(String(init.body)).baseVersion).toBe(4);
|
|
109
176
|
const payload = parseToolJson(result);
|
|
@@ -126,7 +193,7 @@ describe("blueprint tools", () => {
|
|
|
126
193
|
name: "blueprint_update",
|
|
127
194
|
arguments: {
|
|
128
195
|
workspaceId: 11,
|
|
129
|
-
blueprintId: "
|
|
196
|
+
blueprintId: "5668a1ae-3912-4713-b269-f98817b9ccd9",
|
|
130
197
|
patch: { goal: "New goal" },
|
|
131
198
|
},
|
|
132
199
|
});
|
|
@@ -151,7 +218,7 @@ describe("blueprint tools", () => {
|
|
|
151
218
|
try {
|
|
152
219
|
const result = await client.callTool({
|
|
153
220
|
name: "blueprint_update",
|
|
154
|
-
arguments: { workspaceId: 11, blueprintId: "
|
|
221
|
+
arguments: { workspaceId: 11, blueprintId: "5668a1ae-3912-4713-b269-f98817b9ccd9", name: "Renamed" },
|
|
155
222
|
});
|
|
156
223
|
const payload = parseToolJson(result);
|
|
157
224
|
expect(payload.status).toBe("updated");
|
|
@@ -187,7 +254,7 @@ describe("blueprint tools", () => {
|
|
|
187
254
|
try {
|
|
188
255
|
const result = await client.callTool({
|
|
189
256
|
name: "blueprint_synthesize",
|
|
190
|
-
arguments: { workspaceId: 11, blueprintId: "
|
|
257
|
+
arguments: { workspaceId: 11, blueprintId: "5668a1ae-3912-4713-b269-f98817b9ccd9" },
|
|
191
258
|
});
|
|
192
259
|
const payload = parseToolJson(result);
|
|
193
260
|
expect(payload.status).toBe("blocked");
|
|
@@ -216,7 +283,7 @@ describe("blueprint tools", () => {
|
|
|
216
283
|
try {
|
|
217
284
|
const result = await client.callTool({
|
|
218
285
|
name: "blueprint_synthesize",
|
|
219
|
-
arguments: { workspaceId: 11, blueprintId: "
|
|
286
|
+
arguments: { workspaceId: 11, blueprintId: "5668a1ae-3912-4713-b269-f98817b9ccd9" },
|
|
220
287
|
});
|
|
221
288
|
const payload = parseToolJson(result);
|
|
222
289
|
expect(payload.status).toBe("blocked");
|
|
@@ -246,10 +313,10 @@ describe("blueprint tools", () => {
|
|
|
246
313
|
try {
|
|
247
314
|
const result = await client.callTool({
|
|
248
315
|
name: "blueprint_synthesize",
|
|
249
|
-
arguments: { workspaceId: 11, blueprintId: "
|
|
316
|
+
arguments: { workspaceId: 11, blueprintId: "5668a1ae-3912-4713-b269-f98817b9ccd9", replace: true },
|
|
250
317
|
});
|
|
251
318
|
const [url, init] = fetchMock.mock.calls[0];
|
|
252
|
-
expect(String(url)).toBe(`${MW_BASE}${BP}/
|
|
319
|
+
expect(String(url)).toBe(`${MW_BASE}${BP}/5668a1ae-3912-4713-b269-f98817b9ccd9/synthesize`);
|
|
253
320
|
expect(JSON.parse(String(init.body))).toEqual({ replace: true });
|
|
254
321
|
const payload = parseToolJson(result);
|
|
255
322
|
expect(payload.status).toBe("proposal_ready");
|
|
@@ -263,7 +330,7 @@ describe("blueprint tools", () => {
|
|
|
263
330
|
// ── apply-proposal swap guard ──────────────────────────────
|
|
264
331
|
it("blueprint_apply_proposal refuses (without POSTing) when the pending proposal was swapped", async () => {
|
|
265
332
|
const fetchMock = routedFetch({
|
|
266
|
-
"/blueprints/
|
|
333
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9": bpFixture({
|
|
267
334
|
hasPendingProposal: true,
|
|
268
335
|
pendingProposal: {
|
|
269
336
|
patch: {},
|
|
@@ -282,7 +349,7 @@ describe("blueprint tools", () => {
|
|
|
282
349
|
name: "blueprint_apply_proposal",
|
|
283
350
|
arguments: {
|
|
284
351
|
workspaceId: 11,
|
|
285
|
-
blueprintId: "
|
|
352
|
+
blueprintId: "5668a1ae-3912-4713-b269-f98817b9ccd9",
|
|
286
353
|
baseVersion: 2,
|
|
287
354
|
proposalBasedOnSeq: 3,
|
|
288
355
|
},
|
|
@@ -309,7 +376,7 @@ describe("blueprint tools", () => {
|
|
|
309
376
|
createdAt: "2026-08-12T00:00:00Z",
|
|
310
377
|
};
|
|
311
378
|
const fetchMock = routedFetch({
|
|
312
|
-
"/blueprints/
|
|
379
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9/proposal/apply": bpFixture({
|
|
313
380
|
headVersion: 3,
|
|
314
381
|
state: "job_stale",
|
|
315
382
|
document: {
|
|
@@ -318,7 +385,7 @@ describe("blueprint tools", () => {
|
|
|
318
385
|
openQuestions: [],
|
|
319
386
|
},
|
|
320
387
|
}),
|
|
321
|
-
"/blueprints/
|
|
388
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9": bpFixture({
|
|
322
389
|
hasPendingProposal: true,
|
|
323
390
|
pendingProposal,
|
|
324
391
|
}),
|
|
@@ -330,7 +397,7 @@ describe("blueprint tools", () => {
|
|
|
330
397
|
name: "blueprint_apply_proposal",
|
|
331
398
|
arguments: {
|
|
332
399
|
workspaceId: 11,
|
|
333
|
-
blueprintId: "
|
|
400
|
+
blueprintId: "5668a1ae-3912-4713-b269-f98817b9ccd9",
|
|
334
401
|
baseVersion: 2,
|
|
335
402
|
proposalBasedOnSeq: 3,
|
|
336
403
|
},
|
|
@@ -380,7 +447,7 @@ describe("blueprint tools", () => {
|
|
|
380
447
|
name: "blueprint_apply_proposal",
|
|
381
448
|
arguments: {
|
|
382
449
|
workspaceId: 11,
|
|
383
|
-
blueprintId: "
|
|
450
|
+
blueprintId: "5668a1ae-3912-4713-b269-f98817b9ccd9",
|
|
384
451
|
baseVersion: 2,
|
|
385
452
|
proposalBasedOnSeq: 3,
|
|
386
453
|
},
|
|
@@ -421,7 +488,7 @@ describe("blueprint tools", () => {
|
|
|
421
488
|
name: "blueprint_apply_proposal",
|
|
422
489
|
arguments: {
|
|
423
490
|
workspaceId: 11,
|
|
424
|
-
blueprintId: "
|
|
491
|
+
blueprintId: "5668a1ae-3912-4713-b269-f98817b9ccd9",
|
|
425
492
|
baseVersion: 2,
|
|
426
493
|
proposalBasedOnSeq: 3,
|
|
427
494
|
},
|
|
@@ -442,7 +509,7 @@ describe("blueprint tools", () => {
|
|
|
442
509
|
// re-read instead of reporting headVersion: undefined (the next CAS base).
|
|
443
510
|
it("blueprint_update re-reads for headVersion when PATCH returns the raw row", async () => {
|
|
444
511
|
const rawRow = {
|
|
445
|
-
id: "
|
|
512
|
+
id: "5668a1ae-3912-4713-b269-f98817b9ccd9",
|
|
446
513
|
workspaceId: 11,
|
|
447
514
|
name: "COI intake",
|
|
448
515
|
document: { goal: "New goal", steps: [], openQuestions: [] },
|
|
@@ -459,7 +526,7 @@ describe("blueprint tools", () => {
|
|
|
459
526
|
name: "blueprint_update",
|
|
460
527
|
arguments: {
|
|
461
528
|
workspaceId: 11,
|
|
462
|
-
blueprintId: "
|
|
529
|
+
blueprintId: "5668a1ae-3912-4713-b269-f98817b9ccd9",
|
|
463
530
|
patch: { goal: "New goal" },
|
|
464
531
|
baseVersion: 4,
|
|
465
532
|
},
|
|
@@ -491,7 +558,7 @@ describe("blueprint tools", () => {
|
|
|
491
558
|
applied = true;
|
|
492
559
|
// Raw row: no headVersion, no state.
|
|
493
560
|
return jsonResponse({
|
|
494
|
-
id: "
|
|
561
|
+
id: "5668a1ae-3912-4713-b269-f98817b9ccd9",
|
|
495
562
|
workspaceId: 11,
|
|
496
563
|
document: { goal: "Do the thing", steps: [{ id: "s1" }], openQuestions: [] },
|
|
497
564
|
});
|
|
@@ -508,7 +575,7 @@ describe("blueprint tools", () => {
|
|
|
508
575
|
name: "blueprint_apply_proposal",
|
|
509
576
|
arguments: {
|
|
510
577
|
workspaceId: 11,
|
|
511
|
-
blueprintId: "
|
|
578
|
+
blueprintId: "5668a1ae-3912-4713-b269-f98817b9ccd9",
|
|
512
579
|
baseVersion: 2,
|
|
513
580
|
proposalBasedOnSeq: 3,
|
|
514
581
|
},
|
|
@@ -525,7 +592,7 @@ describe("blueprint tools", () => {
|
|
|
525
592
|
});
|
|
526
593
|
it("blueprint_update marks the response partial when the post-write re-read ALSO fails", async () => {
|
|
527
594
|
const rawRow = {
|
|
528
|
-
id: "
|
|
595
|
+
id: "5668a1ae-3912-4713-b269-f98817b9ccd9",
|
|
529
596
|
workspaceId: 11,
|
|
530
597
|
name: "COI intake",
|
|
531
598
|
document: { goal: "New goal", steps: [], openQuestions: [] },
|
|
@@ -542,7 +609,7 @@ describe("blueprint tools", () => {
|
|
|
542
609
|
name: "blueprint_update",
|
|
543
610
|
arguments: {
|
|
544
611
|
workspaceId: 11,
|
|
545
|
-
blueprintId: "
|
|
612
|
+
blueprintId: "5668a1ae-3912-4713-b269-f98817b9ccd9",
|
|
546
613
|
patch: { goal: "New goal" },
|
|
547
614
|
baseVersion: 4,
|
|
548
615
|
},
|
|
@@ -568,7 +635,7 @@ describe("blueprint tools", () => {
|
|
|
568
635
|
try {
|
|
569
636
|
const result = await client.callTool({
|
|
570
637
|
name: "blueprint_reject_proposal",
|
|
571
|
-
arguments: { workspaceId: 11, blueprintId: "
|
|
638
|
+
arguments: { workspaceId: 11, blueprintId: "5668a1ae-3912-4713-b269-f98817b9ccd9" },
|
|
572
639
|
});
|
|
573
640
|
const payload = parseToolJson(result);
|
|
574
641
|
expect(payload.status).toBe("already_gone");
|
|
@@ -588,7 +655,7 @@ describe("blueprint tools", () => {
|
|
|
588
655
|
name: "blueprint_answer_question",
|
|
589
656
|
arguments: {
|
|
590
657
|
workspaceId: 11,
|
|
591
|
-
blueprintId: "
|
|
658
|
+
blueprintId: "5668a1ae-3912-4713-b269-f98817b9ccd9",
|
|
592
659
|
question: "Which account?",
|
|
593
660
|
answer: "The ops account",
|
|
594
661
|
},
|
|
@@ -603,7 +670,7 @@ describe("blueprint tools", () => {
|
|
|
603
670
|
}
|
|
604
671
|
});
|
|
605
672
|
it("blueprint_answer_question propagates a blueprint-missing 404 instead of shaping it as convergence", async () => {
|
|
606
|
-
const fetchMock = vi.fn(async (_input, _init) => jsonResponse({ message: "Blueprint
|
|
673
|
+
const fetchMock = vi.fn(async (_input, _init) => jsonResponse({ message: "Blueprint 5668a1ae-3912-4713-b269-f98817b9ccd9 not found" }, 404));
|
|
607
674
|
vi.stubGlobal("fetch", fetchMock);
|
|
608
675
|
const { client, embedded } = await startServer();
|
|
609
676
|
try {
|
|
@@ -611,7 +678,7 @@ describe("blueprint tools", () => {
|
|
|
611
678
|
name: "blueprint_answer_question",
|
|
612
679
|
arguments: {
|
|
613
680
|
workspaceId: 11,
|
|
614
|
-
blueprintId: "
|
|
681
|
+
blueprintId: "5668a1ae-3912-4713-b269-f98817b9ccd9",
|
|
615
682
|
question: "Which account?",
|
|
616
683
|
answer: "The ops account",
|
|
617
684
|
},
|
|
@@ -626,7 +693,7 @@ describe("blueprint tools", () => {
|
|
|
626
693
|
}
|
|
627
694
|
});
|
|
628
695
|
it("blueprint_apply_proposal propagates a blueprint-missing 404 instead of shaping it as convergence", async () => {
|
|
629
|
-
const fetchMock = vi.fn(async (_input, _init) => jsonResponse({ message: "Blueprint
|
|
696
|
+
const fetchMock = vi.fn(async (_input, _init) => jsonResponse({ message: "Blueprint 5668a1ae-3912-4713-b269-f98817b9ccd9 not found" }, 404));
|
|
630
697
|
vi.stubGlobal("fetch", fetchMock);
|
|
631
698
|
const { client, embedded } = await startServer();
|
|
632
699
|
try {
|
|
@@ -634,7 +701,7 @@ describe("blueprint tools", () => {
|
|
|
634
701
|
name: "blueprint_apply_proposal",
|
|
635
702
|
arguments: {
|
|
636
703
|
workspaceId: 11,
|
|
637
|
-
blueprintId: "
|
|
704
|
+
blueprintId: "5668a1ae-3912-4713-b269-f98817b9ccd9",
|
|
638
705
|
baseVersion: 1,
|
|
639
706
|
proposalBasedOnSeq: 1,
|
|
640
707
|
},
|
|
@@ -663,13 +730,13 @@ describe("blueprint tools", () => {
|
|
|
663
730
|
name: "blueprint_answer_question",
|
|
664
731
|
arguments: {
|
|
665
732
|
workspaceId: 11,
|
|
666
|
-
blueprintId: "
|
|
733
|
+
blueprintId: "5668a1ae-3912-4713-b269-f98817b9ccd9",
|
|
667
734
|
question: "First question?",
|
|
668
735
|
answer: "Answered",
|
|
669
736
|
},
|
|
670
737
|
});
|
|
671
738
|
const [url, init] = fetchMock.mock.calls[0];
|
|
672
|
-
expect(String(url)).toBe(`${MW_BASE}${BP}/
|
|
739
|
+
expect(String(url)).toBe(`${MW_BASE}${BP}/5668a1ae-3912-4713-b269-f98817b9ccd9/questions/answer`);
|
|
673
740
|
expect(JSON.parse(String(init.body))).toEqual({
|
|
674
741
|
question: "First question?",
|
|
675
742
|
answer: "Answered",
|
|
@@ -687,7 +754,7 @@ describe("blueprint tools", () => {
|
|
|
687
754
|
// ── build precondition + handoff artifact ──────────────────
|
|
688
755
|
it("blueprint_build blocks (without syncing) when the linked build run is needs_input", async () => {
|
|
689
756
|
const fetchMock = routedFetch({
|
|
690
|
-
"/blueprints/
|
|
757
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9": bpFixture({
|
|
691
758
|
state: "building",
|
|
692
759
|
buildStatus: "needs_input",
|
|
693
760
|
middlewareId: "mw-1",
|
|
@@ -700,7 +767,7 @@ describe("blueprint tools", () => {
|
|
|
700
767
|
try {
|
|
701
768
|
const result = await client.callTool({
|
|
702
769
|
name: "blueprint_build",
|
|
703
|
-
arguments: { workspaceId: 11, blueprintId: "
|
|
770
|
+
arguments: { workspaceId: 11, blueprintId: "5668a1ae-3912-4713-b269-f98817b9ccd9" },
|
|
704
771
|
});
|
|
705
772
|
// Only the precondition GET — no POST /sync.
|
|
706
773
|
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
@@ -716,13 +783,13 @@ describe("blueprint tools", () => {
|
|
|
716
783
|
});
|
|
717
784
|
it("blueprint_build returns the handoff triple and points at the jobs loop", async () => {
|
|
718
785
|
const fetchMock = routedFetch({
|
|
719
|
-
"/blueprints/
|
|
786
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9/sync": {
|
|
720
787
|
middlewareId: "mw-1",
|
|
721
788
|
routeId: "route-1",
|
|
722
789
|
buildId: "b-2",
|
|
723
790
|
testCaseIds: ["tc-1", "tc-2"],
|
|
724
791
|
},
|
|
725
|
-
"/blueprints/
|
|
792
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9": bpFixture({
|
|
726
793
|
state: "job_stale",
|
|
727
794
|
document: { goal: "Do the thing", steps: [{ id: "s1" }] },
|
|
728
795
|
headVersion: 2,
|
|
@@ -733,7 +800,7 @@ describe("blueprint tools", () => {
|
|
|
733
800
|
try {
|
|
734
801
|
const result = await client.callTool({
|
|
735
802
|
name: "blueprint_build",
|
|
736
|
-
arguments: { workspaceId: 11, blueprintId: "
|
|
803
|
+
arguments: { workspaceId: 11, blueprintId: "5668a1ae-3912-4713-b269-f98817b9ccd9" },
|
|
737
804
|
});
|
|
738
805
|
const payload = parseToolJson(result);
|
|
739
806
|
expect(payload.status).toBe("build_queued");
|
|
@@ -766,7 +833,7 @@ describe("blueprint tools", () => {
|
|
|
766
833
|
try {
|
|
767
834
|
const result = await client.callTool({
|
|
768
835
|
name: "blueprint_build_status",
|
|
769
|
-
arguments: { workspaceId: 11, blueprintId: "
|
|
836
|
+
arguments: { workspaceId: 11, blueprintId: "5668a1ae-3912-4713-b269-f98817b9ccd9" },
|
|
770
837
|
});
|
|
771
838
|
const payload = parseToolJson(result);
|
|
772
839
|
expect(payload.build).toBeNull();
|
|
@@ -787,7 +854,7 @@ describe("blueprint tools", () => {
|
|
|
787
854
|
try {
|
|
788
855
|
const result = await client.callTool({
|
|
789
856
|
name: "resolve_blueprint_state",
|
|
790
|
-
arguments: { workspaceId: 11, blueprintId: "
|
|
857
|
+
arguments: { workspaceId: 11, blueprintId: "5668a1ae-3912-4713-b269-f98817b9ccd9" },
|
|
791
858
|
});
|
|
792
859
|
return parseToolJson(result);
|
|
793
860
|
}
|
|
@@ -809,7 +876,7 @@ describe("blueprint tools", () => {
|
|
|
809
876
|
try {
|
|
810
877
|
const result = await client.callTool({
|
|
811
878
|
name: "resolve_blueprint_state",
|
|
812
|
-
arguments: { workspaceId: 11, blueprintId: "
|
|
879
|
+
arguments: { workspaceId: 11, blueprintId: "5668a1ae-3912-4713-b269-f98817b9ccd9" },
|
|
813
880
|
});
|
|
814
881
|
const payload = parseToolJson(result);
|
|
815
882
|
// The empty spec + unreadable library must NOT unfold to no_context
|
|
@@ -846,7 +913,7 @@ describe("blueprint tools", () => {
|
|
|
846
913
|
try {
|
|
847
914
|
const result = await client.callTool({
|
|
848
915
|
name: "resolve_blueprint_state",
|
|
849
|
-
arguments: { workspaceId: 11, blueprintId: "
|
|
916
|
+
arguments: { workspaceId: 11, blueprintId: "5668a1ae-3912-4713-b269-f98817b9ccd9" },
|
|
850
917
|
});
|
|
851
918
|
const payload = parseToolJson(result);
|
|
852
919
|
// An unreadable linked build must NOT unfold to a normal lifecycle
|
|
@@ -864,18 +931,18 @@ describe("blueprint tools", () => {
|
|
|
864
931
|
});
|
|
865
932
|
it("empty blueprint -> no_context -> feed the library", async () => {
|
|
866
933
|
const payload = await resolve({
|
|
867
|
-
"/blueprints/
|
|
868
|
-
"/blueprints/
|
|
934
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9/entries": [],
|
|
935
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9": bpFixture(),
|
|
869
936
|
});
|
|
870
937
|
expect(payload.state).toBe("no_context");
|
|
871
938
|
expect(payload.nextActions.join("\n")).toContain("blueprint_add_entry");
|
|
872
939
|
});
|
|
873
940
|
it("pending entries -> enriching -> poll the library", async () => {
|
|
874
941
|
const payload = await resolve({
|
|
875
|
-
"/blueprints/
|
|
942
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9/entries": [
|
|
876
943
|
{ id: "e1", kind: "video", title: "Loom", status: "pending", seq: 1 },
|
|
877
944
|
],
|
|
878
|
-
"/blueprints/
|
|
945
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9": bpFixture({
|
|
879
946
|
librarySeq: 1,
|
|
880
947
|
specStale: true,
|
|
881
948
|
state: "spec_stale",
|
|
@@ -887,10 +954,10 @@ describe("blueprint tools", () => {
|
|
|
887
954
|
});
|
|
888
955
|
it("ready library + empty spec -> no_spec -> synthesize", async () => {
|
|
889
956
|
const payload = await resolve({
|
|
890
|
-
"/blueprints/
|
|
957
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9/entries": [
|
|
891
958
|
{ id: "e1", kind: "doc", title: "SOP", status: "ready", seq: 1 },
|
|
892
959
|
],
|
|
893
|
-
"/blueprints/
|
|
960
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9": bpFixture({
|
|
894
961
|
librarySeq: 1,
|
|
895
962
|
specStale: true,
|
|
896
963
|
state: "spec_stale",
|
|
@@ -901,10 +968,10 @@ describe("blueprint tools", () => {
|
|
|
901
968
|
});
|
|
902
969
|
it("pending proposal -> proposal_pending with prefilled apply coordinates", async () => {
|
|
903
970
|
const payload = await resolve({
|
|
904
|
-
"/blueprints/
|
|
971
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9/entries": [
|
|
905
972
|
{ id: "e1", kind: "doc", title: "SOP", status: "ready", seq: 1 },
|
|
906
973
|
],
|
|
907
|
-
"/blueprints/
|
|
974
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9": bpFixture({
|
|
908
975
|
hasPendingProposal: true,
|
|
909
976
|
pendingProposal: {
|
|
910
977
|
patch: {},
|
|
@@ -924,10 +991,10 @@ describe("blueprint tools", () => {
|
|
|
924
991
|
});
|
|
925
992
|
it("open questions -> needs_answers with one answer call per question, then ONE synthesize", async () => {
|
|
926
993
|
const payload = await resolve({
|
|
927
|
-
"/blueprints/
|
|
994
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9/entries": [
|
|
928
995
|
{ id: "e1", kind: "doc", title: "SOP", status: "ready", seq: 1 },
|
|
929
996
|
],
|
|
930
|
-
"/blueprints/
|
|
997
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9": bpFixture({
|
|
931
998
|
document: {
|
|
932
999
|
goal: "Do the thing",
|
|
933
1000
|
steps: [{ id: "s1" }],
|
|
@@ -948,10 +1015,10 @@ describe("blueprint tools", () => {
|
|
|
948
1015
|
status: "needs_input",
|
|
949
1016
|
questions: [{ id: "q1", text: "Which credentials?" }],
|
|
950
1017
|
},
|
|
951
|
-
"/blueprints/
|
|
1018
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9/entries": [
|
|
952
1019
|
{ id: "e1", kind: "doc", title: "SOP", status: "ready", seq: 1 },
|
|
953
1020
|
],
|
|
954
|
-
"/blueprints/
|
|
1021
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9": bpFixture({
|
|
955
1022
|
state: "building",
|
|
956
1023
|
buildStatus: "needs_input",
|
|
957
1024
|
middlewareId: "mw-1",
|
|
@@ -969,11 +1036,11 @@ describe("blueprint tools", () => {
|
|
|
969
1036
|
// The service folds !routeId to never_synced regardless of drift; the
|
|
970
1037
|
// specStale boolean is what must drive the synthesize-first branch.
|
|
971
1038
|
const payload = await resolve({
|
|
972
|
-
"/blueprints/
|
|
1039
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9/entries": [
|
|
973
1040
|
{ id: "e1", kind: "doc", title: "SOP", status: "ready", seq: 1 },
|
|
974
1041
|
{ id: "e2", kind: "note", title: "Late addition", status: "ready", seq: 2 },
|
|
975
1042
|
],
|
|
976
|
-
"/blueprints/
|
|
1043
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9": bpFixture({
|
|
977
1044
|
state: "never_synced",
|
|
978
1045
|
specStale: true,
|
|
979
1046
|
headVersion: 1,
|
|
@@ -992,10 +1059,10 @@ describe("blueprint tools", () => {
|
|
|
992
1059
|
});
|
|
993
1060
|
it("never_synced with a ready spec -> job_stale -> blueprint_build", async () => {
|
|
994
1061
|
const payload = await resolve({
|
|
995
|
-
"/blueprints/
|
|
1062
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9/entries": [
|
|
996
1063
|
{ id: "e1", kind: "doc", title: "SOP", status: "ready", seq: 1 },
|
|
997
1064
|
],
|
|
998
|
-
"/blueprints/
|
|
1065
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9": bpFixture({
|
|
999
1066
|
document: {
|
|
1000
1067
|
goal: "Do the thing",
|
|
1001
1068
|
steps: [{ id: "s1" }],
|
|
@@ -1009,7 +1076,7 @@ describe("blueprint tools", () => {
|
|
|
1009
1076
|
});
|
|
1010
1077
|
it("spec_stale from answer notes only -> flags answerNotesOnly and one synthesize", async () => {
|
|
1011
1078
|
const payload = await resolve({
|
|
1012
|
-
"/blueprints/
|
|
1079
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9/entries": [
|
|
1013
1080
|
{
|
|
1014
1081
|
id: "e2",
|
|
1015
1082
|
kind: "note",
|
|
@@ -1019,7 +1086,7 @@ describe("blueprint tools", () => {
|
|
|
1019
1086
|
content: { answersQuestion: "Which account?" },
|
|
1020
1087
|
},
|
|
1021
1088
|
],
|
|
1022
|
-
"/blueprints/
|
|
1089
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9": bpFixture({
|
|
1023
1090
|
state: "spec_stale",
|
|
1024
1091
|
specStale: true,
|
|
1025
1092
|
routeId: "route-1",
|
|
@@ -1044,10 +1111,10 @@ describe("blueprint tools", () => {
|
|
|
1044
1111
|
});
|
|
1045
1112
|
it("job_ahead -> import-cases fold-back or rebuild", async () => {
|
|
1046
1113
|
const payload = await resolve({
|
|
1047
|
-
"/blueprints/
|
|
1114
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9/entries": [
|
|
1048
1115
|
{ id: "e1", kind: "doc", title: "SOP", status: "ready", seq: 1 },
|
|
1049
1116
|
],
|
|
1050
|
-
"/blueprints/
|
|
1117
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9": bpFixture({
|
|
1051
1118
|
state: "job_ahead",
|
|
1052
1119
|
jobEditedDirectly: true,
|
|
1053
1120
|
routeId: "route-1",
|
|
@@ -1062,7 +1129,7 @@ describe("blueprint tools", () => {
|
|
|
1062
1129
|
});
|
|
1063
1130
|
it("failed enrichment surfaces an enrichment_failed blocker", async () => {
|
|
1064
1131
|
const payload = await resolve({
|
|
1065
|
-
"/blueprints/
|
|
1132
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9/entries": [
|
|
1066
1133
|
{ id: "e1", kind: "doc", title: "SOP", status: "ready", seq: 1 },
|
|
1067
1134
|
{
|
|
1068
1135
|
id: "e2",
|
|
@@ -1073,7 +1140,7 @@ describe("blueprint tools", () => {
|
|
|
1073
1140
|
seq: 2,
|
|
1074
1141
|
},
|
|
1075
1142
|
],
|
|
1076
|
-
"/blueprints/
|
|
1143
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9": bpFixture({
|
|
1077
1144
|
document: { goal: "g", steps: [{ id: "s1" }] },
|
|
1078
1145
|
}),
|
|
1079
1146
|
});
|
|
@@ -1088,10 +1155,10 @@ describe("blueprint tools", () => {
|
|
|
1088
1155
|
status: "queued",
|
|
1089
1156
|
createdAt: new Date(Date.now() - 10 * 60 * 1000).toISOString(),
|
|
1090
1157
|
},
|
|
1091
|
-
"/blueprints/
|
|
1158
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9/entries": [
|
|
1092
1159
|
{ id: "e1", kind: "doc", title: "SOP", status: "ready", seq: 1 },
|
|
1093
1160
|
],
|
|
1094
|
-
"/blueprints/
|
|
1161
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9": bpFixture({
|
|
1095
1162
|
state: "building",
|
|
1096
1163
|
buildStatus: "queued",
|
|
1097
1164
|
middlewareId: "mw-1",
|
|
@@ -1108,10 +1175,10 @@ describe("blueprint tools", () => {
|
|
|
1108
1175
|
it("in_sync -> nothing to do, with the job-side handoff", async () => {
|
|
1109
1176
|
const payload = await resolve({
|
|
1110
1177
|
"/routes/route-1/builds/b-1": { id: "b-1", status: "green" },
|
|
1111
|
-
"/blueprints/
|
|
1178
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9/entries": [
|
|
1112
1179
|
{ id: "e1", kind: "doc", title: "SOP", status: "ready", seq: 1 },
|
|
1113
1180
|
],
|
|
1114
|
-
"/blueprints/
|
|
1181
|
+
"/blueprints/5668a1ae-3912-4713-b269-f98817b9ccd9": bpFixture({
|
|
1115
1182
|
state: "in_sync",
|
|
1116
1183
|
routeId: "route-1",
|
|
1117
1184
|
middlewareId: "mw-1",
|
|
@@ -1146,7 +1213,7 @@ describe("blueprint tools", () => {
|
|
|
1146
1213
|
"/routes": [{ id: "route-1", method: "POST", path: "/coi" }],
|
|
1147
1214
|
"/api/workspaces/11/blueprints": [
|
|
1148
1215
|
{
|
|
1149
|
-
id: "
|
|
1216
|
+
id: "be9b3716-a487-4eac-886d-e6324bdc01d9",
|
|
1150
1217
|
name: "COI intake",
|
|
1151
1218
|
state: "in_sync",
|
|
1152
1219
|
middlewareId: "mw-1",
|
|
@@ -1167,19 +1234,19 @@ describe("blueprint tools", () => {
|
|
|
1167
1234
|
});
|
|
1168
1235
|
const payload = parseToolJson(result);
|
|
1169
1236
|
expect(payload.blueprint).toEqual({
|
|
1170
|
-
blueprintId: "
|
|
1237
|
+
blueprintId: "be9b3716-a487-4eac-886d-e6324bdc01d9",
|
|
1171
1238
|
state: "in_sync",
|
|
1172
|
-
hint: expect.stringContaining("resolve_blueprint_state blueprintId=
|
|
1239
|
+
hint: expect.stringContaining("resolve_blueprint_state blueprintId=be9b3716-a487-4eac-886d-e6324bdc01d9"),
|
|
1173
1240
|
});
|
|
1174
1241
|
const actions = payload.nextActions.join("\n");
|
|
1175
|
-
expect(actions).toContain("OWNED by blueprint
|
|
1242
|
+
expect(actions).toContain("OWNED by blueprint be9b3716-a487-4eac-886d-e6324bdc01d9");
|
|
1176
1243
|
// The route has no test cases and no definition — on an owned route the
|
|
1177
1244
|
// resolver must route BOTH gaps through the spec, never recommend the
|
|
1178
1245
|
// direct job edits its own ownership warning forbids.
|
|
1179
1246
|
expect(actions).not.toContain("add_test_case (input + assertions)");
|
|
1180
1247
|
expect(actions).not.toContain("teach_job (example input + intent)");
|
|
1181
1248
|
expect(actions).not.toContain("update_job variant=draft with a step graph");
|
|
1182
|
-
expect(actions).toContain("blueprint_build blueprintId=
|
|
1249
|
+
expect(actions).toContain("blueprint_build blueprintId=be9b3716-a487-4eac-886d-e6324bdc01d9");
|
|
1183
1250
|
}
|
|
1184
1251
|
finally {
|
|
1185
1252
|
await client.close();
|