@tom2012/cc-web 2026.5.14-b → 2026.5.15-b
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 +1 -1
- package/backend/dist/index.d.ts.map +1 -1
- package/backend/dist/index.js +51 -0
- package/backend/dist/index.js.map +1 -1
- package/backend/dist/routes/flows.d.ts.map +1 -1
- package/backend/dist/routes/flows.js +10 -0
- package/backend/dist/routes/flows.js.map +1 -1
- package/backend/dist/routes/global-tracks.d.ts +11 -0
- package/backend/dist/routes/global-tracks.d.ts.map +1 -0
- package/backend/dist/routes/global-tracks.js +86 -0
- package/backend/dist/routes/global-tracks.js.map +1 -0
- package/backend/dist/routes/tracks.d.ts +14 -0
- package/backend/dist/routes/tracks.d.ts.map +1 -0
- package/backend/dist/routes/tracks.js +184 -0
- package/backend/dist/routes/tracks.js.map +1 -0
- package/backend/dist/tracks/__tests__/verify-track-t1.d.ts +11 -0
- package/backend/dist/tracks/__tests__/verify-track-t1.d.ts.map +1 -0
- package/backend/dist/tracks/__tests__/verify-track-t1.js +293 -0
- package/backend/dist/tracks/__tests__/verify-track-t1.js.map +1 -0
- package/backend/dist/tracks/__tests__/verify-track.d.ts +20 -0
- package/backend/dist/tracks/__tests__/verify-track.d.ts.map +1 -0
- package/backend/dist/tracks/__tests__/verify-track.js +187 -0
- package/backend/dist/tracks/__tests__/verify-track.js.map +1 -0
- package/backend/dist/tracks/ask-user-bridge.d.ts +59 -0
- package/backend/dist/tracks/ask-user-bridge.d.ts.map +1 -0
- package/backend/dist/tracks/ask-user-bridge.js +186 -0
- package/backend/dist/tracks/ask-user-bridge.js.map +1 -0
- package/backend/dist/tracks/ccweb-train-adapter.d.ts +40 -0
- package/backend/dist/tracks/ccweb-train-adapter.d.ts.map +1 -0
- package/backend/dist/tracks/ccweb-train-adapter.js +111 -0
- package/backend/dist/tracks/ccweb-train-adapter.js.map +1 -0
- package/backend/dist/tracks/cross-lock.d.ts +30 -0
- package/backend/dist/tracks/cross-lock.d.ts.map +1 -0
- package/backend/dist/tracks/cross-lock.js +44 -0
- package/backend/dist/tracks/cross-lock.js.map +1 -0
- package/backend/dist/tracks/index.d.ts +20 -0
- package/backend/dist/tracks/index.d.ts.map +1 -0
- package/backend/dist/tracks/index.js +42 -0
- package/backend/dist/tracks/index.js.map +1 -0
- package/backend/dist/tracks/registry.d.ts +56 -0
- package/backend/dist/tracks/registry.d.ts.map +1 -0
- package/backend/dist/tracks/registry.js +161 -0
- package/backend/dist/tracks/registry.js.map +1 -0
- package/backend/dist/tracks/store.d.ts +37 -0
- package/backend/dist/tracks/store.d.ts.map +1 -0
- package/backend/dist/tracks/store.js +254 -0
- package/backend/dist/tracks/store.js.map +1 -0
- package/backend/dist/tracks/track-runner.d.ts +62 -0
- package/backend/dist/tracks/track-runner.d.ts.map +1 -0
- package/backend/dist/tracks/track-runner.js +134 -0
- package/backend/dist/tracks/track-runner.js.map +1 -0
- package/backend/dist/tracks/train-loader.d.ts +44 -0
- package/backend/dist/tracks/train-loader.d.ts.map +1 -0
- package/backend/dist/tracks/train-loader.js +32 -0
- package/backend/dist/tracks/train-loader.js.map +1 -0
- package/backend/dist/tracks/types-train.d.ts +12 -0
- package/backend/dist/tracks/types-train.d.ts.map +1 -0
- package/backend/dist/tracks/types-train.js +13 -0
- package/backend/dist/tracks/types-train.js.map +1 -0
- package/backend/dist/tracks/types.d.ts +66 -0
- package/backend/dist/tracks/types.d.ts.map +1 -0
- package/backend/dist/tracks/types.js +12 -0
- package/backend/dist/tracks/types.js.map +1 -0
- package/backend/dist/tracks/workflow-data-watcher.d.ts +47 -0
- package/backend/dist/tracks/workflow-data-watcher.d.ts.map +1 -0
- package/backend/dist/tracks/workflow-data-watcher.js +166 -0
- package/backend/dist/tracks/workflow-data-watcher.js.map +1 -0
- package/backend/package-lock.json +107 -0
- package/backend/package.json +6 -1
- package/backend/vendor/@train-lang/adapter-spec/dist/index.d.ts +164 -0
- package/backend/vendor/@train-lang/adapter-spec/dist/index.d.ts.map +1 -0
- package/backend/vendor/@train-lang/adapter-spec/dist/index.js +13 -0
- package/backend/vendor/@train-lang/adapter-spec/dist/index.js.map +1 -0
- package/backend/vendor/@train-lang/adapter-spec/package.json +15 -0
- package/backend/vendor/@train-lang/core/dist/ast-cache.d.ts +74 -0
- package/backend/vendor/@train-lang/core/dist/ast-cache.d.ts.map +1 -0
- package/backend/vendor/@train-lang/core/dist/ast-cache.js +157 -0
- package/backend/vendor/@train-lang/core/dist/ast-cache.js.map +1 -0
- package/backend/vendor/@train-lang/core/dist/ast.d.ts +350 -0
- package/backend/vendor/@train-lang/core/dist/ast.d.ts.map +1 -0
- package/backend/vendor/@train-lang/core/dist/ast.js +15 -0
- package/backend/vendor/@train-lang/core/dist/ast.js.map +1 -0
- package/backend/vendor/@train-lang/core/dist/builder.d.ts +21 -0
- package/backend/vendor/@train-lang/core/dist/builder.d.ts.map +1 -0
- package/backend/vendor/@train-lang/core/dist/builder.js +1221 -0
- package/backend/vendor/@train-lang/core/dist/builder.js.map +1 -0
- package/backend/vendor/@train-lang/core/dist/builtins.d.ts +17 -0
- package/backend/vendor/@train-lang/core/dist/builtins.d.ts.map +1 -0
- package/backend/vendor/@train-lang/core/dist/builtins.js +488 -0
- package/backend/vendor/@train-lang/core/dist/builtins.js.map +1 -0
- package/backend/vendor/@train-lang/core/dist/index.d.ts +54 -0
- package/backend/vendor/@train-lang/core/dist/index.d.ts.map +1 -0
- package/backend/vendor/@train-lang/core/dist/index.js +66 -0
- package/backend/vendor/@train-lang/core/dist/index.js.map +1 -0
- package/backend/vendor/@train-lang/core/dist/interpreter.d.ts +110 -0
- package/backend/vendor/@train-lang/core/dist/interpreter.d.ts.map +1 -0
- package/backend/vendor/@train-lang/core/dist/interpreter.js +894 -0
- package/backend/vendor/@train-lang/core/dist/interpreter.js.map +1 -0
- package/backend/vendor/@train-lang/core/dist/lexer.d.ts +88 -0
- package/backend/vendor/@train-lang/core/dist/lexer.d.ts.map +1 -0
- package/backend/vendor/@train-lang/core/dist/lexer.js +243 -0
- package/backend/vendor/@train-lang/core/dist/lexer.js.map +1 -0
- package/backend/vendor/@train-lang/core/dist/module-loader.d.ts +74 -0
- package/backend/vendor/@train-lang/core/dist/module-loader.d.ts.map +1 -0
- package/backend/vendor/@train-lang/core/dist/module-loader.js +134 -0
- package/backend/vendor/@train-lang/core/dist/module-loader.js.map +1 -0
- package/backend/vendor/@train-lang/core/dist/parser.d.ts +135 -0
- package/backend/vendor/@train-lang/core/dist/parser.d.ts.map +1 -0
- package/backend/vendor/@train-lang/core/dist/parser.js +838 -0
- package/backend/vendor/@train-lang/core/dist/parser.js.map +1 -0
- package/backend/vendor/@train-lang/core/dist/prompt-composer.d.ts +49 -0
- package/backend/vendor/@train-lang/core/dist/prompt-composer.d.ts.map +1 -0
- package/backend/vendor/@train-lang/core/dist/prompt-composer.js +159 -0
- package/backend/vendor/@train-lang/core/dist/prompt-composer.js.map +1 -0
- package/backend/vendor/@train-lang/core/dist/runtime.d.ts +146 -0
- package/backend/vendor/@train-lang/core/dist/runtime.d.ts.map +1 -0
- package/backend/vendor/@train-lang/core/dist/runtime.js +156 -0
- package/backend/vendor/@train-lang/core/dist/runtime.js.map +1 -0
- package/backend/vendor/@train-lang/core/dist/type-descriptor.d.ts +18 -0
- package/backend/vendor/@train-lang/core/dist/type-descriptor.d.ts.map +1 -0
- package/backend/vendor/@train-lang/core/dist/type-descriptor.js +94 -0
- package/backend/vendor/@train-lang/core/dist/type-descriptor.js.map +1 -0
- package/backend/vendor/@train-lang/core/dist/validation.d.ts +44 -0
- package/backend/vendor/@train-lang/core/dist/validation.d.ts.map +1 -0
- package/backend/vendor/@train-lang/core/dist/validation.js +271 -0
- package/backend/vendor/@train-lang/core/dist/validation.js.map +1 -0
- package/backend/vendor/@train-lang/core/package.json +35 -0
- package/frontend/dist/assets/{ChatOverlay-B4bHclb4.js → ChatOverlay-59ZxvtRP.js} +1 -1
- package/frontend/dist/assets/{GraphPreview-CBR4uFHb.js → GraphPreview-sbpMfB9C.js} +2 -2
- package/frontend/dist/assets/{MobilePage-B7u9HJ1Y.js → MobilePage-Dcx6MXJq.js} +3 -3
- package/frontend/dist/assets/{OfficePreview-V-X3ON2u.js → OfficePreview-pFRYqbUT.js} +2 -2
- package/frontend/dist/assets/{PdfPreview-NktKOUdL.js → PdfPreview-YuE4294t.js} +1 -1
- package/frontend/dist/assets/{ProjectPage-DAU6cEkl.js → ProjectPage-99jMQxFL.js} +5 -5
- package/frontend/dist/assets/{SettingsPage-CtBCvofK.js → SettingsPage-lBTzzVSA.js} +2 -2
- package/frontend/dist/assets/{SkillHubPage-CHvWwI8j.js → SkillHubPage-Ba16r6gG.js} +3 -3
- package/frontend/dist/assets/TrackEditor-BHghiFPX.js +14 -0
- package/frontend/dist/assets/abap-LPLW346S.js +7 -0
- package/frontend/dist/assets/apex-Dk-jUCUV.js +7 -0
- package/frontend/dist/assets/azcli-DPUMmPlX.js +7 -0
- package/frontend/dist/assets/bat-C1Qbg1bV.js +7 -0
- package/frontend/dist/assets/bicep-D-e-VSJi.js +7 -0
- package/frontend/dist/assets/cameligo-CjUqTgqL.js +7 -0
- package/frontend/dist/assets/{chevron-down-COdWD3xd.js → chevron-down-D8NwXKSN.js} +1 -1
- package/frontend/dist/assets/clojure-BWsu6Kju.js +7 -0
- package/frontend/dist/assets/codicon-DCmgc-ay.ttf +0 -0
- package/frontend/dist/assets/coffee-DeC36AK3.js +7 -0
- package/frontend/dist/assets/cpp-DcZnmBWT.js +7 -0
- package/frontend/dist/assets/csharp-DqBXBMf0.js +7 -0
- package/frontend/dist/assets/csp-CkO7y8ul.js +7 -0
- package/frontend/dist/assets/css-OAcfVtED.js +7 -0
- package/frontend/dist/assets/cssMode-JswmrBJm.js +7 -0
- package/frontend/dist/assets/cypher-40UGrUjD.js +7 -0
- package/frontend/dist/assets/dart-DmixyLor.js +7 -0
- package/frontend/dist/assets/dockerfile-CayO4nTA.js +7 -0
- package/frontend/dist/assets/ecl-DRrKCuVc.js +7 -0
- package/frontend/dist/assets/editor-B5EY1bb8.css +1 -0
- package/frontend/dist/assets/editor.main-DxKJbewY.js +37 -0
- package/frontend/dist/assets/elixir-J3qpp9mX.js +7 -0
- package/frontend/dist/assets/flow9-DzW2c4Im.js +7 -0
- package/frontend/dist/assets/freemarker2-DSk3lXcG.js +7 -0
- package/frontend/dist/assets/fsharp-D00tn_6c.js +7 -0
- package/frontend/dist/assets/go-NnNmgWK_.js +7 -0
- package/frontend/dist/assets/graphql-C9_--VLF.js +7 -0
- package/frontend/dist/assets/handlebars-3L3xIxMF.js +7 -0
- package/frontend/dist/assets/hcl-BhbOULbp.js +7 -0
- package/frontend/dist/assets/html-jGWDYvg4.js +7 -0
- package/frontend/dist/assets/htmlMode-BNn43R0H.js +7 -0
- package/frontend/dist/assets/index-BWlHiqbD.js +1 -0
- package/frontend/dist/assets/index-BmPb0Wl1.css +1 -0
- package/frontend/dist/assets/{index-CZ4PAGPA.js → index-CcOfgS18.js} +2 -2
- package/frontend/dist/assets/{index-CaO8S0F7.js → index-DbB1EvuS.js} +1 -1
- package/frontend/dist/assets/{index-CRhUXLfj.js → index-DzYcaccz.js} +1 -1
- package/frontend/dist/assets/ini-zR-_X5iG.js +7 -0
- package/frontend/dist/assets/java-CSTjsyoZ.js +7 -0
- package/frontend/dist/assets/javascript-DrTQenPf.js +7 -0
- package/frontend/dist/assets/jsonMode-BJqz4hx6.js +7 -0
- package/frontend/dist/assets/{jszip.min-CP_BBUld.js → jszip.min-Dn7y6lhP.js} +1 -1
- package/frontend/dist/assets/julia-DioMOKVu.js +7 -0
- package/frontend/dist/assets/kotlin-Dsb0PKmW.js +7 -0
- package/frontend/dist/assets/less-CZYLoAVD.js +7 -0
- package/frontend/dist/assets/lexon-d5JUiwNk.js +7 -0
- package/frontend/dist/assets/liquid-51VrCPM1.js +7 -0
- package/frontend/dist/assets/lua-1Al72GG8.js +7 -0
- package/frontend/dist/assets/m3-hx1xCPC3.js +7 -0
- package/frontend/dist/assets/markdown-DPGrH1xZ.js +7 -0
- package/frontend/dist/assets/mdx-B9MBogQu.js +7 -0
- package/frontend/dist/assets/mips-CYbZjkIm.js +7 -0
- package/frontend/dist/assets/msdax-DAioKM5A.js +7 -0
- package/frontend/dist/assets/mysql-7e9GUebS.js +7 -0
- package/frontend/dist/assets/objective-c-BGf8QNjz.js +7 -0
- package/frontend/dist/assets/pascal-hEDRz3un.js +7 -0
- package/frontend/dist/assets/pascaligo-gqEhN6pG.js +7 -0
- package/frontend/dist/assets/perl-CN8Ht9Vk.js +7 -0
- package/frontend/dist/assets/pgsql-CRCqHQBx.js +7 -0
- package/frontend/dist/assets/php-DTZrlAwe.js +7 -0
- package/frontend/dist/assets/pla-CRmh4UcC.js +7 -0
- package/frontend/dist/assets/postiats-Car2G7g8.js +7 -0
- package/frontend/dist/assets/powerquery-BJKl8V3o.js +7 -0
- package/frontend/dist/assets/powershell-Du7a_J7r.js +7 -0
- package/frontend/dist/assets/protobuf-ChneWI0H.js +7 -0
- package/frontend/dist/assets/pug-BH6LSJaf.js +7 -0
- package/frontend/dist/assets/python-B4lxjc3U.js +7 -0
- package/frontend/dist/assets/qsharp-CU-Hxpxi.js +7 -0
- package/frontend/dist/assets/r-Bw-W15zh.js +7 -0
- package/frontend/dist/assets/razor-Df88ZAwt.js +7 -0
- package/frontend/dist/assets/redis-bY-X9-ol.js +7 -0
- package/frontend/dist/assets/redshift-CMu3ubbS.js +7 -0
- package/frontend/dist/assets/restructuredtext-KNkiWGNN.js +7 -0
- package/frontend/dist/assets/ruby-dQWMhU86.js +7 -0
- package/frontend/dist/assets/rust-BAcHhnEU.js +7 -0
- package/frontend/dist/assets/sb-Bidr5w2z.js +7 -0
- package/frontend/dist/assets/scala-imTtxsGY.js +7 -0
- package/frontend/dist/assets/scheme-BY-WHKiB.js +7 -0
- package/frontend/dist/assets/scss-NDoRP52C.js +7 -0
- package/frontend/dist/assets/{select-Cf6Q2O8Z.js → select-BCKg8P7d.js} +1 -1
- package/frontend/dist/assets/shell-DrIjotnh.js +7 -0
- package/frontend/dist/assets/solidity-DTahNycF.js +7 -0
- package/frontend/dist/assets/sophia-DtyrjGkZ.js +7 -0
- package/frontend/dist/assets/sparql-CFuS5E3z.js +7 -0
- package/frontend/dist/assets/sql-BRxcnbRv.js +7 -0
- package/frontend/dist/assets/st-Dz4uh7MK.js +7 -0
- package/frontend/dist/assets/swift-Digsrw1G.js +11 -0
- package/frontend/dist/assets/systemverilog-7TDrkMau.js +7 -0
- package/frontend/dist/assets/tcl-BtaFcnDi.js +7 -0
- package/frontend/dist/assets/tsMode-BHae3zIH.js +7 -0
- package/frontend/dist/assets/twig-Deid_oBs.js +7 -0
- package/frontend/dist/assets/typescript-Bv6gAW_5.js +7 -0
- package/frontend/dist/assets/typespec-zUaxhbG8.js +7 -0
- package/frontend/dist/assets/{user-B4YUPhU8.js → user-CGd4Ayhq.js} +1 -1
- package/frontend/dist/assets/vb-DK0rKJzo.js +7 -0
- package/frontend/dist/assets/wgsl-B8fNVlOQ.js +7 -0
- package/frontend/dist/assets/xml-C70S0rct.js +7 -0
- package/frontend/dist/assets/yaml-BZVXvTCX.js +7 -0
- package/frontend/dist/index.html +2 -2
- package/package.json +2 -1
- package/frontend/dist/assets/index-BkQ6KI1l.css +0 -1
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* T0 verification script for the Track subsystem.
|
|
4
|
+
*
|
|
5
|
+
* NOT a vitest/jest test — ccweb backend has no test framework yet.
|
|
6
|
+
* Runs as a standalone Node script to verify end-to-end:
|
|
7
|
+
*
|
|
8
|
+
* 1. TrackRunner can load a .tr file
|
|
9
|
+
* 2. train-lang composes prompt + calls CcwebTrainAdapter
|
|
10
|
+
* 3. CcwebTrainAdapter injects prompt (capture into a mock buffer)
|
|
11
|
+
* 4. We programmatically simulate the LLM writing outputs by editing
|
|
12
|
+
* workflow_data.json + setting task_progress[].finish = true
|
|
13
|
+
* 5. WorkflowDataWatcher detects the finish signal
|
|
14
|
+
* 6. Adapter reads variables.<name> → returns FaiResult.success
|
|
15
|
+
* 7. train continues execution → main() returns
|
|
16
|
+
* 8. TrackRunner reports ok=true with the returned value
|
|
17
|
+
*
|
|
18
|
+
* Run: cd backend && npx ts-node src/tracks/__tests__/verify-track.ts
|
|
19
|
+
*/
|
|
20
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
23
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
24
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
25
|
+
}
|
|
26
|
+
Object.defineProperty(o, k2, desc);
|
|
27
|
+
}) : (function(o, m, k, k2) {
|
|
28
|
+
if (k2 === undefined) k2 = k;
|
|
29
|
+
o[k2] = m[k];
|
|
30
|
+
}));
|
|
31
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
32
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
33
|
+
}) : function(o, v) {
|
|
34
|
+
o["default"] = v;
|
|
35
|
+
});
|
|
36
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
37
|
+
var ownKeys = function(o) {
|
|
38
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
39
|
+
var ar = [];
|
|
40
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
41
|
+
return ar;
|
|
42
|
+
};
|
|
43
|
+
return ownKeys(o);
|
|
44
|
+
};
|
|
45
|
+
return function (mod) {
|
|
46
|
+
if (mod && mod.__esModule) return mod;
|
|
47
|
+
var result = {};
|
|
48
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
49
|
+
__setModuleDefault(result, mod);
|
|
50
|
+
return result;
|
|
51
|
+
};
|
|
52
|
+
})();
|
|
53
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
54
|
+
const fs = __importStar(require("fs/promises"));
|
|
55
|
+
const os = __importStar(require("os"));
|
|
56
|
+
const path = __importStar(require("path"));
|
|
57
|
+
const __1 = require("..");
|
|
58
|
+
let failed = 0;
|
|
59
|
+
function check(name, cond, msg) {
|
|
60
|
+
if (cond) {
|
|
61
|
+
console.log(` ✓ ${name}`);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
failed++;
|
|
65
|
+
console.error(` ✗ ${name}${msg ? ': ' + msg : ''}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const DEMO_TR = `
|
|
69
|
+
fai analyze(file_path: string, prompt: prompt) -> rating: int 0-10, comment: string maxLen=500 { }
|
|
70
|
+
|
|
71
|
+
func main(input_path: string) -> string {
|
|
72
|
+
let r = analyze(input_path, "评分 0-10")
|
|
73
|
+
return r.comment
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export main
|
|
77
|
+
`;
|
|
78
|
+
async function readWf(p) {
|
|
79
|
+
const text = await fs.readFile(p, 'utf8');
|
|
80
|
+
return JSON.parse(text);
|
|
81
|
+
}
|
|
82
|
+
async function writeWf(p, w) {
|
|
83
|
+
await fs.writeFile(p, JSON.stringify(w, null, 2), 'utf8');
|
|
84
|
+
}
|
|
85
|
+
async function main() {
|
|
86
|
+
console.log('=== Track T0 verification ===\n');
|
|
87
|
+
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'ccweb-track-t0-'));
|
|
88
|
+
console.log(`tmpDir = ${tmpDir}`);
|
|
89
|
+
const trackPath = path.join(tmpDir, 'demo.tr');
|
|
90
|
+
const wfPath = path.join(tmpDir, 'workflow_data.json');
|
|
91
|
+
await fs.writeFile(trackPath, DEMO_TR, 'utf8');
|
|
92
|
+
await writeWf(wfPath, {
|
|
93
|
+
constants: {},
|
|
94
|
+
variables: {},
|
|
95
|
+
task_progress: [],
|
|
96
|
+
});
|
|
97
|
+
const watcher = (0, __1.createWorkflowDataWatcher)(wfPath);
|
|
98
|
+
// Capture prompts injected by adapter
|
|
99
|
+
const promptsInjected = [];
|
|
100
|
+
// Mock injector: instead of writing to a PTY, it parses the
|
|
101
|
+
// [Required outputs] section from the prompt, fabricates legal
|
|
102
|
+
// values, and writes them to workflow_data.json after a short
|
|
103
|
+
// delay (simulating LLM round-trip latency).
|
|
104
|
+
const injector = async (text) => {
|
|
105
|
+
promptsInjected.push(text);
|
|
106
|
+
// Extract taskIndex from the ccweb header (first 3 lines)
|
|
107
|
+
const m = text.match(/taskIndex = (\d+)/);
|
|
108
|
+
if (!m)
|
|
109
|
+
throw new Error('no taskIndex in prompt — adapter contract broken');
|
|
110
|
+
const taskIndex = Number(m[1]);
|
|
111
|
+
// Simulate LLM writing outputs after 30ms
|
|
112
|
+
setTimeout(async () => {
|
|
113
|
+
const wf = await readWf(wfPath);
|
|
114
|
+
// Pretend the LLM gave rating=8 + comment="OK"
|
|
115
|
+
wf.variables.rating = 8;
|
|
116
|
+
wf.variables.comment = 'OK';
|
|
117
|
+
wf.task_progress.push({
|
|
118
|
+
nodeId: taskIndex,
|
|
119
|
+
name: 'analyze',
|
|
120
|
+
finish: true,
|
|
121
|
+
startedAt: Date.now() - 10,
|
|
122
|
+
finishedAt: Date.now(),
|
|
123
|
+
});
|
|
124
|
+
await writeWf(wfPath, wf);
|
|
125
|
+
}, 30);
|
|
126
|
+
};
|
|
127
|
+
const runner = (0, __1.createTrackRunner)({
|
|
128
|
+
projectId: 'demo-proj',
|
|
129
|
+
injector,
|
|
130
|
+
watcher,
|
|
131
|
+
maxFaiAttempts: 2,
|
|
132
|
+
defaultFaiTimeoutMs: 5000,
|
|
133
|
+
});
|
|
134
|
+
const result = await runner.run(trackPath, ['src/foo.ts']);
|
|
135
|
+
// Assertions
|
|
136
|
+
check('result.ok is true', result.ok, JSON.stringify(result.error));
|
|
137
|
+
check('result.value is the LLM-supplied comment ("OK")', result.value === 'OK', `got: ${JSON.stringify(result.value)}`);
|
|
138
|
+
check('injector called exactly once', promptsInjected.length === 1);
|
|
139
|
+
check('prompt contains writeProtocolHint marker', promptsInjected[0]?.includes('[Write outputs to .ccweb/workflow_data.json') ?? false);
|
|
140
|
+
check('prompt does NOT contain stale train default hint', !(promptsInjected[0]?.includes('stack[<callId>]') ?? false));
|
|
141
|
+
check('prompt contains ccweb track context header (taskIndex)', promptsInjected[0]?.includes('taskIndex = ') ?? false);
|
|
142
|
+
check('final workflow_data.task_progress has 1 finished entry', (await readWf(wfPath)).task_progress.length === 1);
|
|
143
|
+
// Verify cancellation path
|
|
144
|
+
console.log('\n--- cancellation path ---');
|
|
145
|
+
await writeWf(wfPath, {
|
|
146
|
+
constants: {},
|
|
147
|
+
variables: {},
|
|
148
|
+
task_progress: [],
|
|
149
|
+
});
|
|
150
|
+
// Use an injector that never resolves the finish signal
|
|
151
|
+
const slowPromptsInjected = [];
|
|
152
|
+
const slowInjector = async (text) => {
|
|
153
|
+
slowPromptsInjected.push(text);
|
|
154
|
+
// Don't write anything — simulate LLM hung
|
|
155
|
+
};
|
|
156
|
+
const watcher2 = (0, __1.createWorkflowDataWatcher)(wfPath);
|
|
157
|
+
const cancelRunner = (0, __1.createTrackRunner)({
|
|
158
|
+
projectId: 'demo-proj',
|
|
159
|
+
injector: slowInjector,
|
|
160
|
+
watcher: watcher2,
|
|
161
|
+
maxFaiAttempts: 1,
|
|
162
|
+
defaultFaiTimeoutMs: 60000, // long timeout — we'll cancel before this
|
|
163
|
+
});
|
|
164
|
+
// Cancel after 100ms
|
|
165
|
+
const cancelTimer = setTimeout(() => cancelRunner.cancel(), 100);
|
|
166
|
+
const cancelResult = await cancelRunner.run(trackPath, ['src/foo.ts']);
|
|
167
|
+
clearTimeout(cancelTimer);
|
|
168
|
+
check('cancel: ok is false', !cancelResult.ok);
|
|
169
|
+
check('cancel: error is UserCancelError-like', /cancel/i.test(cancelResult.error?.errorType ?? '') ||
|
|
170
|
+
/cancel/i.test(cancelResult.error?.message ?? ''), `got: ${JSON.stringify(cancelResult.error)}`);
|
|
171
|
+
// Verify writeProtocolHint factory shape (smoke test)
|
|
172
|
+
console.log('\n--- buildCcwebWriteProtocolHint shape ---');
|
|
173
|
+
const hint = (0, __1.buildCcwebWriteProtocolHint)();
|
|
174
|
+
check('hint mentions workflow_data.json', hint.includes('workflow_data.json'));
|
|
175
|
+
check('hint mentions variables', hint.includes('variables.<name>'));
|
|
176
|
+
check('hint mentions task_progress', hint.includes('task_progress'));
|
|
177
|
+
check('hint mentions finish: true', hint.includes('finish: true'));
|
|
178
|
+
// Cleanup
|
|
179
|
+
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
180
|
+
console.log(`\n${failed === 0 ? '✅ ALL CHECKS PASSED' : `❌ ${failed} CHECK(S) FAILED`}`);
|
|
181
|
+
process.exit(failed === 0 ? 0 : 1);
|
|
182
|
+
}
|
|
183
|
+
main().catch((e) => {
|
|
184
|
+
console.error('verify-track crashed:', e);
|
|
185
|
+
process.exit(2);
|
|
186
|
+
});
|
|
187
|
+
//# sourceMappingURL=verify-track.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-track.js","sourceRoot":"","sources":["../../../src/tracks/__tests__/verify-track.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AskUserBridge — bridges train-lang's host builtin call to the ccweb
|
|
3
|
+
* frontend.
|
|
4
|
+
*
|
|
5
|
+
* Flow:
|
|
6
|
+
* 1. .tr code calls `__ccweb_ask_user({ fields: [...] })`
|
|
7
|
+
* 2. train evaluates this as a builtin → call our bridge.requestInput()
|
|
8
|
+
* 3. bridge pushes a "track_ask_user" event (via onPush callback)
|
|
9
|
+
* to the WebSocket layer, which broadcasts to the frontend
|
|
10
|
+
* 4. frontend renders a form, user submits → POST /api/.../tracks/input
|
|
11
|
+
* 5. route handler calls bridge.submitInput(runId, requestId, data)
|
|
12
|
+
* 6. bridge resolves the pending Promise → train continues
|
|
13
|
+
*
|
|
14
|
+
* The bridge maintains one pending request per runId. Concurrent
|
|
15
|
+
* ask_user calls within one track would queue (only the most recent
|
|
16
|
+
* pending request is active). For T1 this is fine; multi-prompt would
|
|
17
|
+
* need a queue (T2+).
|
|
18
|
+
*
|
|
19
|
+
* Cancellation: AbortSignal aborts the pending request immediately,
|
|
20
|
+
* rejecting the Promise with a TrainException-shaped error.
|
|
21
|
+
*/
|
|
22
|
+
import type { Value, BuiltinFunction } from '../tracks/types-train';
|
|
23
|
+
export interface AskUserFieldSpec {
|
|
24
|
+
key: string;
|
|
25
|
+
label: string;
|
|
26
|
+
type: 'text' | 'enum' | 'number' | 'bool';
|
|
27
|
+
variants?: string[];
|
|
28
|
+
placeholder?: string;
|
|
29
|
+
required?: boolean;
|
|
30
|
+
}
|
|
31
|
+
export interface AskUserRequest {
|
|
32
|
+
runId: string;
|
|
33
|
+
requestId: string;
|
|
34
|
+
fields: AskUserFieldSpec[];
|
|
35
|
+
}
|
|
36
|
+
export interface AskUserPushEvent extends AskUserRequest {
|
|
37
|
+
kind: 'track_ask_user';
|
|
38
|
+
}
|
|
39
|
+
export type AskUserPushFn = (event: AskUserPushEvent) => void;
|
|
40
|
+
export interface AskUserBridge {
|
|
41
|
+
/** Called from the builtin when train evaluates __ccweb_ask_user(...). */
|
|
42
|
+
requestInput(runId: string, spec: AskUserFieldSpec[], signal?: AbortSignal): Promise<Record<string, Value>>;
|
|
43
|
+
/** Called from the route handler when the user submits the form. */
|
|
44
|
+
submitInput(runId: string, requestId: string, data: Record<string, Value>): {
|
|
45
|
+
ok: boolean;
|
|
46
|
+
message?: string;
|
|
47
|
+
};
|
|
48
|
+
/** Reject all pending requests for a runId (e.g. on track cancel). */
|
|
49
|
+
cancelAllForRun(runId: string, reason?: string): void;
|
|
50
|
+
/** For diagnostics + tests. */
|
|
51
|
+
getPending(runId: string): AskUserRequest | null;
|
|
52
|
+
}
|
|
53
|
+
export declare function createAskUserBridge(onPush: AskUserPushFn): AskUserBridge;
|
|
54
|
+
/**
|
|
55
|
+
* Build the `__ccweb_ask_user` builtin function bound to this run's
|
|
56
|
+
* bridge + AbortSignal. Pass into TrainOptions.extraBuiltins.
|
|
57
|
+
*/
|
|
58
|
+
export declare function createAskUserBuiltin(bridge: AskUserBridge, runId: string, signal?: AbortSignal): Promise<BuiltinFunction>;
|
|
59
|
+
//# sourceMappingURL=ask-user-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ask-user-bridge.d.ts","sourceRoot":"","sources":["../../src/tracks/ask-user-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAGnE,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAA;IACzC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,gBAAgB,EAAE,CAAA;CAC3B;AAED,MAAM,WAAW,gBAAiB,SAAQ,cAAc;IACtD,IAAI,EAAE,gBAAgB,CAAA;CACvB;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAA;AAE7D,MAAM,WAAW,aAAa;IAC5B,0EAA0E;IAC1E,YAAY,CACV,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,gBAAgB,EAAE,EACxB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAA;IAEjC,oEAAoE;IACpE,WAAW,CACT,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GAC1B;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAEpC,sEAAsE;IACtE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAErD,+BAA+B;IAC/B,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAAA;CACjD;AAiBD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,GAAG,aAAa,CA2IxE;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,aAAa,EACrB,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,eAAe,CAAC,CAiB1B"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* AskUserBridge — bridges train-lang's host builtin call to the ccweb
|
|
4
|
+
* frontend.
|
|
5
|
+
*
|
|
6
|
+
* Flow:
|
|
7
|
+
* 1. .tr code calls `__ccweb_ask_user({ fields: [...] })`
|
|
8
|
+
* 2. train evaluates this as a builtin → call our bridge.requestInput()
|
|
9
|
+
* 3. bridge pushes a "track_ask_user" event (via onPush callback)
|
|
10
|
+
* to the WebSocket layer, which broadcasts to the frontend
|
|
11
|
+
* 4. frontend renders a form, user submits → POST /api/.../tracks/input
|
|
12
|
+
* 5. route handler calls bridge.submitInput(runId, requestId, data)
|
|
13
|
+
* 6. bridge resolves the pending Promise → train continues
|
|
14
|
+
*
|
|
15
|
+
* The bridge maintains one pending request per runId. Concurrent
|
|
16
|
+
* ask_user calls within one track would queue (only the most recent
|
|
17
|
+
* pending request is active). For T1 this is fine; multi-prompt would
|
|
18
|
+
* need a queue (T2+).
|
|
19
|
+
*
|
|
20
|
+
* Cancellation: AbortSignal aborts the pending request immediately,
|
|
21
|
+
* rejecting the Promise with a TrainException-shaped error.
|
|
22
|
+
*/
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.createAskUserBridge = createAskUserBridge;
|
|
25
|
+
exports.createAskUserBuiltin = createAskUserBuiltin;
|
|
26
|
+
const train_loader_1 = require("./train-loader");
|
|
27
|
+
function detachSignal(entry) {
|
|
28
|
+
if (entry.signal && entry.signalHandler) {
|
|
29
|
+
entry.signal.removeEventListener('abort', entry.signalHandler);
|
|
30
|
+
entry.signalHandler = undefined;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function createAskUserBridge(onPush) {
|
|
34
|
+
const pending = new Map(); // runId → PendingRequest
|
|
35
|
+
function newRequestId() {
|
|
36
|
+
return 'req-' + Math.random().toString(36).slice(2, 10);
|
|
37
|
+
}
|
|
38
|
+
function validateSpec(spec) {
|
|
39
|
+
if (!Array.isArray(spec) || spec.length === 0) {
|
|
40
|
+
throw new Error('ask_user requires a non-empty fields array');
|
|
41
|
+
}
|
|
42
|
+
const seen = new Set();
|
|
43
|
+
for (const f of spec) {
|
|
44
|
+
if (!f.key || typeof f.key !== 'string') {
|
|
45
|
+
throw new Error('ask_user field missing string key');
|
|
46
|
+
}
|
|
47
|
+
if (seen.has(f.key)) {
|
|
48
|
+
throw new Error(`ask_user duplicate field key: ${f.key}`);
|
|
49
|
+
}
|
|
50
|
+
seen.add(f.key);
|
|
51
|
+
if (f.type === 'enum' && (!f.variants || f.variants.length === 0)) {
|
|
52
|
+
throw new Error(`ask_user enum field "${f.key}" missing variants`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function validateResponse(spec, data) {
|
|
57
|
+
for (const f of spec) {
|
|
58
|
+
const v = data[f.key];
|
|
59
|
+
if (v === undefined && f.required !== false) {
|
|
60
|
+
return { ok: false, message: `missing required field: ${f.key}` };
|
|
61
|
+
}
|
|
62
|
+
if (v === undefined)
|
|
63
|
+
continue;
|
|
64
|
+
switch (f.type) {
|
|
65
|
+
case 'text':
|
|
66
|
+
if (typeof v !== 'string') {
|
|
67
|
+
return { ok: false, message: `${f.key}: expected string` };
|
|
68
|
+
}
|
|
69
|
+
break;
|
|
70
|
+
case 'number':
|
|
71
|
+
if (typeof v !== 'number') {
|
|
72
|
+
return { ok: false, message: `${f.key}: expected number` };
|
|
73
|
+
}
|
|
74
|
+
break;
|
|
75
|
+
case 'bool':
|
|
76
|
+
if (typeof v !== 'boolean') {
|
|
77
|
+
return { ok: false, message: `${f.key}: expected boolean` };
|
|
78
|
+
}
|
|
79
|
+
break;
|
|
80
|
+
case 'enum':
|
|
81
|
+
if (typeof v !== 'string' || !f.variants?.includes(v)) {
|
|
82
|
+
return {
|
|
83
|
+
ok: false,
|
|
84
|
+
message: `${f.key}: must be one of [${f.variants?.join(', ') ?? ''}]`,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return { ok: true };
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
requestInput(runId, spec, signal) {
|
|
94
|
+
validateSpec(spec);
|
|
95
|
+
return new Promise((resolve, reject) => {
|
|
96
|
+
// If a previous request for this runId is still pending,
|
|
97
|
+
// detach its abort listener BEFORE rejecting + replacing.
|
|
98
|
+
// Otherwise an abort on the old signal would `pending.delete(runId)`
|
|
99
|
+
// and clobber the new request.
|
|
100
|
+
const existing = pending.get(runId);
|
|
101
|
+
if (existing) {
|
|
102
|
+
detachSignal(existing);
|
|
103
|
+
pending.delete(runId);
|
|
104
|
+
existing.reject(new Error('superseded by new ask_user request'));
|
|
105
|
+
}
|
|
106
|
+
const request = {
|
|
107
|
+
runId,
|
|
108
|
+
requestId: newRequestId(),
|
|
109
|
+
fields: spec,
|
|
110
|
+
};
|
|
111
|
+
const entry = { request, resolve, reject, signal };
|
|
112
|
+
if (signal) {
|
|
113
|
+
if (signal.aborted) {
|
|
114
|
+
reject(new Error('ask_user cancelled'));
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
// The handler validates that THIS entry is still the active one
|
|
118
|
+
// before mutating the map (defense in depth — supersede path above
|
|
119
|
+
// already detaches, but a separate abort + supersede race could
|
|
120
|
+
// still try to fire stale handlers).
|
|
121
|
+
entry.signalHandler = () => {
|
|
122
|
+
const current = pending.get(runId);
|
|
123
|
+
if (current === entry) {
|
|
124
|
+
pending.delete(runId);
|
|
125
|
+
reject(new Error('ask_user cancelled'));
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
signal.addEventListener('abort', entry.signalHandler, { once: true });
|
|
129
|
+
}
|
|
130
|
+
pending.set(runId, entry);
|
|
131
|
+
onPush({ kind: 'track_ask_user', ...request });
|
|
132
|
+
});
|
|
133
|
+
},
|
|
134
|
+
submitInput(runId, requestId, data) {
|
|
135
|
+
const entry = pending.get(runId);
|
|
136
|
+
if (!entry) {
|
|
137
|
+
return { ok: false, message: `no pending ask_user for runId=${runId}` };
|
|
138
|
+
}
|
|
139
|
+
if (entry.request.requestId !== requestId) {
|
|
140
|
+
return {
|
|
141
|
+
ok: false,
|
|
142
|
+
message: `requestId mismatch (expected ${entry.request.requestId}, got ${requestId})`,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
const v = validateResponse(entry.request.fields, data);
|
|
146
|
+
if (!v.ok)
|
|
147
|
+
return v;
|
|
148
|
+
pending.delete(runId);
|
|
149
|
+
detachSignal(entry);
|
|
150
|
+
entry.resolve(data);
|
|
151
|
+
return { ok: true };
|
|
152
|
+
},
|
|
153
|
+
cancelAllForRun(runId, reason = 'cancelled') {
|
|
154
|
+
const entry = pending.get(runId);
|
|
155
|
+
if (!entry)
|
|
156
|
+
return;
|
|
157
|
+
pending.delete(runId);
|
|
158
|
+
detachSignal(entry);
|
|
159
|
+
entry.reject(new Error(`ask_user ${reason}`));
|
|
160
|
+
},
|
|
161
|
+
getPending(runId) {
|
|
162
|
+
return pending.get(runId)?.request ?? null;
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Build the `__ccweb_ask_user` builtin function bound to this run's
|
|
168
|
+
* bridge + AbortSignal. Pass into TrainOptions.extraBuiltins.
|
|
169
|
+
*/
|
|
170
|
+
async function createAskUserBuiltin(bridge, runId, signal) {
|
|
171
|
+
return (0, train_loader_1.makeBuiltinDynamic)('__ccweb_ask_user', async (args) => {
|
|
172
|
+
// args[0] is the spec object passed from .tr:
|
|
173
|
+
// __ccweb_ask_user({ fields: [...] })
|
|
174
|
+
const arg = args[0];
|
|
175
|
+
if (!arg || typeof arg !== 'object') {
|
|
176
|
+
throw new Error('__ccweb_ask_user expects 1 argument: { fields: [...] }');
|
|
177
|
+
}
|
|
178
|
+
const fields = arg.fields;
|
|
179
|
+
if (!Array.isArray(fields)) {
|
|
180
|
+
throw new Error('__ccweb_ask_user spec.fields must be an array');
|
|
181
|
+
}
|
|
182
|
+
const result = await bridge.requestInput(runId, fields, signal);
|
|
183
|
+
return result;
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=ask-user-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ask-user-bridge.js","sourceRoot":"","sources":["../../src/tracks/ask-user-bridge.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;AA+DH,kDA2IC;AAMD,oDAqBC;AAlOD,iDAAmD;AAqDnD,SAAS,YAAY,CAAC,KAAqB;IACzC,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,aAAa,EAAE,CAAC;QACxC,KAAK,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,aAAa,CAAC,CAAA;QAC9D,KAAK,CAAC,aAAa,GAAG,SAAS,CAAA;IACjC,CAAC;AACH,CAAC;AAED,SAAgB,mBAAmB,CAAC,MAAqB;IACvD,MAAM,OAAO,GAAG,IAAI,GAAG,EAA0B,CAAA,CAAC,yBAAyB;IAE3E,SAAS,YAAY;QACnB,OAAO,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IACzD,CAAC;IAED,SAAS,YAAY,CAAC,IAAwB;QAC5C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9C,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAA;QAC/D,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;QAC9B,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,OAAO,CAAC,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;gBACxC,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAA;YACtD,CAAC;YACD,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;gBACpB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAA;YAC3D,CAAC;YACD,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;YACf,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;gBAClE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC,GAAG,oBAAoB,CAAC,CAAA;YACpE,CAAC;QACH,CAAC;IACH,CAAC;IAED,SAAS,gBAAgB,CACvB,IAAwB,EACxB,IAA2B;QAE3B,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;YACrB,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;gBAC5C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,2BAA2B,CAAC,CAAC,GAAG,EAAE,EAAE,CAAA;YACnE,CAAC;YACD,IAAI,CAAC,KAAK,SAAS;gBAAE,SAAQ;YAC7B,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;gBACf,KAAK,MAAM;oBACT,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;wBAC1B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,GAAG,mBAAmB,EAAE,CAAA;oBAC5D,CAAC;oBACD,MAAK;gBACP,KAAK,QAAQ;oBACX,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;wBAC1B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,GAAG,mBAAmB,EAAE,CAAA;oBAC5D,CAAC;oBACD,MAAK;gBACP,KAAK,MAAM;oBACT,IAAI,OAAO,CAAC,KAAK,SAAS,EAAE,CAAC;wBAC3B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,GAAG,oBAAoB,EAAE,CAAA;oBAC7D,CAAC;oBACD,MAAK;gBACP,KAAK,MAAM;oBACT,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;wBACtD,OAAO;4BACL,EAAE,EAAE,KAAK;4BACT,OAAO,EAAE,GAAG,CAAC,CAAC,GAAG,qBAAqB,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG;yBACtE,CAAA;oBACH,CAAC;oBACD,MAAK;YACT,CAAC;QACH,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAA;IACrB,CAAC;IAED,OAAO;QACL,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM;YAC9B,YAAY,CAAC,IAAI,CAAC,CAAA;YAClB,OAAO,IAAI,OAAO,CAAwB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBAC5D,yDAAyD;gBACzD,0DAA0D;gBAC1D,qEAAqE;gBACrE,+BAA+B;gBAC/B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;gBACnC,IAAI,QAAQ,EAAE,CAAC;oBACb,YAAY,CAAC,QAAQ,CAAC,CAAA;oBACtB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;oBACrB,QAAQ,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC,CAAA;gBAClE,CAAC;gBACD,MAAM,OAAO,GAAmB;oBAC9B,KAAK;oBACL,SAAS,EAAE,YAAY,EAAE;oBACzB,MAAM,EAAE,IAAI;iBACb,CAAA;gBACD,MAAM,KAAK,GAAmB,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAA;gBAClE,IAAI,MAAM,EAAE,CAAC;oBACX,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;wBACnB,MAAM,CAAC,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAA;wBACvC,OAAM;oBACR,CAAC;oBACD,gEAAgE;oBAChE,mEAAmE;oBACnE,gEAAgE;oBAChE,qCAAqC;oBACrC,KAAK,CAAC,aAAa,GAAG,GAAG,EAAE;wBACzB,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;wBAClC,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;4BACtB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;4BACrB,MAAM,CAAC,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAA;wBACzC,CAAC;oBACH,CAAC,CAAA;oBACD,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,aAAa,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;gBACvE,CAAC;gBACD,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;gBACzB,MAAM,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,GAAG,OAAO,EAAE,CAAC,CAAA;YAChD,CAAC,CAAC,CAAA;QACJ,CAAC;QAED,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI;YAChC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YAChC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,iCAAiC,KAAK,EAAE,EAAE,CAAA;YACzE,CAAC;YACD,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;gBAC1C,OAAO;oBACL,EAAE,EAAE,KAAK;oBACT,OAAO,EAAE,gCAAgC,KAAK,CAAC,OAAO,CAAC,SAAS,SAAS,SAAS,GAAG;iBACtF,CAAA;YACH,CAAC;YACD,MAAM,CAAC,GAAG,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;YACtD,IAAI,CAAC,CAAC,CAAC,EAAE;gBAAE,OAAO,CAAC,CAAA;YACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YACrB,YAAY,CAAC,KAAK,CAAC,CAAA;YACnB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;YACnB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAA;QACrB,CAAC;QAED,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW;YACzC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YAChC,IAAI,CAAC,KAAK;gBAAE,OAAM;YAClB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YACrB,YAAY,CAAC,KAAK,CAAC,CAAA;YACnB,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,YAAY,MAAM,EAAE,CAAC,CAAC,CAAA;QAC/C,CAAC;QAED,UAAU,CAAC,KAAK;YACd,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,OAAO,IAAI,IAAI,CAAA;QAC5C,CAAC;KACF,CAAA;AACH,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,oBAAoB,CACxC,MAAqB,EACrB,KAAa,EACb,MAAoB;IAEpB,OAAO,IAAA,iCAAkB,EAAC,kBAAkB,EAAE,KAAK,EAAE,IAAa,EAAE,EAAE;QACpE,8CAA8C;QAC9C,wCAAwC;QACxC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAA2C,CAAA;QAC7D,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CACb,wDAAwD,CACzD,CAAA;QACH,CAAC;QACD,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAA;QACzB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;QAClE,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;QAC/D,OAAO,MAA0B,CAAA;IACnC,CAAC,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CcwebTrainAdapter — bridges train-lang's LLMAdapter interface to
|
|
3
|
+
* ccweb's PTY + workflow_data.json infrastructure.
|
|
4
|
+
*
|
|
5
|
+
* Paradigm: writesWorkflowData=true (agent CLI). train-lang composes
|
|
6
|
+
* the [System][Inputs][Task][Outputs] prompt; ccweb appends a
|
|
7
|
+
* writeProtocolHint that tells the LLM to write outputs into
|
|
8
|
+
* `.ccweb/workflow_data.json` at `variables.<name>`, then signal
|
|
9
|
+
* completion via `task_progress.push({...finish:true})`.
|
|
10
|
+
*
|
|
11
|
+
* 详见 ~/Obsidian/Base/cc-web/工作轨重构规划.md §5。
|
|
12
|
+
*/
|
|
13
|
+
import type { LLMAdapter } from '@train-lang/adapter-spec';
|
|
14
|
+
import type { WorkflowDataWatcher } from './workflow-data-watcher';
|
|
15
|
+
export interface CcwebAdapterDeps {
|
|
16
|
+
projectId: string;
|
|
17
|
+
runId: string;
|
|
18
|
+
/** Inject text into the project's active CLI PTY. */
|
|
19
|
+
injector: (text: string) => Promise<void> | void;
|
|
20
|
+
/** Watcher for `.ccweb/workflow_data.json`. */
|
|
21
|
+
watcher: WorkflowDataWatcher;
|
|
22
|
+
/** Per-run monotonic counter assigning task_progress[] index. */
|
|
23
|
+
nextTaskIndex: () => number;
|
|
24
|
+
/** Optional logger (pino-compatible interface). */
|
|
25
|
+
logger?: {
|
|
26
|
+
debug?: (msg: string, ...args: unknown[]) => void;
|
|
27
|
+
info?: (msg: string, ...args: unknown[]) => void;
|
|
28
|
+
warn?: (msg: string, ...args: unknown[]) => void;
|
|
29
|
+
error?: (msg: string, ...args: unknown[]) => void;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The writeProtocolHint string injected into train's prompt. ccweb's
|
|
34
|
+
* single authoritative "how to write back" instruction — replaces
|
|
35
|
+
* train's default `stack[<callId>].outputs` hint (which doesn't match
|
|
36
|
+
* ccweb v2 schema).
|
|
37
|
+
*/
|
|
38
|
+
export declare function buildCcwebWriteProtocolHint(): string;
|
|
39
|
+
export declare function createCcwebTrainAdapter(deps: CcwebAdapterDeps): LLMAdapter;
|
|
40
|
+
//# sourceMappingURL=ccweb-train-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ccweb-train-adapter.d.ts","sourceRoot":"","sources":["../../src/tracks/ccweb-train-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EACV,UAAU,EAGX,MAAM,0BAA0B,CAAA;AACjC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAElE,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,qDAAqD;IACrD,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAChD,+CAA+C;IAC/C,OAAO,EAAE,mBAAmB,CAAA;IAC5B,iEAAiE;IACjE,aAAa,EAAE,MAAM,MAAM,CAAA;IAC3B,mDAAmD;IACnD,MAAM,CAAC,EAAE;QACP,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;QACjD,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;QAChD,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;QAChD,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;KAClD,CAAA;CACF;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,IAAI,MAAM,CAapD;AA+BD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,gBAAgB,GAAG,UAAU,CAgE1E"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* CcwebTrainAdapter — bridges train-lang's LLMAdapter interface to
|
|
4
|
+
* ccweb's PTY + workflow_data.json infrastructure.
|
|
5
|
+
*
|
|
6
|
+
* Paradigm: writesWorkflowData=true (agent CLI). train-lang composes
|
|
7
|
+
* the [System][Inputs][Task][Outputs] prompt; ccweb appends a
|
|
8
|
+
* writeProtocolHint that tells the LLM to write outputs into
|
|
9
|
+
* `.ccweb/workflow_data.json` at `variables.<name>`, then signal
|
|
10
|
+
* completion via `task_progress.push({...finish:true})`.
|
|
11
|
+
*
|
|
12
|
+
* 详见 ~/Obsidian/Base/cc-web/工作轨重构规划.md §5。
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.buildCcwebWriteProtocolHint = buildCcwebWriteProtocolHint;
|
|
16
|
+
exports.createCcwebTrainAdapter = createCcwebTrainAdapter;
|
|
17
|
+
/**
|
|
18
|
+
* The writeProtocolHint string injected into train's prompt. ccweb's
|
|
19
|
+
* single authoritative "how to write back" instruction — replaces
|
|
20
|
+
* train's default `stack[<callId>].outputs` hint (which doesn't match
|
|
21
|
+
* ccweb v2 schema).
|
|
22
|
+
*/
|
|
23
|
+
function buildCcwebWriteProtocolHint() {
|
|
24
|
+
return [
|
|
25
|
+
'[Write outputs to .ccweb/workflow_data.json, then signal completion:]',
|
|
26
|
+
' 1. For each declared output `<name>` in [Required outputs] above:',
|
|
27
|
+
' set variables.<name> = <your value matching the declared type>',
|
|
28
|
+
' 2. Append to task_progress:',
|
|
29
|
+
' { nodeId: <taskIndex from prompt header>, name: "<fai name>", ' +
|
|
30
|
+
'finish: true, finishedAt: <unix ms> }',
|
|
31
|
+
'',
|
|
32
|
+
'Do NOT touch other variables. Do NOT modify constants. Do NOT remove ' +
|
|
33
|
+
'existing task_progress entries.',
|
|
34
|
+
'After writing, the train runtime will read variables.<name> and continue.',
|
|
35
|
+
].join('\n');
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Compose the ccweb-specific prompt prefix that identifies the current
|
|
39
|
+
* call's taskIndex (for the writeProtocolHint instructions to reference).
|
|
40
|
+
*
|
|
41
|
+
* This is prepended (NOT appended) to the prompt train already composed,
|
|
42
|
+
* so it's visible above [Required outputs].
|
|
43
|
+
*/
|
|
44
|
+
function buildCcwebHeader(taskIndex, fnName) {
|
|
45
|
+
return `[ccweb track context]\n taskIndex = ${taskIndex}\n fai = ${fnName}\n`;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Filter workflow_data.variables to just the outputs declared on the
|
|
49
|
+
* fai call. Extra keys are ignored (train validator will catch missing
|
|
50
|
+
* keys as schema mismatch).
|
|
51
|
+
*/
|
|
52
|
+
function pickOutputs(variables, outputSchema) {
|
|
53
|
+
const out = {};
|
|
54
|
+
for (const key of Object.keys(outputSchema)) {
|
|
55
|
+
if (key in variables) {
|
|
56
|
+
out[key] = variables[key];
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
function createCcwebTrainAdapter(deps) {
|
|
62
|
+
return {
|
|
63
|
+
name: 'ccweb',
|
|
64
|
+
version: '0.0.0',
|
|
65
|
+
capabilities: {
|
|
66
|
+
parallel: false, // one CLI process per project
|
|
67
|
+
cancellation: true, // honors req.options.signal
|
|
68
|
+
writesWorkflowData: true,
|
|
69
|
+
},
|
|
70
|
+
async call(req) {
|
|
71
|
+
const taskIndex = deps.nextTaskIndex();
|
|
72
|
+
deps.logger?.debug?.('[CcwebTrainAdapter] dispatch', { fnName: req.fnName, taskIndex, callId: req.callId, attempt: req.options.attempt });
|
|
73
|
+
// Compose final prompt = ccweb header + train's prompt (which
|
|
74
|
+
// already includes writeProtocolHint from RunOptions).
|
|
75
|
+
const finalPrompt = buildCcwebHeader(taskIndex, req.fnName) + '\n' + req.prompt;
|
|
76
|
+
// 1. Inject into PTY
|
|
77
|
+
try {
|
|
78
|
+
await deps.injector(finalPrompt);
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
return {
|
|
82
|
+
kind: 'error',
|
|
83
|
+
message: `ccweb adapter: failed to inject prompt: ${e.message}`,
|
|
84
|
+
recoverable: false,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
// 2. Wait for task_progress[taskIndex].finish=true
|
|
88
|
+
const outcome = await deps.watcher.waitForFinish(taskIndex, req.options.timeoutMs, req.options.signal);
|
|
89
|
+
if (outcome.kind === 'timeout') {
|
|
90
|
+
deps.logger?.warn?.('[CcwebTrainAdapter] timeout', { taskIndex });
|
|
91
|
+
return { kind: 'timeout' };
|
|
92
|
+
}
|
|
93
|
+
if (outcome.kind === 'cancelled') {
|
|
94
|
+
deps.logger?.info?.('[CcwebTrainAdapter] cancelled', { taskIndex });
|
|
95
|
+
return { kind: 'cancelled' };
|
|
96
|
+
}
|
|
97
|
+
if (outcome.kind === 'error') {
|
|
98
|
+
return {
|
|
99
|
+
kind: 'error',
|
|
100
|
+
message: `ccweb adapter: watcher error: ${outcome.message}`,
|
|
101
|
+
recoverable: false,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
// 3. Read outputs from workflow_data.variables
|
|
105
|
+
const outputs = pickOutputs(outcome.data.variables ?? {}, req.outputs);
|
|
106
|
+
deps.logger?.debug?.('[CcwebTrainAdapter] success', { taskIndex, outputKeys: Object.keys(outputs) });
|
|
107
|
+
return { kind: 'success', outputs };
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=ccweb-train-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ccweb-train-adapter.js","sourceRoot":"","sources":["../../src/tracks/ccweb-train-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-subsystem lock between flows and tracks.
|
|
3
|
+
*
|
|
4
|
+
* Both flows/runner.ts and tracks/registry.ts write
|
|
5
|
+
* <project>/.ccweb/workflow_data.json. Concurrent runs on the same
|
|
6
|
+
* project would corrupt that file (RMW race). This module exposes a
|
|
7
|
+
* small registry so each side can ask "is the other currently running
|
|
8
|
+
* on this project?" without creating an import cycle between
|
|
9
|
+
* routes/flows.ts and routes/tracks.ts or between flows/runner.ts and
|
|
10
|
+
* tracks/registry.ts.
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* - index.ts constructs `trackRegistry` and calls
|
|
14
|
+
* `setTrackRunningProbe((pid) => trackRegistry.isRunning(pid))`
|
|
15
|
+
* - routes/flows.ts's run handler calls `isTrackRunning(pid)` before
|
|
16
|
+
* starting a flow; rejects with 409 if a track is in flight.
|
|
17
|
+
* - routes/tracks.ts's run handler imports flowRunner directly
|
|
18
|
+
* (already in the same module graph) and calls
|
|
19
|
+
* `flowRunner.isRunning(pid)` before starting a track.
|
|
20
|
+
*
|
|
21
|
+
* The asymmetry (flows side uses a probe, tracks side imports
|
|
22
|
+
* flowRunner) is intentional: flowRunner has been a stable module
|
|
23
|
+
* singleton since v1; trackRegistry was created later inside index.ts
|
|
24
|
+
* to avoid leaking PTY infra into module init.
|
|
25
|
+
*/
|
|
26
|
+
type RunningProbe = (projectId: string) => boolean;
|
|
27
|
+
export declare function setTrackRunningProbe(fn: RunningProbe): void;
|
|
28
|
+
export declare function isTrackRunning(projectId: string): boolean;
|
|
29
|
+
export {};
|
|
30
|
+
//# sourceMappingURL=cross-lock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cross-lock.d.ts","sourceRoot":"","sources":["../../src/tracks/cross-lock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,KAAK,YAAY,GAAG,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAA;AAIlD,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAE3D;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAOzD"}
|