yaml-flow 8.5.0 → 8.5.2
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/browser/asset-integrity.json +3 -3
- package/browser/board-livecards-client.js +1 -1
- package/cli/browser-api/board-live-cards-browser-adapter.d.ts +1 -1
- package/cli/bundled/board-live-cards-cli.mjs +14 -14
- package/cli/bundled/chat-store-cli.mjs +13 -13
- package/cli/{types-D2s3VzyY.d.ts → types-H3EMBPY2.d.ts} +7 -2
- package/examples/board/demo-shell-with-server.html +2 -2
- package/examples/board/doc.html +2 -2
- package/examples/board/server/README-mcp-api.md +680 -0
- package/examples/board/test/server-http-mcp-test.js +406 -34
- package/examples/board-local/demo-shell-localstorage.html +3 -3
- package/lib/artifacts-store-public.d.cts +1 -1
- package/lib/artifacts-store-public.d.ts +1 -1
- package/lib/board-live-cards-mcp.cjs +1 -1
- package/lib/board-live-cards-mcp.d.cts +42 -5
- package/lib/board-live-cards-mcp.d.ts +42 -5
- package/lib/board-live-cards-mcp.js +1 -1
- package/lib/board-live-cards-node.cjs +14 -14
- package/lib/board-live-cards-node.d.cts +4 -4
- package/lib/board-live-cards-node.d.ts +4 -4
- package/lib/board-live-cards-node.js +14 -14
- package/lib/{board-live-cards-public-CvkDfZQ7.d.cts → board-live-cards-public-B13InXhC.d.cts} +7 -2
- package/lib/{board-live-cards-public-DdVhH4M-.d.ts → board-live-cards-public-BGS22cMb.d.ts} +7 -2
- package/lib/board-live-cards-public.cjs +2 -2
- package/lib/board-live-cards-public.d.cts +1 -1
- package/lib/board-live-cards-public.d.ts +1 -1
- package/lib/board-live-cards-public.js +2 -2
- package/lib/board-live-cards-server-runtime.cjs +4 -4
- package/lib/board-live-cards-server-runtime.d.cts +2 -2
- package/lib/board-live-cards-server-runtime.d.ts +2 -2
- package/lib/board-live-cards-server-runtime.js +4 -4
- package/lib/card-store-public.d.cts +1 -1
- package/lib/card-store-public.d.ts +1 -1
- package/lib/chat-store-public.cjs +1 -1
- package/lib/chat-store-public.d.cts +6 -1
- package/lib/chat-store-public.d.ts +6 -1
- package/lib/chat-store-public.js +1 -1
- package/lib/server-runtime/index.cjs +4 -4
- package/lib/server-runtime/index.d.cts +3 -3
- package/lib/server-runtime/index.d.ts +3 -3
- package/lib/server-runtime/index.js +4 -4
- package/lib/{types-QNI__eAf.d.ts → types-30R357js.d.ts} +1 -1
- package/lib/{types-NM_d_1oZ.d.cts → types-CIgsh56O.d.cts} +1 -1
- package/package.json +1 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
name: 'portfolio variant B',
|
|
4
|
+
card: portfolioVariantB,
|
|
5
5
|
* Smoke test for demo-board/server/board-server.js over HTTP + SSE.
|
|
6
6
|
* Targets the 'live' board with --cards-pattern cardT* to load only the 3
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
assert(Array.isArray(body.provides_outputs?.holdings) && body.provides_outputs.holdings.length === baseHoldings.length + 1, 'T4 run-cycle portfolio variant B provides mismatch');
|
|
8
|
+
assert(body.rendered_view?.elements?.[0]?.kind === 'editable-table', 'T4 run-cycle portfolio variant B rendered_view mismatch');
|
|
9
9
|
* T0: init-board -> SSE initial payload -> wait for all cards to complete
|
|
10
10
|
* T1: mutate holdings in memory -> manage.upsert-card over MCP -> verify recomputation
|
|
11
11
|
*
|
|
@@ -34,6 +34,7 @@ const cliPort = portArg !== -1 ? parseInt(cliArgs[portArg + 1], 10) : NaN;
|
|
|
34
34
|
const skipT1 = cliArgs.includes('--skip-t1');
|
|
35
35
|
const skipT2 = cliArgs.includes('--skip-t2');
|
|
36
36
|
const skipT3 = cliArgs.includes('--skip-t3');
|
|
37
|
+
const skipT4 = cliArgs.includes('--skip-t4');
|
|
37
38
|
function isCopilotAvailable() {
|
|
38
39
|
try {
|
|
39
40
|
const r = spawnSync('copilot', ['--version'], { timeout: 5_000, stdio: 'ignore', windowsHide: true });
|
|
@@ -378,6 +379,16 @@ function httpUploadChatFile(url, fileName, content, contentType = 'text/plain; c
|
|
|
378
379
|
});
|
|
379
380
|
}
|
|
380
381
|
|
|
382
|
+
function deepCloneJson(value) {
|
|
383
|
+
return JSON.parse(JSON.stringify(value));
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function expectMcpSuccess(httpResult, label) {
|
|
387
|
+
assert(httpResult.status === 200, `${label} returned ${httpResult.status}`);
|
|
388
|
+
assert(httpResult.data?.status === 'success', `${label} expected status=success, got ${JSON.stringify(httpResult.data)}`);
|
|
389
|
+
return httpResult.data.data;
|
|
390
|
+
}
|
|
391
|
+
|
|
381
392
|
function startServer(port) {
|
|
382
393
|
return new Promise((resolve, reject) => {
|
|
383
394
|
const proc = spawn(process.execPath, [SERVER_SCRIPT], {
|
|
@@ -456,8 +467,8 @@ try {
|
|
|
456
467
|
|
|
457
468
|
console.log('\n=== T0 Step 4: board-status cross-check ===');
|
|
458
469
|
const statusRes = await httpMcp('inspect.board-runtime-status', {});
|
|
459
|
-
|
|
460
|
-
const httpSummary =
|
|
470
|
+
const statusData = expectMcpSuccess(statusRes, 'inspect.board-runtime-status');
|
|
471
|
+
const httpSummary = statusData?.summary;
|
|
461
472
|
assert(httpSummary, 'statusSnapshot.summary missing from board-status');
|
|
462
473
|
assert(httpSummary.completed === httpSummary.card_count, `not all complete: ${JSON.stringify(httpSummary)}`);
|
|
463
474
|
console.log(`[T0.4] board-status: ${JSON.stringify(httpSummary)}`);
|
|
@@ -471,9 +482,8 @@ try {
|
|
|
471
482
|
} else {
|
|
472
483
|
console.log('\n=== T1: local mutation + manage.upsert-card (+1 row) ===');
|
|
473
484
|
|
|
474
|
-
const portfolioCardRes = await httpMcp('
|
|
475
|
-
|
|
476
|
-
const existingCard = Array.isArray(portfolioCardRes.data) ? portfolioCardRes.data[0] : null;
|
|
485
|
+
const portfolioCardRes = await httpMcp('inspect.card-definition-and-runtime', { card_id: 'card-portfolio' });
|
|
486
|
+
const existingCard = expectMcpSuccess(portfolioCardRes, 'inspect.card-definition-and-runtime')?.card_definition_and_static_data ?? null;
|
|
477
487
|
const existingHoldings = existingCard?.card_data?.holdings;
|
|
478
488
|
assert(Array.isArray(existingHoldings), 'card-portfolio.card_data.holdings missing');
|
|
479
489
|
const t0HoldingsCount = existingHoldings.length;
|
|
@@ -510,9 +520,8 @@ try {
|
|
|
510
520
|
const t1Summary = await waitForAllCompleted(30_000, 'T1 holdings upsert');
|
|
511
521
|
assert(t1Summary.failed === 0, `T1 failed=${t1Summary.failed}`);
|
|
512
522
|
|
|
513
|
-
const t1PortfolioRes = await httpMcp('
|
|
514
|
-
|
|
515
|
-
const afterCard = Array.isArray(t1PortfolioRes.data) ? t1PortfolioRes.data[0] : null;
|
|
523
|
+
const t1PortfolioRes = await httpMcp('inspect.card-definition-and-runtime', { card_id: 'card-portfolio' });
|
|
524
|
+
const afterCard = expectMcpSuccess(t1PortfolioRes, 'inspect.card-definition-and-runtime after upsert')?.card_definition_and_static_data ?? null;
|
|
516
525
|
const afterHoldings = afterCard?.card_data?.holdings;
|
|
517
526
|
const afterHoldingsCount = Array.isArray(afterHoldings) ? afterHoldings.length : 0;
|
|
518
527
|
|
|
@@ -532,8 +541,8 @@ try {
|
|
|
532
541
|
} else {
|
|
533
542
|
console.log('\n=== T2: plain file upload -> card_data.files -> download ===');
|
|
534
543
|
const t2CardBefore = await httpMcp('manage.read-card', { card_id: T2_FILE_CARD_ID });
|
|
535
|
-
|
|
536
|
-
const t2CardBeforeObj = Array.isArray(
|
|
544
|
+
const t2CardBeforeData = expectMcpSuccess(t2CardBefore, 'T2 pre card read');
|
|
545
|
+
const t2CardBeforeObj = Array.isArray(t2CardBeforeData) ? t2CardBeforeData[0] : null;
|
|
537
546
|
const t2FilesBefore = Array.isArray(t2CardBeforeObj?.card_data?.files) ? t2CardBeforeObj.card_data.files : [];
|
|
538
547
|
const t2BeforeCount = t2FilesBefore.length;
|
|
539
548
|
|
|
@@ -545,14 +554,14 @@ try {
|
|
|
545
554
|
content_type: 'text/plain; charset=utf-8',
|
|
546
555
|
text: t2UploadText,
|
|
547
556
|
});
|
|
548
|
-
|
|
549
|
-
const t2UploadedFile =
|
|
557
|
+
const t2UploadData = expectMcpSuccess(t2UploadRes, 'T2 file upload');
|
|
558
|
+
const t2UploadedFile = t2UploadData?.file;
|
|
550
559
|
assert(t2UploadedFile && typeof t2UploadedFile === 'object', 'T2 upload response missing file metadata');
|
|
551
560
|
assert(String(t2UploadedFile?.name || '') === t2UploadName, 'T2 uploaded file name mismatch');
|
|
552
561
|
|
|
553
562
|
const t2CardAfter = await httpMcp('manage.read-card', { card_id: T2_FILE_CARD_ID });
|
|
554
|
-
|
|
555
|
-
const t2CardAfterObj = Array.isArray(
|
|
563
|
+
const t2CardAfterData = expectMcpSuccess(t2CardAfter, 'T2 post card read');
|
|
564
|
+
const t2CardAfterObj = Array.isArray(t2CardAfterData) ? t2CardAfterData[0] : null;
|
|
556
565
|
const t2FilesAfter = Array.isArray(t2CardAfterObj?.card_data?.files) ? t2CardAfterObj.card_data.files : [];
|
|
557
566
|
assert(t2FilesAfter.length === t2BeforeCount + 1, `T2 expected files +1 (before=${t2BeforeCount}, after=${t2FilesAfter.length})`);
|
|
558
567
|
|
|
@@ -584,8 +593,8 @@ try {
|
|
|
584
593
|
assert(subRes.status === 200, `chat subscribe returned ${subRes.status}`);
|
|
585
594
|
|
|
586
595
|
const t3Before = await httpMcp('inspect.chat-messages-on-cards', { card_id: CHAT_CARD_ID, 'all-turns': true });
|
|
587
|
-
|
|
588
|
-
const t3BeforeMessages = Array.isArray(
|
|
596
|
+
const t3BeforeData = expectMcpSuccess(t3Before, 'T3 MCP pre chats');
|
|
597
|
+
const t3BeforeMessages = Array.isArray(t3BeforeData?.messages) ? t3BeforeData.messages : [];
|
|
589
598
|
const t3BeforeCount = t3BeforeMessages.length;
|
|
590
599
|
const t3EventStart = NS.chatEvents.length;
|
|
591
600
|
const t3ProbePrompt = `Probe protocol validation ${Date.now()}`;
|
|
@@ -611,8 +620,8 @@ try {
|
|
|
611
620
|
assert(!!t3Lifecycle, 'T3 ordered lifecycle not observed');
|
|
612
621
|
|
|
613
622
|
const t3After = await httpMcp('inspect.chat-messages-on-cards', { card_id: CHAT_CARD_ID, 'all-turns': true });
|
|
614
|
-
|
|
615
|
-
const t3AfterMessages = Array.isArray(
|
|
623
|
+
const t3AfterData = expectMcpSuccess(t3After, 'T3 MCP post chats');
|
|
624
|
+
const t3AfterMessages = Array.isArray(t3AfterData?.messages) ? t3AfterData.messages : [];
|
|
616
625
|
const t3NewMessages = t3AfterMessages.slice(t3BeforeCount);
|
|
617
626
|
assert(t3NewMessages.length >= 3, `T3 expected at least 3 new chat messages, got ${t3NewMessages.length}`);
|
|
618
627
|
const t3User = t3NewMessages.find((m) => m?.role === 'user');
|
|
@@ -634,8 +643,8 @@ try {
|
|
|
634
643
|
} else {
|
|
635
644
|
console.log('\n=== T3a: non-probe chat protocol (expect paris) ===');
|
|
636
645
|
const t3aBefore = await httpMcp('inspect.chat-messages-on-cards', { card_id: CHAT_CARD_ID, 'all-turns': true });
|
|
637
|
-
|
|
638
|
-
const t3aBeforeMessages = Array.isArray(
|
|
646
|
+
const t3aBeforeData = expectMcpSuccess(t3aBefore, 'T3a MCP pre chats');
|
|
647
|
+
const t3aBeforeMessages = Array.isArray(t3aBeforeData?.messages) ? t3aBeforeData.messages : [];
|
|
639
648
|
const t3aBeforeCount = t3aBeforeMessages.length;
|
|
640
649
|
const t3aPrompt = 'Just answer what is the capital of France. No Fluff. No COmmentary. No Markup Respond in lower case in one word.';
|
|
641
650
|
const t3aTurnId = randomTurnId();
|
|
@@ -664,8 +673,8 @@ try {
|
|
|
664
673
|
assert(!!t3aAssistant, 'T3a assistant response with paris not observed on SSE');
|
|
665
674
|
|
|
666
675
|
const t3aAfter = await httpMcp('inspect.chat-messages-on-cards', { card_id: CHAT_CARD_ID, 'all-turns': true });
|
|
667
|
-
|
|
668
|
-
const t3aAfterMessages = Array.isArray(
|
|
676
|
+
const t3aAfterData = expectMcpSuccess(t3aAfter, 'T3a MCP post chats');
|
|
677
|
+
const t3aAfterMessages = Array.isArray(t3aAfterData?.messages) ? t3aAfterData.messages : [];
|
|
669
678
|
const t3aNewMessages = t3aAfterMessages.slice(t3aBeforeCount);
|
|
670
679
|
assert(t3aNewMessages.length >= 2, `T3a expected at least 2 new chat messages, got ${t3aNewMessages.length}`);
|
|
671
680
|
const t3aUser = t3aNewMessages.find((m) => m?.role === 'user');
|
|
@@ -686,8 +695,8 @@ try {
|
|
|
686
695
|
} else {
|
|
687
696
|
console.log('\n=== T3b: probe-echo chat with file upload protocol ===');
|
|
688
697
|
const t3bBefore = await httpMcp('inspect.chat-messages-on-cards', { card_id: CHAT_CARD_ID, 'all-turns': true });
|
|
689
|
-
|
|
690
|
-
const t3bBeforeMessages = Array.isArray(
|
|
698
|
+
const t3bBeforeData = expectMcpSuccess(t3bBefore, 'T3b MCP pre chats');
|
|
699
|
+
const t3bBeforeMessages = Array.isArray(t3bBeforeData?.messages) ? t3bBeforeData.messages : [];
|
|
691
700
|
const t3bBeforeCount = t3bBeforeMessages.length;
|
|
692
701
|
const t3bTurnId = randomTurnId();
|
|
693
702
|
|
|
@@ -701,8 +710,8 @@ try {
|
|
|
701
710
|
assert(uploadedFile && typeof uploadedFile === 'object', 'T3b upload response missing file metadata');
|
|
702
711
|
|
|
703
712
|
const t3bAfterUpload = await httpMcp('inspect.chat-messages-on-cards', { card_id: CHAT_CARD_ID, 'all-turns': true });
|
|
704
|
-
|
|
705
|
-
const t3bUploadMessages = Array.isArray(
|
|
713
|
+
const t3bAfterUploadData = expectMcpSuccess(t3bAfterUpload, 'T3b MCP chats after upload');
|
|
714
|
+
const t3bUploadMessages = Array.isArray(t3bAfterUploadData?.messages) ? t3bAfterUploadData.messages : [];
|
|
706
715
|
const t3bUploadNewMessages = t3bUploadMessages.slice(t3bBeforeCount);
|
|
707
716
|
const t3bUploadSystem = t3bUploadNewMessages.find((m) => m?.role === 'system');
|
|
708
717
|
assert(!!t3bUploadSystem, 'T3b upload protocol missing system chat file');
|
|
@@ -710,8 +719,8 @@ try {
|
|
|
710
719
|
assert(String(t3bUploadSystem?.turn || '') === t3bTurnId, 'T3b upload system turn id mismatch');
|
|
711
720
|
|
|
712
721
|
const t3bCardAfterUpload = await httpMcp('manage.read-card', { card_id: CHAT_CARD_ID });
|
|
713
|
-
|
|
714
|
-
const t3bCardAfterUploadValue = Array.isArray(
|
|
722
|
+
const t3bCardAfterUploadData = expectMcpSuccess(t3bCardAfterUpload, 'T3b manage.read-card after upload');
|
|
723
|
+
const t3bCardAfterUploadValue = Array.isArray(t3bCardAfterUploadData) ? t3bCardAfterUploadData[0] : null;
|
|
715
724
|
const t3bFilesAfterUpload = Array.isArray(t3bCardAfterUploadValue?.card_data?.files)
|
|
716
725
|
? t3bCardAfterUploadValue.card_data.files
|
|
717
726
|
: [];
|
|
@@ -751,8 +760,8 @@ try {
|
|
|
751
760
|
assert(!!t3bLifecycle, 'T3b ordered lifecycle not observed');
|
|
752
761
|
|
|
753
762
|
const t3bAfter = await httpMcp('inspect.chat-messages-on-cards', { card_id: CHAT_CARD_ID, 'all-turns': true });
|
|
754
|
-
|
|
755
|
-
const t3bAfterMessages = Array.isArray(
|
|
763
|
+
const t3bAfterData = expectMcpSuccess(t3bAfter, 'T3b MCP post chats');
|
|
764
|
+
const t3bAfterMessages = Array.isArray(t3bAfterData?.messages) ? t3bAfterData.messages : [];
|
|
756
765
|
const t3bNewMessages = t3bAfterMessages.slice(t3bSendBaseline);
|
|
757
766
|
assert(t3bNewMessages.length >= 3, `T3b expected at least 3 chat messages after send, got ${t3bNewMessages.length}`);
|
|
758
767
|
|
|
@@ -772,6 +781,369 @@ try {
|
|
|
772
781
|
}
|
|
773
782
|
}
|
|
774
783
|
|
|
784
|
+
if (skipT4) {
|
|
785
|
+
console.log('\n=== T4: skipped (--skip-t4) ===');
|
|
786
|
+
} else {
|
|
787
|
+
console.log('\n=== T4: preflight MCP smoke checks ===');
|
|
788
|
+
|
|
789
|
+
const discoverSourceKindsData = expectMcpSuccess(
|
|
790
|
+
await httpMcp('discover.source-kinds', {}),
|
|
791
|
+
'T4 discover.source-kinds',
|
|
792
|
+
);
|
|
793
|
+
assert(discoverSourceKindsData && typeof discoverSourceKindsData === 'object', 'T4 discover.source-kinds missing payload');
|
|
794
|
+
assert(discoverSourceKindsData.sourceKinds && typeof discoverSourceKindsData.sourceKinds === 'object', 'T4 discover.source-kinds missing sourceKinds');
|
|
795
|
+
const discoveredSourceKinds = Object.keys(discoverSourceKindsData.sourceKinds).sort();
|
|
796
|
+
assert(
|
|
797
|
+
JSON.stringify(discoveredSourceKinds) === JSON.stringify(['mock', 'sqlite', 'urls']),
|
|
798
|
+
`T4 discover.source-kinds mismatch: ${JSON.stringify(discoveredSourceKinds)}`,
|
|
799
|
+
);
|
|
800
|
+
console.log('[T4.discover] ok: source kinds match demo task executor');
|
|
801
|
+
|
|
802
|
+
const getCardDefinition = (fileName) => {
|
|
803
|
+
const filePath = path.join(BOARD_DIR, 'cards', fileName);
|
|
804
|
+
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
805
|
+
return JSON.parse(raw);
|
|
806
|
+
};
|
|
807
|
+
|
|
808
|
+
const expectPreflightSuccess = (res, label) => {
|
|
809
|
+
assert(res.status === 200, `${label} returned ${res.status}`);
|
|
810
|
+
assert(res.data?.status === 'success', `${label} expected status=success, got ${JSON.stringify(res.data)}`);
|
|
811
|
+
assert(res.data?.data && typeof res.data.data === 'object', `${label} missing success data`);
|
|
812
|
+
return res.data.data;
|
|
813
|
+
};
|
|
814
|
+
|
|
815
|
+
const portfolioCard = getCardDefinition('cardT-portfolio.json');
|
|
816
|
+
const marketCard = getCardDefinition('cardT-market-prices.json');
|
|
817
|
+
const portfolioValueCard = getCardDefinition('cardT-portfolio-value.json');
|
|
818
|
+
const baseHoldings = Array.isArray(portfolioCard?.card_data?.holdings) ? deepCloneJson(portfolioCard.card_data.holdings) : [];
|
|
819
|
+
|
|
820
|
+
const mockQuotes = {
|
|
821
|
+
quoteResponse: {
|
|
822
|
+
result: [
|
|
823
|
+
{ symbol: 'AAPL', shortName: 'Apple Inc.', regularMarketPrice: 198.15, regularMarketChange: 2.15, regularMarketChangePercent: 1.10 },
|
|
824
|
+
{ symbol: 'MSFT', shortName: 'Microsoft Corp.', regularMarketPrice: 415.32, regularMarketChange: -1.23, regularMarketChangePercent: -0.30 },
|
|
825
|
+
{ symbol: 'GOOGL', shortName: 'Alphabet Inc.', regularMarketPrice: 174.89, regularMarketChange: 0.89, regularMarketChangePercent: 0.51 },
|
|
826
|
+
{ symbol: 'TSLA', shortName: 'Tesla Inc.', regularMarketPrice: 247.12, regularMarketChange: 5.43, regularMarketChangePercent: 2.25 },
|
|
827
|
+
],
|
|
828
|
+
error: null,
|
|
829
|
+
},
|
|
830
|
+
};
|
|
831
|
+
|
|
832
|
+
const makePortfolioVariant = (id, extraHolding) => {
|
|
833
|
+
const card = deepCloneJson(portfolioCard);
|
|
834
|
+
card.id = id;
|
|
835
|
+
card.card_data.holdings = [...baseHoldings, extraHolding];
|
|
836
|
+
return card;
|
|
837
|
+
};
|
|
838
|
+
|
|
839
|
+
const makeMockSourceCard = ({ id, bindTo = 'quotes', secondBindTo = null, includeProjection = false, projectionExpr = '"ok"', missingMock = false }) => {
|
|
840
|
+
const card = deepCloneJson(marketCard);
|
|
841
|
+
card.id = id;
|
|
842
|
+
card.requires = [];
|
|
843
|
+
card.source_defs = [
|
|
844
|
+
{ bindTo, mock: missingMock ? 'missing-mock-key' : 'quotes' },
|
|
845
|
+
...(secondBindTo ? [{ bindTo: secondBindTo, mock: 'quotes' }] : []),
|
|
846
|
+
];
|
|
847
|
+
if (includeProjection) {
|
|
848
|
+
card.source_defs[0].projections = { passthrough: projectionExpr };
|
|
849
|
+
} else {
|
|
850
|
+
delete card.source_defs[0].projections;
|
|
851
|
+
}
|
|
852
|
+
delete card.source_defs[0].urls;
|
|
853
|
+
if (card.source_defs[1]) delete card.source_defs[1].urls;
|
|
854
|
+
return card;
|
|
855
|
+
};
|
|
856
|
+
|
|
857
|
+
const portfolioVariantA = makePortfolioVariant('card-portfolio-preflight-a', { ticker: 'NVDA', quantity: 7, cost_basis: 121 });
|
|
858
|
+
const portfolioVariantB = makePortfolioVariant('card-portfolio-preflight-b', { ticker: 'AMD', quantity: 9, cost_basis: 143 });
|
|
859
|
+
const marketMockCycleCard = makeMockSourceCard({ id: 'card-market-prices-preflight-cycle' });
|
|
860
|
+
const marketMockSourceCardA = makeMockSourceCard({ id: 'card-market-prices-preflight-source-a' });
|
|
861
|
+
const marketMockSourceCardB = makeMockSourceCard({ id: 'card-market-prices-preflight-source-b', includeProjection: true });
|
|
862
|
+
const marketMockSourceCardC = makeMockSourceCard({ id: 'card-market-prices-preflight-source-c', secondBindTo: 'quotesBackup' });
|
|
863
|
+
const marketMockSourceCardD = makeMockSourceCard({ id: 'card-market-prices-preflight-source-d', bindTo: 'quotesPrimary' });
|
|
864
|
+
const marketMockSourceCardE = makeMockSourceCard({ id: 'card-market-prices-preflight-source-e', bindTo: 'quotesEcho' });
|
|
865
|
+
const marketMissingMockCard = makeMockSourceCard({ id: 'card-market-prices-preflight-missing', missingMock: true });
|
|
866
|
+
const invalidCard = {
|
|
867
|
+
...deepCloneJson(marketCard),
|
|
868
|
+
id: '',
|
|
869
|
+
source_defs: [{ bindTo: '', mock: 'quotes' }],
|
|
870
|
+
view: { layout: { kind: 'stack' }, elements: [{ id: 'broken' }] },
|
|
871
|
+
};
|
|
872
|
+
|
|
873
|
+
const validateSuccessCases = [
|
|
874
|
+
{ name: 'portfolio live', card: portfolioCard, expectCardId: 'card-portfolio' },
|
|
875
|
+
{ name: 'market live', card: marketCard, expectCardId: 'card-market-prices' },
|
|
876
|
+
{ name: 'portfolio-value live', card: portfolioValueCard, expectCardId: 'card-portfolio-value' },
|
|
877
|
+
{ name: 'portfolio variant', card: portfolioVariantA, expectCardId: 'card-portfolio-preflight-a' },
|
|
878
|
+
{ name: 'portfolio variant B', card: portfolioVariantB, expectCardId: 'card-portfolio-preflight-b' },
|
|
879
|
+
];
|
|
880
|
+
for (const tc of validateSuccessCases) {
|
|
881
|
+
const body = expectPreflightSuccess(await httpMcp('preflight.validate-candidate-card-definition', {
|
|
882
|
+
candidate_card_content: tc.card,
|
|
883
|
+
}), `T4 validate success (${tc.name})`);
|
|
884
|
+
assert(body.cardId === tc.expectCardId, `T4 validate ${tc.name} cardId mismatch`);
|
|
885
|
+
assert(body.isValid === true, `T4 validate ${tc.name} expected isValid=true`);
|
|
886
|
+
assert(Array.isArray(body.issues) && body.issues.length === 0, `T4 validate ${tc.name} expected no issues`);
|
|
887
|
+
console.log(`[T4.validate] ok: ${tc.name}`);
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
const validateFailureBody = expectPreflightSuccess(await httpMcp('preflight.validate-candidate-card-definition', {
|
|
891
|
+
candidate_card_content: invalidCard,
|
|
892
|
+
}), 'T4 validate failure (invalid card)');
|
|
893
|
+
assert(validateFailureBody.isValid === false, 'T4 validate invalid card should be invalid');
|
|
894
|
+
assert(Array.isArray(validateFailureBody.issues) && validateFailureBody.issues.length > 0, 'T4 validate invalid card should report issues');
|
|
895
|
+
console.log('[T4.validate] ok: invalid card reports validation issues');
|
|
896
|
+
|
|
897
|
+
const materializeSuccessCases = [
|
|
898
|
+
{
|
|
899
|
+
name: 'portfolio live empty mocks',
|
|
900
|
+
card: portfolioCard,
|
|
901
|
+
mockRequires: {},
|
|
902
|
+
mockFetchedSources: {},
|
|
903
|
+
verify: (body) => {
|
|
904
|
+
assert(Array.isArray(body.provides_outputs?.holdings), 'T4 materialize portfolio holdings missing');
|
|
905
|
+
assert(body.provides_outputs.holdings.length === baseHoldings.length, 'T4 materialize portfolio holdings length mismatch');
|
|
906
|
+
assert(body.rendered_view?.elements?.[0]?.kind === 'editable-table', 'T4 materialize portfolio rendered_view mismatch');
|
|
907
|
+
},
|
|
908
|
+
},
|
|
909
|
+
{
|
|
910
|
+
name: 'portfolio variant with extra holding',
|
|
911
|
+
card: portfolioVariantA,
|
|
912
|
+
mockRequires: {},
|
|
913
|
+
mockFetchedSources: {},
|
|
914
|
+
verify: (body) => {
|
|
915
|
+
assert(Array.isArray(body.provides_outputs?.holdings), 'T4 materialize portfolio variant holdings missing');
|
|
916
|
+
assert(body.provides_outputs.holdings.length === baseHoldings.length + 1, 'T4 materialize portfolio variant holdings length mismatch');
|
|
917
|
+
},
|
|
918
|
+
},
|
|
919
|
+
{
|
|
920
|
+
name: 'portfolio variant B with extra holding',
|
|
921
|
+
card: portfolioVariantB,
|
|
922
|
+
mockRequires: {},
|
|
923
|
+
mockFetchedSources: {},
|
|
924
|
+
verify: (body) => {
|
|
925
|
+
assert(Array.isArray(body.provides_outputs?.holdings), 'T4 materialize portfolio variant B holdings missing');
|
|
926
|
+
assert(body.provides_outputs.holdings.length === baseHoldings.length + 1, 'T4 materialize portfolio variant B holdings length mismatch');
|
|
927
|
+
},
|
|
928
|
+
},
|
|
929
|
+
{
|
|
930
|
+
name: 'portfolio-value live with mock requires',
|
|
931
|
+
card: portfolioValueCard,
|
|
932
|
+
mockRequires: { holdings: baseHoldings, quotes: mockQuotes },
|
|
933
|
+
mockFetchedSources: {},
|
|
934
|
+
verify: (body) => {
|
|
935
|
+
assert(Array.isArray(body.computed_values?.positions) && body.computed_values.positions.length > 0, 'T4 materialize portfolio-value positions missing');
|
|
936
|
+
assert(Array.isArray(body.provides_outputs?.positions) && body.provides_outputs.positions.length > 0, 'T4 materialize portfolio-value provides missing');
|
|
937
|
+
assert(body.rendered_view?.elements?.length === 3, 'T4 materialize portfolio-value rendered_view length mismatch');
|
|
938
|
+
},
|
|
939
|
+
},
|
|
940
|
+
{
|
|
941
|
+
name: 'portfolio-value subset requires',
|
|
942
|
+
card: portfolioValueCard,
|
|
943
|
+
mockRequires: {
|
|
944
|
+
holdings: baseHoldings.slice(0, 2),
|
|
945
|
+
quotes: { quoteResponse: { result: mockQuotes.quoteResponse.result.slice(0, 2), error: null } },
|
|
946
|
+
},
|
|
947
|
+
mockFetchedSources: {},
|
|
948
|
+
verify: (body) => {
|
|
949
|
+
assert(Array.isArray(body.computed_values?.positions) && body.computed_values.positions.length === 2, 'T4 materialize portfolio-value subset positions mismatch');
|
|
950
|
+
assert(Array.isArray(body.provides_outputs?.positions) && body.provides_outputs.positions.length === 2, 'T4 materialize portfolio-value subset provides mismatch');
|
|
951
|
+
},
|
|
952
|
+
},
|
|
953
|
+
];
|
|
954
|
+
for (const tc of materializeSuccessCases) {
|
|
955
|
+
const body = expectPreflightSuccess(await httpMcp('preflight.materialize-candidate-card', {
|
|
956
|
+
candidate_card_content: tc.card,
|
|
957
|
+
mock_requires: tc.mockRequires,
|
|
958
|
+
mock_fetched_sources: tc.mockFetchedSources,
|
|
959
|
+
}), `T4 materialize success (${tc.name})`);
|
|
960
|
+
assert(body.ok === true, `T4 materialize ${tc.name} expected ok=true`);
|
|
961
|
+
assert(Array.isArray(body.errors) && body.errors.length === 0, `T4 materialize ${tc.name} expected no errors`);
|
|
962
|
+
tc.verify(body);
|
|
963
|
+
console.log(`[T4.materialize] ok: ${tc.name}`);
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
const materializeFailureRes = await httpMcp('preflight.materialize-candidate-card', {
|
|
967
|
+
candidate_card_content: portfolioCard,
|
|
968
|
+
});
|
|
969
|
+
assert(materializeFailureRes.status === 400, `T4 materialize missing args expected 400, got ${materializeFailureRes.status}`);
|
|
970
|
+
assert(materializeFailureRes.data?.error === 'MCP tool requires mock_requires', 'T4 materialize missing args error mismatch');
|
|
971
|
+
console.log('[T4.materialize] ok: missing required mocks is rejected');
|
|
972
|
+
|
|
973
|
+
const probeSuccessCases = [
|
|
974
|
+
{ name: 'single mock source base', card: marketMockSourceCardA, sourceIdx: 0, bindTo: 'quotes', mockProjections: {} },
|
|
975
|
+
{ name: 'single mock source with projection payload', card: marketMockSourceCardB, sourceIdx: 0, bindTo: 'quotes', mockProjections: { passthrough: 'ok' } },
|
|
976
|
+
{ name: 'two mock sources first entry', card: marketMockSourceCardC, sourceIdx: 0, bindTo: 'quotes', mockProjections: {} },
|
|
977
|
+
{ name: 'two mock sources second entry', card: marketMockSourceCardC, sourceIdx: 1, bindTo: 'quotesBackup', mockProjections: {} },
|
|
978
|
+
{ name: 'single mock source alternate bindTo', card: marketMockSourceCardD, sourceIdx: 0, bindTo: 'quotesPrimary', mockProjections: {} },
|
|
979
|
+
];
|
|
980
|
+
for (const tc of probeSuccessCases) {
|
|
981
|
+
const body = expectPreflightSuccess(await httpMcp('preflight.probe-single-source-in-candidate-card', {
|
|
982
|
+
candidate_card_content: tc.card,
|
|
983
|
+
source_idx: tc.sourceIdx,
|
|
984
|
+
mock_projections: tc.mockProjections,
|
|
985
|
+
}), `T4 probe success (${tc.name})`);
|
|
986
|
+
assert(body.bindTo === tc.bindTo, `T4 probe ${tc.name} bindTo mismatch`);
|
|
987
|
+
assert(body.reachable === true, `T4 probe ${tc.name} expected reachable=true`);
|
|
988
|
+
assert(typeof body.latencyMs === 'number', `T4 probe ${tc.name} expected numeric latencyMs`);
|
|
989
|
+
console.log(`[T4.probe] ok: ${tc.name}`);
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
const probeFailureRes = await httpMcp('preflight.probe-single-source-in-candidate-card', {
|
|
993
|
+
candidate_card_content: marketMissingMockCard,
|
|
994
|
+
source_idx: 0,
|
|
995
|
+
mock_projections: {},
|
|
996
|
+
});
|
|
997
|
+
assert(probeFailureRes.status === 400, `T4 probe failure expected 400, got ${probeFailureRes.status}`);
|
|
998
|
+
assert(typeof probeFailureRes.data?.error === 'string' && probeFailureRes.data.error.length > 0, 'T4 probe failure expected error text');
|
|
999
|
+
console.log('[T4.probe] ok: missing mock source returns HTTP error');
|
|
1000
|
+
|
|
1001
|
+
const runSourceSuccessCases = [
|
|
1002
|
+
{ name: 'single mock source base', card: marketMockSourceCardA, sourceIdx: 0, bindTo: 'quotes' },
|
|
1003
|
+
{ name: 'single mock source with projection payload', card: marketMockSourceCardB, sourceIdx: 0, bindTo: 'quotes' },
|
|
1004
|
+
{ name: 'two mock sources first entry', card: marketMockSourceCardC, sourceIdx: 0, bindTo: 'quotes' },
|
|
1005
|
+
{ name: 'two mock sources second entry', card: marketMockSourceCardC, sourceIdx: 1, bindTo: 'quotesBackup' },
|
|
1006
|
+
{ name: 'single mock source alternate bindTo', card: marketMockSourceCardE, sourceIdx: 0, bindTo: 'quotesEcho' },
|
|
1007
|
+
];
|
|
1008
|
+
for (const tc of runSourceSuccessCases) {
|
|
1009
|
+
const body = expectPreflightSuccess(await httpMcp('preflight.run-single-source-in-candidate-card', {
|
|
1010
|
+
candidate_card_content: tc.card,
|
|
1011
|
+
source_idx: tc.sourceIdx,
|
|
1012
|
+
mock_projections: {},
|
|
1013
|
+
}), `T4 run-source success (${tc.name})`);
|
|
1014
|
+
assert(body.bindTo === tc.bindTo, `T4 run-source ${tc.name} bindTo mismatch`);
|
|
1015
|
+
assert(body.ok === true, `T4 run-source ${tc.name} expected ok=true`);
|
|
1016
|
+
assert(Array.isArray(body.issues) && body.issues.length === 0, `T4 run-source ${tc.name} expected no issues`);
|
|
1017
|
+
assert(Array.isArray(body.result?.quoteResponse?.result) && body.result.quoteResponse.result.length > 0, `T4 run-source ${tc.name} result shape mismatch`);
|
|
1018
|
+
console.log(`[T4.run-source] ok: ${tc.name}`);
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
const runSourceFailureBody = expectPreflightSuccess(await httpMcp('preflight.run-single-source-in-candidate-card', {
|
|
1022
|
+
candidate_card_content: marketMissingMockCard,
|
|
1023
|
+
source_idx: 0,
|
|
1024
|
+
mock_projections: {},
|
|
1025
|
+
}), 'T4 run-source failure (missing mock source)');
|
|
1026
|
+
assert(runSourceFailureBody.ok === false, 'T4 run-source missing mock should set ok=false');
|
|
1027
|
+
assert(Array.isArray(runSourceFailureBody.issues) && runSourceFailureBody.issues.length > 0, 'T4 run-source missing mock should report issues');
|
|
1028
|
+
console.log('[T4.run-source] ok: missing mock source returns ok=false with issues');
|
|
1029
|
+
|
|
1030
|
+
const liveRunCardId = String(marketCard?.id || 'card-market-prices');
|
|
1031
|
+
|
|
1032
|
+
const liveRunSourceBody = expectPreflightSuccess(await httpMcp('preflight.run-single-source-in-live-card', {
|
|
1033
|
+
card_id: liveRunCardId,
|
|
1034
|
+
source_idx: 0,
|
|
1035
|
+
mock_requires: { holdings: baseHoldings },
|
|
1036
|
+
}), 'T4 run-source live card success');
|
|
1037
|
+
assert(liveRunSourceBody.bindTo === 'quotes', 'T4 run-source live card bindTo mismatch');
|
|
1038
|
+
assert(liveRunSourceBody.ok === true, 'T4 run-source live card expected ok=true');
|
|
1039
|
+
assert(Array.isArray(liveRunSourceBody.issues) && liveRunSourceBody.issues.length === 0, 'T4 run-source live card expected no issues');
|
|
1040
|
+
assert(Array.isArray(liveRunSourceBody.result) && liveRunSourceBody.result.length === baseHoldings.length, 'T4 run-source live card result shape mismatch');
|
|
1041
|
+
console.log('[T4.run-source-live] ok: live card source run returns candidate-compatible shape');
|
|
1042
|
+
|
|
1043
|
+
const liveRunRequiresBody = expectPreflightSuccess(await httpMcp('preflight.run-single-source-in-live-card', {
|
|
1044
|
+
card_id: liveRunCardId,
|
|
1045
|
+
source_idx: 0,
|
|
1046
|
+
mock_requires: { holdings: baseHoldings },
|
|
1047
|
+
}), 'T4 run-source live card uses mock_requires in projections');
|
|
1048
|
+
assert(liveRunRequiresBody.bindTo === 'quotes', 'T4 run-source live card requires bindTo mismatch');
|
|
1049
|
+
assert(liveRunRequiresBody.ok === true, 'T4 run-source live card requires expected ok=true');
|
|
1050
|
+
assert(Array.isArray(liveRunRequiresBody.issues) && liveRunRequiresBody.issues.length === 0, 'T4 run-source live card requires expected no issues');
|
|
1051
|
+
assert(Array.isArray(liveRunRequiresBody.result) && liveRunRequiresBody.result.length === baseHoldings.length, 'T4 run-source live card requires result shape mismatch');
|
|
1052
|
+
console.log('[T4.run-source-live] ok: non-empty mock_requires is consumed via source projections');
|
|
1053
|
+
|
|
1054
|
+
const liveRunOutOfRangeRes = await httpMcp('preflight.run-single-source-in-live-card', {
|
|
1055
|
+
card_id: liveRunCardId,
|
|
1056
|
+
source_idx: 9,
|
|
1057
|
+
mock_requires: {},
|
|
1058
|
+
});
|
|
1059
|
+
assert(liveRunOutOfRangeRes.status === 400, `T4 run-source live card out-of-range expected 400, got ${liveRunOutOfRangeRes.status}`);
|
|
1060
|
+
assert(typeof liveRunOutOfRangeRes.data?.error === 'string' && liveRunOutOfRangeRes.data.error.length > 0, 'T4 run-source live card out-of-range expected error text');
|
|
1061
|
+
console.log('[T4.run-source-live] ok: out-of-range source_idx is rejected with HTTP error');
|
|
1062
|
+
|
|
1063
|
+
const liveRunMissingMockRequiresRes = await httpMcp('preflight.run-single-source-in-live-card', {
|
|
1064
|
+
card_id: liveRunCardId,
|
|
1065
|
+
source_idx: 0,
|
|
1066
|
+
});
|
|
1067
|
+
assert(liveRunMissingMockRequiresRes.status === 400, `T4 run-source live card missing mock_requires expected 400, got ${liveRunMissingMockRequiresRes.status}`);
|
|
1068
|
+
assert(liveRunMissingMockRequiresRes.data?.error === 'MCP tool requires mock_requires', 'T4 run-source live card missing mock_requires error mismatch');
|
|
1069
|
+
console.log('[T4.run-source-live] ok: missing mock_requires is rejected');
|
|
1070
|
+
|
|
1071
|
+
const runCycleSuccessCases = [
|
|
1072
|
+
{
|
|
1073
|
+
name: 'portfolio live',
|
|
1074
|
+
card: portfolioCard,
|
|
1075
|
+
mockRequires: {},
|
|
1076
|
+
verify: (body) => {
|
|
1077
|
+
assert(Array.isArray(body.provides_outputs?.holdings) && body.provides_outputs.holdings.length === baseHoldings.length, 'T4 run-cycle portfolio provides mismatch');
|
|
1078
|
+
assert(body.rendered_view?.elements?.[0]?.kind === 'editable-table', 'T4 run-cycle portfolio rendered_view mismatch');
|
|
1079
|
+
},
|
|
1080
|
+
},
|
|
1081
|
+
{
|
|
1082
|
+
name: 'portfolio variant',
|
|
1083
|
+
card: portfolioVariantB,
|
|
1084
|
+
mockRequires: {},
|
|
1085
|
+
verify: (body) => {
|
|
1086
|
+
assert(Array.isArray(body.provides_outputs?.holdings) && body.provides_outputs.holdings.length === baseHoldings.length + 1, 'T4 run-cycle portfolio variant provides mismatch');
|
|
1087
|
+
},
|
|
1088
|
+
},
|
|
1089
|
+
{
|
|
1090
|
+
name: 'portfolio variant B',
|
|
1091
|
+
card: portfolioVariantB,
|
|
1092
|
+
mockRequires: {},
|
|
1093
|
+
verify: (body) => {
|
|
1094
|
+
assert(Array.isArray(body.provides_outputs?.holdings) && body.provides_outputs.holdings.length === baseHoldings.length + 1, 'T4 run-cycle portfolio variant B provides mismatch');
|
|
1095
|
+
assert(body.rendered_view?.elements?.[0]?.kind === 'editable-table', 'T4 run-cycle portfolio variant B rendered_view mismatch');
|
|
1096
|
+
},
|
|
1097
|
+
},
|
|
1098
|
+
{
|
|
1099
|
+
name: 'portfolio-value with full requires',
|
|
1100
|
+
card: portfolioValueCard,
|
|
1101
|
+
mockRequires: { holdings: baseHoldings, quotes: mockQuotes },
|
|
1102
|
+
verify: (body) => {
|
|
1103
|
+
assert(Array.isArray(body.provides_outputs?.positions) && body.provides_outputs.positions.length > 0, 'T4 run-cycle portfolio-value provides mismatch');
|
|
1104
|
+
assert(body.rendered_view?.elements?.length === 3, 'T4 run-cycle portfolio-value rendered_view mismatch');
|
|
1105
|
+
},
|
|
1106
|
+
},
|
|
1107
|
+
{
|
|
1108
|
+
name: 'portfolio-value subset requires',
|
|
1109
|
+
card: portfolioValueCard,
|
|
1110
|
+
mockRequires: {
|
|
1111
|
+
holdings: baseHoldings.slice(0, 2),
|
|
1112
|
+
quotes: { quoteResponse: { result: mockQuotes.quoteResponse.result.slice(0, 2), error: null } },
|
|
1113
|
+
},
|
|
1114
|
+
verify: (body) => {
|
|
1115
|
+
assert(Array.isArray(body.provides_outputs?.positions) && body.provides_outputs.positions.length === 2, 'T4 run-cycle portfolio-value subset length mismatch');
|
|
1116
|
+
},
|
|
1117
|
+
},
|
|
1118
|
+
{
|
|
1119
|
+
name: 'market-prices with live source simulation',
|
|
1120
|
+
card: marketCard,
|
|
1121
|
+
mockRequires: { holdings: baseHoldings.slice(0, 3) },
|
|
1122
|
+
verify: (body) => {
|
|
1123
|
+
const quoteRows = body.provides_outputs?.quotes?.quoteResponse?.result;
|
|
1124
|
+
assert(Array.isArray(quoteRows) && quoteRows.length === 3, 'T4 run-cycle market-prices provides result length mismatch');
|
|
1125
|
+
assert(typeof quoteRows[0]?.symbol === 'string' && quoteRows[0].symbol.length > 0, 'T4 run-cycle market-prices provides symbol missing');
|
|
1126
|
+
|
|
1127
|
+
const resolvedRows = body.rendered_view?.elements?.[0]?.resolved;
|
|
1128
|
+
assert(Array.isArray(resolvedRows) && resolvedRows.length === 3, 'T4 run-cycle market-prices rendered resolved length mismatch');
|
|
1129
|
+
assert(typeof resolvedRows[0]?.ticker === 'string' && resolvedRows[0].ticker.length > 0, 'T4 run-cycle market-prices rendered ticker missing');
|
|
1130
|
+
assert(typeof resolvedRows[0]?.price === 'number', 'T4 run-cycle market-prices rendered price missing');
|
|
1131
|
+
},
|
|
1132
|
+
},
|
|
1133
|
+
];
|
|
1134
|
+
for (const tc of runCycleSuccessCases) {
|
|
1135
|
+
const body = expectPreflightSuccess(await httpMcp('preflight.run-one-cycle-with-candidate-card', {
|
|
1136
|
+
candidate_card_content: tc.card,
|
|
1137
|
+
mock_requires: tc.mockRequires,
|
|
1138
|
+
}), `T4 run-cycle success (${tc.name})`);
|
|
1139
|
+
assert(body.ok === true, `T4 run-cycle ${tc.name} expected ok=true`);
|
|
1140
|
+
assert(Array.isArray(body.issues) && body.issues.length === 0, `T4 run-cycle ${tc.name} expected no issues`);
|
|
1141
|
+
tc.verify(body);
|
|
1142
|
+
console.log(`[T4.run-cycle] ok: ${tc.name}`);
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
}
|
|
1146
|
+
|
|
775
1147
|
console.log('\n=== All smoke checks passed ===\n');
|
|
776
1148
|
} finally {
|
|
777
1149
|
if (chatSseClientId) {
|
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
<title>Example Board Demo (LocalStorage Runtime)</title>
|
|
7
7
|
<link rel="icon" type="image/svg+xml" href="../../browser/favicon.svg" />
|
|
8
8
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" />
|
|
9
|
-
<script src="https://cdn.jsdelivr.net/npm/yaml-flow@8.5.
|
|
9
|
+
<script src="https://cdn.jsdelivr.net/npm/yaml-flow@8.5.2/browser/compute-jsonata.js"></script>
|
|
10
10
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
11
11
|
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
12
12
|
<script src="https://cdn.jsdelivr.net/npm/dompurify/dist/purify.min.js"></script>
|
|
13
13
|
<script src="https://cdn.jsdelivr.net/npm/leader-line/leader-line.min.js"></script>
|
|
14
|
-
<script src="https://cdn.jsdelivr.net/npm/yaml-flow@8.5.
|
|
15
|
-
<script src="https://cdn.jsdelivr.net/npm/yaml-flow@8.5.
|
|
14
|
+
<script src="https://cdn.jsdelivr.net/npm/yaml-flow@8.5.2/browser/live-cards.js"></script>
|
|
15
|
+
<script src="https://cdn.jsdelivr.net/npm/yaml-flow@8.5.2/browser/board-livecards-localstorage.js"></script>
|
|
16
16
|
</head>
|
|
17
17
|
<body class="bg-light">
|
|
18
18
|
<div class="container-fluid py-3">
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as CommandInput, C as CommandResult } from './board-live-cards-public-
|
|
1
|
+
import { a as CommandInput, C as CommandResult } from './board-live-cards-public-B13InXhC.cjs';
|
|
2
2
|
import { A as ArtifactInfo, a as ArtifactsStore } from './artifacts-store-lib-CVgtQrNZ.cjs';
|
|
3
3
|
import './storage-interface-B2WD9D5n.cjs';
|
|
4
4
|
import './execution-refs.cjs';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as CommandInput, C as CommandResult } from './board-live-cards-public-
|
|
1
|
+
import { a as CommandInput, C as CommandResult } from './board-live-cards-public-BGS22cMb.js';
|
|
2
2
|
import { A as ArtifactInfo, a as ArtifactsStore } from './artifacts-store-lib-D-k-E8Vy.js';
|
|
3
3
|
import './storage-interface-B2WD9D5n.js';
|
|
4
4
|
import './execution-refs.js';
|