@tom2012/cc-web 2026.5.14-a → 2026.5.15-a
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-DsfZXjjz.js → ChatOverlay-D0AFod2I.js} +1 -1
- package/frontend/dist/assets/{GraphPreview-BGZHA8KW.js → GraphPreview-BTnlkocf.js} +2 -2
- package/frontend/dist/assets/{MobilePage-B-FiVfUE.js → MobilePage-CnjdRqIt.js} +3 -3
- package/frontend/dist/assets/{OfficePreview-CvHPeAlI.js → OfficePreview-nTZKPD9R.js} +2 -2
- package/frontend/dist/assets/{PdfPreview-D1OVG7jG.js → PdfPreview-DlB-s5M8.js} +1 -1
- package/frontend/dist/assets/{ProjectPage-CyKEenc5.js → ProjectPage-C_3_sZbd.js} +5 -5
- package/frontend/dist/assets/{SettingsPage-CIe3HZml.js → SettingsPage-BYSCQKoh.js} +2 -2
- package/frontend/dist/assets/{SkillHubPage-CG1-G4Pf.js → SkillHubPage-CUgZXyeE.js} +3 -3
- package/frontend/dist/assets/TrackEditor-R2lmPugZ.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-CS7uu2Ol.js → chevron-down-Bc6Xpnnk.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-oT-78_Ke.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-CKHkO4rf.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-gLqtlSdW.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-CMR-cKzv.js +7 -0
- package/frontend/dist/assets/hcl-BhbOULbp.js +7 -0
- package/frontend/dist/assets/html-er6LXl7Q.js +7 -0
- package/frontend/dist/assets/htmlMode-BY7CWp3G.js +7 -0
- package/frontend/dist/assets/index-BmPb0Wl1.css +1 -0
- package/frontend/dist/assets/{index-DN91i4kg.js → index-C6JmYBh3.js} +1 -1
- package/frontend/dist/assets/{index-BThL9NV3.js → index-C7QaGdFu.js} +2 -2
- package/frontend/dist/assets/{index-DCc5jmus.js → index-CuoDBJ4_.js} +1 -1
- package/frontend/dist/assets/index-LxjrLxfp.js +1 -0
- package/frontend/dist/assets/ini-zR-_X5iG.js +7 -0
- package/frontend/dist/assets/java-CSTjsyoZ.js +7 -0
- package/frontend/dist/assets/javascript-R0QZ7Rw2.js +7 -0
- package/frontend/dist/assets/jsonMode-dh6Js0Qv.js +7 -0
- package/frontend/dist/assets/{jszip.min-DHcltCpp.js → jszip.min-D7W3wEX7.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-ggFR895M.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-B4WBy0Yh.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-AIGmVleM.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-BGAZW957.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-C09dwvOR.js → select-B9gOzVx5.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-UrEEwBkN.js +7 -0
- package/frontend/dist/assets/twig-Deid_oBs.js +7 -0
- package/frontend/dist/assets/typescript-BTfMCp5C.js +7 -0
- package/frontend/dist/assets/typespec-zUaxhbG8.js +7 -0
- package/frontend/dist/assets/{user-Bj8X-WCQ.js → user-BG-Xqf8M.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-BCL5DPdB.js +7 -0
- package/frontend/dist/assets/yaml-B__nW1c2.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,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Cross-subsystem lock between flows and tracks.
|
|
4
|
+
*
|
|
5
|
+
* Both flows/runner.ts and tracks/registry.ts write
|
|
6
|
+
* <project>/.ccweb/workflow_data.json. Concurrent runs on the same
|
|
7
|
+
* project would corrupt that file (RMW race). This module exposes a
|
|
8
|
+
* small registry so each side can ask "is the other currently running
|
|
9
|
+
* on this project?" without creating an import cycle between
|
|
10
|
+
* routes/flows.ts and routes/tracks.ts or between flows/runner.ts and
|
|
11
|
+
* tracks/registry.ts.
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* - index.ts constructs `trackRegistry` and calls
|
|
15
|
+
* `setTrackRunningProbe((pid) => trackRegistry.isRunning(pid))`
|
|
16
|
+
* - routes/flows.ts's run handler calls `isTrackRunning(pid)` before
|
|
17
|
+
* starting a flow; rejects with 409 if a track is in flight.
|
|
18
|
+
* - routes/tracks.ts's run handler imports flowRunner directly
|
|
19
|
+
* (already in the same module graph) and calls
|
|
20
|
+
* `flowRunner.isRunning(pid)` before starting a track.
|
|
21
|
+
*
|
|
22
|
+
* The asymmetry (flows side uses a probe, tracks side imports
|
|
23
|
+
* flowRunner) is intentional: flowRunner has been a stable module
|
|
24
|
+
* singleton since v1; trackRegistry was created later inside index.ts
|
|
25
|
+
* to avoid leaking PTY infra into module init.
|
|
26
|
+
*/
|
|
27
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
+
exports.setTrackRunningProbe = setTrackRunningProbe;
|
|
29
|
+
exports.isTrackRunning = isTrackRunning;
|
|
30
|
+
let trackProbe = null;
|
|
31
|
+
function setTrackRunningProbe(fn) {
|
|
32
|
+
trackProbe = fn;
|
|
33
|
+
}
|
|
34
|
+
function isTrackRunning(projectId) {
|
|
35
|
+
if (!trackProbe)
|
|
36
|
+
return false;
|
|
37
|
+
try {
|
|
38
|
+
return trackProbe(projectId);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=cross-lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cross-lock.js","sourceRoot":"","sources":["../../src/tracks/cross-lock.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;;AAMH,oDAEC;AAED,wCAOC;AAbD,IAAI,UAAU,GAAwB,IAAI,CAAA;AAE1C,SAAgB,oBAAoB,CAAC,EAAgB;IACnD,UAAU,GAAG,EAAE,CAAA;AACjB,CAAC;AAED,SAAgB,cAAc,CAAC,SAAiB;IAC9C,IAAI,CAAC,UAAU;QAAE,OAAO,KAAK,CAAA;IAC7B,IAAI,CAAC;QACH,OAAO,UAAU,CAAC,SAAS,CAAC,CAAA;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ccweb "工作轨" (Track) subsystem — public exports.
|
|
3
|
+
*
|
|
4
|
+
* Entry points for the rest of the backend:
|
|
5
|
+
* - createTrackRunner({ ... }) → run .tr files
|
|
6
|
+
* - createCcwebTrainAdapter({ ... }) → train-lang LLMAdapter impl
|
|
7
|
+
* - createWorkflowDataWatcher(path) → workflow_data.json file watch
|
|
8
|
+
*
|
|
9
|
+
* See ~/Obsidian/Base/cc-web/工作轨重构规划.md for the architecture
|
|
10
|
+
* design and phase plan.
|
|
11
|
+
*/
|
|
12
|
+
export { createTrackRunner, type TrackRunner, type TrackRunnerDeps, type TrackRunResult, } from './track-runner';
|
|
13
|
+
export { createCcwebTrainAdapter, buildCcwebWriteProtocolHint, type CcwebAdapterDeps, } from './ccweb-train-adapter';
|
|
14
|
+
export { createWorkflowDataWatcher, type WorkflowDataWatcher, type FinishOutcome, } from './workflow-data-watcher';
|
|
15
|
+
export type { WorkflowData, TaskProgressEntry, TrackCallState, TrackRunStatus, TrackRunState, AdapterCallContext, } from './types';
|
|
16
|
+
export { createAskUserBridge, createAskUserBuiltin, type AskUserBridge, type AskUserFieldSpec, type AskUserRequest, type AskUserPushEvent, type AskUserPushFn, } from './ask-user-bridge';
|
|
17
|
+
export { loadTrainCore, makeBuiltinDynamic } from './train-loader';
|
|
18
|
+
export { createTrackRegistry, type TrackRegistry, type TrackRegistryDeps, } from './registry';
|
|
19
|
+
export { listTracks, loadTrack, saveTrack, deleteTrack, resolveTrackPath, sanitizeTrackFilename, listGlobalTracks, loadGlobalTrack, saveGlobalTrack, deleteGlobalTrack, resolveGlobalTrackPath, type TrackFileInfo, } from './store';
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tracks/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,iBAAiB,EACjB,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,cAAc,GACpB,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EACL,uBAAuB,EACvB,2BAA2B,EAC3B,KAAK,gBAAgB,GACtB,MAAM,uBAAuB,CAAA;AAE9B,OAAO,EACL,yBAAyB,EACzB,KAAK,mBAAmB,EACxB,KAAK,aAAa,GACnB,MAAM,yBAAyB,CAAA;AAEhC,YAAY,EACV,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,aAAa,EACb,kBAAkB,GACnB,MAAM,SAAS,CAAA;AAEhB,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,aAAa,GACnB,MAAM,mBAAmB,CAAA;AAE1B,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAElE,OAAO,EACL,mBAAmB,EACnB,KAAK,aAAa,EAClB,KAAK,iBAAiB,GACvB,MAAM,YAAY,CAAA;AAEnB,OAAO,EACL,UAAU,EACV,SAAS,EACT,SAAS,EACT,WAAW,EACX,gBAAgB,EAChB,qBAAqB,EACrB,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,sBAAsB,EACtB,KAAK,aAAa,GACnB,MAAM,SAAS,CAAA"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* ccweb "工作轨" (Track) subsystem — public exports.
|
|
4
|
+
*
|
|
5
|
+
* Entry points for the rest of the backend:
|
|
6
|
+
* - createTrackRunner({ ... }) → run .tr files
|
|
7
|
+
* - createCcwebTrainAdapter({ ... }) → train-lang LLMAdapter impl
|
|
8
|
+
* - createWorkflowDataWatcher(path) → workflow_data.json file watch
|
|
9
|
+
*
|
|
10
|
+
* See ~/Obsidian/Base/cc-web/工作轨重构规划.md for the architecture
|
|
11
|
+
* design and phase plan.
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.resolveGlobalTrackPath = exports.deleteGlobalTrack = exports.saveGlobalTrack = exports.loadGlobalTrack = exports.listGlobalTracks = exports.sanitizeTrackFilename = exports.resolveTrackPath = exports.deleteTrack = exports.saveTrack = exports.loadTrack = exports.listTracks = exports.createTrackRegistry = exports.makeBuiltinDynamic = exports.loadTrainCore = exports.createAskUserBuiltin = exports.createAskUserBridge = exports.createWorkflowDataWatcher = exports.buildCcwebWriteProtocolHint = exports.createCcwebTrainAdapter = exports.createTrackRunner = void 0;
|
|
15
|
+
var track_runner_1 = require("./track-runner");
|
|
16
|
+
Object.defineProperty(exports, "createTrackRunner", { enumerable: true, get: function () { return track_runner_1.createTrackRunner; } });
|
|
17
|
+
var ccweb_train_adapter_1 = require("./ccweb-train-adapter");
|
|
18
|
+
Object.defineProperty(exports, "createCcwebTrainAdapter", { enumerable: true, get: function () { return ccweb_train_adapter_1.createCcwebTrainAdapter; } });
|
|
19
|
+
Object.defineProperty(exports, "buildCcwebWriteProtocolHint", { enumerable: true, get: function () { return ccweb_train_adapter_1.buildCcwebWriteProtocolHint; } });
|
|
20
|
+
var workflow_data_watcher_1 = require("./workflow-data-watcher");
|
|
21
|
+
Object.defineProperty(exports, "createWorkflowDataWatcher", { enumerable: true, get: function () { return workflow_data_watcher_1.createWorkflowDataWatcher; } });
|
|
22
|
+
var ask_user_bridge_1 = require("./ask-user-bridge");
|
|
23
|
+
Object.defineProperty(exports, "createAskUserBridge", { enumerable: true, get: function () { return ask_user_bridge_1.createAskUserBridge; } });
|
|
24
|
+
Object.defineProperty(exports, "createAskUserBuiltin", { enumerable: true, get: function () { return ask_user_bridge_1.createAskUserBuiltin; } });
|
|
25
|
+
var train_loader_1 = require("./train-loader");
|
|
26
|
+
Object.defineProperty(exports, "loadTrainCore", { enumerable: true, get: function () { return train_loader_1.loadTrainCore; } });
|
|
27
|
+
Object.defineProperty(exports, "makeBuiltinDynamic", { enumerable: true, get: function () { return train_loader_1.makeBuiltinDynamic; } });
|
|
28
|
+
var registry_1 = require("./registry");
|
|
29
|
+
Object.defineProperty(exports, "createTrackRegistry", { enumerable: true, get: function () { return registry_1.createTrackRegistry; } });
|
|
30
|
+
var store_1 = require("./store");
|
|
31
|
+
Object.defineProperty(exports, "listTracks", { enumerable: true, get: function () { return store_1.listTracks; } });
|
|
32
|
+
Object.defineProperty(exports, "loadTrack", { enumerable: true, get: function () { return store_1.loadTrack; } });
|
|
33
|
+
Object.defineProperty(exports, "saveTrack", { enumerable: true, get: function () { return store_1.saveTrack; } });
|
|
34
|
+
Object.defineProperty(exports, "deleteTrack", { enumerable: true, get: function () { return store_1.deleteTrack; } });
|
|
35
|
+
Object.defineProperty(exports, "resolveTrackPath", { enumerable: true, get: function () { return store_1.resolveTrackPath; } });
|
|
36
|
+
Object.defineProperty(exports, "sanitizeTrackFilename", { enumerable: true, get: function () { return store_1.sanitizeTrackFilename; } });
|
|
37
|
+
Object.defineProperty(exports, "listGlobalTracks", { enumerable: true, get: function () { return store_1.listGlobalTracks; } });
|
|
38
|
+
Object.defineProperty(exports, "loadGlobalTrack", { enumerable: true, get: function () { return store_1.loadGlobalTrack; } });
|
|
39
|
+
Object.defineProperty(exports, "saveGlobalTrack", { enumerable: true, get: function () { return store_1.saveGlobalTrack; } });
|
|
40
|
+
Object.defineProperty(exports, "deleteGlobalTrack", { enumerable: true, get: function () { return store_1.deleteGlobalTrack; } });
|
|
41
|
+
Object.defineProperty(exports, "resolveGlobalTrackPath", { enumerable: true, get: function () { return store_1.resolveGlobalTrackPath; } });
|
|
42
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tracks/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;AAEH,+CAKuB;AAJrB,iHAAA,iBAAiB,OAAA;AAMnB,6DAI8B;AAH5B,8HAAA,uBAAuB,OAAA;AACvB,kIAAA,2BAA2B,OAAA;AAI7B,iEAIgC;AAH9B,kIAAA,yBAAyB,OAAA;AAc3B,qDAQ0B;AAPxB,sHAAA,mBAAmB,OAAA;AACnB,uHAAA,oBAAoB,OAAA;AAQtB,+CAAkE;AAAzD,6GAAA,aAAa,OAAA;AAAE,kHAAA,kBAAkB,OAAA;AAE1C,uCAImB;AAHjB,+GAAA,mBAAmB,OAAA;AAKrB,iCAagB;AAZd,mGAAA,UAAU,OAAA;AACV,kGAAA,SAAS,OAAA;AACT,kGAAA,SAAS,OAAA;AACT,oGAAA,WAAW,OAAA;AACX,yGAAA,gBAAgB,OAAA;AAChB,8GAAA,qBAAqB,OAAA;AACrB,yGAAA,gBAAgB,OAAA;AAChB,wGAAA,eAAe,OAAA;AACf,wGAAA,eAAe,OAAA;AACf,0GAAA,iBAAiB,OAAA;AACjB,+GAAA,sBAAsB,OAAA"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TrackRunnerRegistry — per-project TrackRunner accounting.
|
|
3
|
+
*
|
|
4
|
+
* Singleton owned by backend/src/index.ts. Wraps creation of a runner
|
|
5
|
+
* (with the project's PTY injector + workflow_data path) and exposes
|
|
6
|
+
* lifecycle calls used by the HTTP route handlers.
|
|
7
|
+
*
|
|
8
|
+
* One project can have at most one in-flight track run; starting a
|
|
9
|
+
* new one while another is running rejects with 'busy'.
|
|
10
|
+
*/
|
|
11
|
+
import { type AskUserFieldSpec } from './ask-user-bridge';
|
|
12
|
+
import type { TrackRunState } from './types';
|
|
13
|
+
export interface TrackRegistryDeps {
|
|
14
|
+
/** Look up the absolute project folder path by projectId. */
|
|
15
|
+
getProjectFolder: (projectId: string) => string | null;
|
|
16
|
+
/** Inject text into the project's active CLI PTY. */
|
|
17
|
+
injectIntoPty: (projectId: string, text: string) => Promise<void> | void;
|
|
18
|
+
/** Push a JSON message to all WS clients subscribed to this project. */
|
|
19
|
+
broadcast: (projectId: string, message: Record<string, unknown>) => void;
|
|
20
|
+
/** Pino-compatible logger. */
|
|
21
|
+
logger?: {
|
|
22
|
+
debug?: (msg: string, ...args: unknown[]) => void;
|
|
23
|
+
info?: (msg: string, ...args: unknown[]) => void;
|
|
24
|
+
warn?: (msg: string, ...args: unknown[]) => void;
|
|
25
|
+
error?: (msg: string, ...args: unknown[]) => void;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export interface TrackRegistry {
|
|
29
|
+
/** Start a track run. */
|
|
30
|
+
start(projectId: string, absTrackPath: string, trackFilename: string, args?: unknown[]): Promise<{
|
|
31
|
+
ok: true;
|
|
32
|
+
runId: string;
|
|
33
|
+
} | {
|
|
34
|
+
ok: false;
|
|
35
|
+
reason: string;
|
|
36
|
+
}>;
|
|
37
|
+
/** Cancel the in-flight run for a project. */
|
|
38
|
+
abort(projectId: string): boolean;
|
|
39
|
+
/** Submit user input for a pending ask_user request. */
|
|
40
|
+
submitInput(projectId: string, requestId: string, data: Record<string, unknown>): {
|
|
41
|
+
ok: boolean;
|
|
42
|
+
message?: string;
|
|
43
|
+
};
|
|
44
|
+
/** Get the latest state for a project (running or last finished). */
|
|
45
|
+
getState(projectId: string): TrackRunState | null;
|
|
46
|
+
/** True if a run is in flight (status === running or paused). */
|
|
47
|
+
isRunning(projectId: string): boolean;
|
|
48
|
+
/** Get the pending ask_user request if any. */
|
|
49
|
+
getPendingAskUser(projectId: string): {
|
|
50
|
+
runId: string;
|
|
51
|
+
requestId: string;
|
|
52
|
+
fields: AskUserFieldSpec[];
|
|
53
|
+
} | null;
|
|
54
|
+
}
|
|
55
|
+
export declare function createTrackRegistry(deps: TrackRegistryDeps): TrackRegistry;
|
|
56
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/tracks/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,EAA2C,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAClG,OAAO,KAAK,EAAE,aAAa,EAAkB,MAAM,SAAS,CAAA;AAE5D,MAAM,WAAW,iBAAiB;IAChC,6DAA6D;IAC7D,gBAAgB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAA;IACtD,qDAAqD;IACrD,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IACxE,wEAAwE;IACxE,SAAS,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;IACxE,8BAA8B;IAC9B,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;AAkBD,MAAM,WAAW,aAAa;IAC5B,yBAAyB;IACzB,KAAK,CACH,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,IAAI,CAAC,EAAE,OAAO,EAAE,GACf,OAAO,CAAC;QAAE,EAAE,EAAE,IAAI,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAEvE,8CAA8C;IAC9C,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAA;IAEjC,wDAAwD;IACxD,WAAW,CACT,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAEpC,qEAAqE;IACrE,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAAA;IAEjD,iEAAiE;IACjE,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAA;IAErC,+CAA+C;IAC/C,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG;QACpC,KAAK,EAAE,MAAM,CAAA;QACb,SAAS,EAAE,MAAM,CAAA;QACjB,MAAM,EAAE,gBAAgB,EAAE,CAAA;KAC3B,GAAG,IAAI,CAAA;CACT;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,iBAAiB,GAAG,aAAa,CAqH1E"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* TrackRunnerRegistry — per-project TrackRunner accounting.
|
|
4
|
+
*
|
|
5
|
+
* Singleton owned by backend/src/index.ts. Wraps creation of a runner
|
|
6
|
+
* (with the project's PTY injector + workflow_data path) and exposes
|
|
7
|
+
* lifecycle calls used by the HTTP route handlers.
|
|
8
|
+
*
|
|
9
|
+
* One project can have at most one in-flight track run; starting a
|
|
10
|
+
* new one while another is running rejects with 'busy'.
|
|
11
|
+
*/
|
|
12
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
15
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
16
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
17
|
+
}
|
|
18
|
+
Object.defineProperty(o, k2, desc);
|
|
19
|
+
}) : (function(o, m, k, k2) {
|
|
20
|
+
if (k2 === undefined) k2 = k;
|
|
21
|
+
o[k2] = m[k];
|
|
22
|
+
}));
|
|
23
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
24
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
25
|
+
}) : function(o, v) {
|
|
26
|
+
o["default"] = v;
|
|
27
|
+
});
|
|
28
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
29
|
+
var ownKeys = function(o) {
|
|
30
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
31
|
+
var ar = [];
|
|
32
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
33
|
+
return ar;
|
|
34
|
+
};
|
|
35
|
+
return ownKeys(o);
|
|
36
|
+
};
|
|
37
|
+
return function (mod) {
|
|
38
|
+
if (mod && mod.__esModule) return mod;
|
|
39
|
+
var result = {};
|
|
40
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
41
|
+
__setModuleDefault(result, mod);
|
|
42
|
+
return result;
|
|
43
|
+
};
|
|
44
|
+
})();
|
|
45
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
+
exports.createTrackRegistry = createTrackRegistry;
|
|
47
|
+
const path = __importStar(require("path"));
|
|
48
|
+
const track_runner_1 = require("./track-runner");
|
|
49
|
+
const workflow_data_watcher_1 = require("./workflow-data-watcher");
|
|
50
|
+
const ask_user_bridge_1 = require("./ask-user-bridge");
|
|
51
|
+
function createTrackRegistry(deps) {
|
|
52
|
+
const projects = new Map();
|
|
53
|
+
function emit(projectId, kind, payload) {
|
|
54
|
+
deps.broadcast(projectId, { type: kind, ...payload });
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
async start(projectId, absTrackPath, trackFilename, args = []) {
|
|
58
|
+
// Synchronous in-flight gate — set BEFORE any await to close the
|
|
59
|
+
// race window between two concurrent start() calls.
|
|
60
|
+
const existing = projects.get(projectId);
|
|
61
|
+
if (existing && (existing.inFlight || existing.lastState?.status === 'running')) {
|
|
62
|
+
return { ok: false, reason: 'a track is already running for this project' };
|
|
63
|
+
}
|
|
64
|
+
const projectFolder = deps.getProjectFolder(projectId);
|
|
65
|
+
if (!projectFolder) {
|
|
66
|
+
return { ok: false, reason: 'project not found' };
|
|
67
|
+
}
|
|
68
|
+
const runId = `track-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
69
|
+
const workflowDataPath = path.join(projectFolder, '.ccweb', 'workflow_data.json');
|
|
70
|
+
const watcher = (0, workflow_data_watcher_1.createWorkflowDataWatcher)(workflowDataPath);
|
|
71
|
+
const bridge = (0, ask_user_bridge_1.createAskUserBridge)((event) => {
|
|
72
|
+
emit(projectId, 'track_ask_user', event);
|
|
73
|
+
});
|
|
74
|
+
const runner = (0, track_runner_1.createTrackRunner)({
|
|
75
|
+
projectId,
|
|
76
|
+
injector: (text) => deps.injectIntoPty(projectId, text),
|
|
77
|
+
watcher,
|
|
78
|
+
logger: deps.logger,
|
|
79
|
+
askUserBridge: bridge,
|
|
80
|
+
onState: (state) => {
|
|
81
|
+
// Ignore late callbacks from a previous run — only the run
|
|
82
|
+
// whose runId matches the entry's current runId is allowed
|
|
83
|
+
// to overwrite lastState. (Defense against runner finishing
|
|
84
|
+
// after the entry has been replaced.)
|
|
85
|
+
const e = projects.get(projectId);
|
|
86
|
+
if (!e || e.runId !== runId)
|
|
87
|
+
return;
|
|
88
|
+
e.lastState = state;
|
|
89
|
+
emit(projectId, 'track_status_change', {
|
|
90
|
+
state: state,
|
|
91
|
+
});
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
const entry = {
|
|
95
|
+
runner,
|
|
96
|
+
bridge,
|
|
97
|
+
lastState: null,
|
|
98
|
+
trackFilename,
|
|
99
|
+
inFlight: true,
|
|
100
|
+
runId,
|
|
101
|
+
};
|
|
102
|
+
projects.set(projectId, entry);
|
|
103
|
+
// Fire and forget — the run resolves later; route returns immediately.
|
|
104
|
+
void runner.run(absTrackPath, args).then((result) => {
|
|
105
|
+
const e = projects.get(projectId);
|
|
106
|
+
if (e && e.runId === runId) {
|
|
107
|
+
e.inFlight = false;
|
|
108
|
+
}
|
|
109
|
+
deps.logger?.info?.('[TrackRegistry] run finished', {
|
|
110
|
+
projectId,
|
|
111
|
+
runId,
|
|
112
|
+
ok: result.ok,
|
|
113
|
+
error: result.error,
|
|
114
|
+
});
|
|
115
|
+
emit(projectId, 'track_run_complete', {
|
|
116
|
+
ok: result.ok,
|
|
117
|
+
value: result.value,
|
|
118
|
+
error: result.error,
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
return { ok: true, runId };
|
|
122
|
+
},
|
|
123
|
+
abort(projectId) {
|
|
124
|
+
const entry = projects.get(projectId);
|
|
125
|
+
if (!entry)
|
|
126
|
+
return false;
|
|
127
|
+
entry.runner.cancel();
|
|
128
|
+
entry.bridge.cancelAllForRun(entry.runId, 'aborted');
|
|
129
|
+
return true;
|
|
130
|
+
},
|
|
131
|
+
submitInput(projectId, requestId, data) {
|
|
132
|
+
const entry = projects.get(projectId);
|
|
133
|
+
if (!entry)
|
|
134
|
+
return { ok: false, message: 'no track running for project' };
|
|
135
|
+
// Pass values straight through — bridge.submitInput does per-field
|
|
136
|
+
// type validation (text/number/bool/enum).
|
|
137
|
+
return entry.bridge.submitInput(entry.runId, requestId, data);
|
|
138
|
+
},
|
|
139
|
+
getState(projectId) {
|
|
140
|
+
return projects.get(projectId)?.lastState ?? null;
|
|
141
|
+
},
|
|
142
|
+
isRunning(projectId) {
|
|
143
|
+
const entry = projects.get(projectId);
|
|
144
|
+
if (!entry)
|
|
145
|
+
return false;
|
|
146
|
+
// Window 1: inFlight true during start() pre-state phase.
|
|
147
|
+
// Window 2: lastState.status running/paused after first onState fires.
|
|
148
|
+
if (entry.inFlight)
|
|
149
|
+
return true;
|
|
150
|
+
const running = ['running', 'paused'];
|
|
151
|
+
return entry.lastState ? running.includes(entry.lastState.status) : false;
|
|
152
|
+
},
|
|
153
|
+
getPendingAskUser(projectId) {
|
|
154
|
+
const entry = projects.get(projectId);
|
|
155
|
+
if (!entry)
|
|
156
|
+
return null;
|
|
157
|
+
return entry.bridge.getPending(entry.runId);
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/tracks/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Track storage — read/write .tr files under <project>/.ccweb/tracks/.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors backend/src/flows/store.ts but for .tr source files instead
|
|
5
|
+
* of FlowDef JSON. Each track is a plain UTF-8 text file (train-lang
|
|
6
|
+
* source). No schema validation here — parse errors surface from
|
|
7
|
+
* train-lang when the track is run.
|
|
8
|
+
*/
|
|
9
|
+
export interface TrackFileInfo {
|
|
10
|
+
filename: string;
|
|
11
|
+
size: number;
|
|
12
|
+
mtime: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* sanitize a user-provided filename: forbid path separators, ensure
|
|
16
|
+
* .tr extension. Returns null if input is unsafe.
|
|
17
|
+
*/
|
|
18
|
+
export declare function sanitizeTrackFilename(input: unknown): string | null;
|
|
19
|
+
export declare function listTracks(projectFolder: string): TrackFileInfo[];
|
|
20
|
+
/**
|
|
21
|
+
* Read a track. Refuses to follow symlinks — if the on-disk entry is a
|
|
22
|
+
* symlink, returns null. This prevents an attacker with write access to
|
|
23
|
+
* `.ccweb/tracks/` from planting `attack.tr -> /etc/passwd` and reading
|
|
24
|
+
* arbitrary files via the GET endpoint. Symmetric guard in saveTrack
|
|
25
|
+
* (rejects writing to a path whose existing target is a symlink).
|
|
26
|
+
*/
|
|
27
|
+
export declare function loadTrack(projectFolder: string, filename: string): string | null;
|
|
28
|
+
export declare function saveTrack(projectFolder: string, filename: string, source: string): boolean;
|
|
29
|
+
export declare function deleteTrack(projectFolder: string, filename: string): boolean;
|
|
30
|
+
/** Absolute path used by TrackRunner when starting a run. */
|
|
31
|
+
export declare function resolveTrackPath(projectFolder: string, filename: string): string;
|
|
32
|
+
export declare function listGlobalTracks(username: string): TrackFileInfo[];
|
|
33
|
+
export declare function loadGlobalTrack(username: string, filename: string): string | null;
|
|
34
|
+
export declare function saveGlobalTrack(username: string, filename: string, source: string): boolean;
|
|
35
|
+
export declare function deleteGlobalTrack(username: string, filename: string): boolean;
|
|
36
|
+
export declare function resolveGlobalTrackPath(username: string, filename: string): string;
|
|
37
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/tracks/store.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AASH,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;CACd;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAYnE;AAUD,wBAAgB,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,aAAa,EAAE,CAgBjE;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CACvB,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,GACf,MAAM,GAAG,IAAI,CAaf;AAED,wBAAgB,SAAS,CACvB,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,OAAO,CAqBT;AAED,wBAAgB,WAAW,CAAC,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAS5E;AAED,6DAA6D;AAC7D,wBAAgB,gBAAgB,CAC9B,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,GACf,MAAM,CAER;AAYD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,EAAE,CAgBlE;AAED,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,MAAM,GAAG,IAAI,CAaf;AAED,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,OAAO,CAkBT;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAS7E;AAED,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,MAAM,CAER"}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Track storage — read/write .tr files under <project>/.ccweb/tracks/.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors backend/src/flows/store.ts but for .tr source files instead
|
|
6
|
+
* of FlowDef JSON. Each track is a plain UTF-8 text file (train-lang
|
|
7
|
+
* source). No schema validation here — parse errors surface from
|
|
8
|
+
* train-lang when the track is run.
|
|
9
|
+
*/
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
22
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
23
|
+
}) : function(o, v) {
|
|
24
|
+
o["default"] = v;
|
|
25
|
+
});
|
|
26
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
27
|
+
var ownKeys = function(o) {
|
|
28
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
29
|
+
var ar = [];
|
|
30
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
31
|
+
return ar;
|
|
32
|
+
};
|
|
33
|
+
return ownKeys(o);
|
|
34
|
+
};
|
|
35
|
+
return function (mod) {
|
|
36
|
+
if (mod && mod.__esModule) return mod;
|
|
37
|
+
var result = {};
|
|
38
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
39
|
+
__setModuleDefault(result, mod);
|
|
40
|
+
return result;
|
|
41
|
+
};
|
|
42
|
+
})();
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.sanitizeTrackFilename = sanitizeTrackFilename;
|
|
45
|
+
exports.listTracks = listTracks;
|
|
46
|
+
exports.loadTrack = loadTrack;
|
|
47
|
+
exports.saveTrack = saveTrack;
|
|
48
|
+
exports.deleteTrack = deleteTrack;
|
|
49
|
+
exports.resolveTrackPath = resolveTrackPath;
|
|
50
|
+
exports.listGlobalTracks = listGlobalTracks;
|
|
51
|
+
exports.loadGlobalTrack = loadGlobalTrack;
|
|
52
|
+
exports.saveGlobalTrack = saveGlobalTrack;
|
|
53
|
+
exports.deleteGlobalTrack = deleteGlobalTrack;
|
|
54
|
+
exports.resolveGlobalTrackPath = resolveGlobalTrackPath;
|
|
55
|
+
const fs = __importStar(require("fs"));
|
|
56
|
+
const path = __importStar(require("path"));
|
|
57
|
+
const os = __importStar(require("os"));
|
|
58
|
+
const TRACK_EXT = '.tr';
|
|
59
|
+
const TRACKS_DIRNAME = 'tracks';
|
|
60
|
+
/**
|
|
61
|
+
* sanitize a user-provided filename: forbid path separators, ensure
|
|
62
|
+
* .tr extension. Returns null if input is unsafe.
|
|
63
|
+
*/
|
|
64
|
+
function sanitizeTrackFilename(input) {
|
|
65
|
+
if (typeof input !== 'string')
|
|
66
|
+
return null;
|
|
67
|
+
const trimmed = input.trim();
|
|
68
|
+
if (!trimmed)
|
|
69
|
+
return null;
|
|
70
|
+
// No path separators or relative parents
|
|
71
|
+
if (/[\\/]/.test(trimmed) || trimmed.includes('..'))
|
|
72
|
+
return null;
|
|
73
|
+
// No control bytes
|
|
74
|
+
if (/[\x00-\x1f]/.test(trimmed))
|
|
75
|
+
return null;
|
|
76
|
+
// Ensure .tr extension
|
|
77
|
+
const withExt = trimmed.endsWith(TRACK_EXT) ? trimmed : trimmed + TRACK_EXT;
|
|
78
|
+
if (withExt.length > 200)
|
|
79
|
+
return null;
|
|
80
|
+
return withExt;
|
|
81
|
+
}
|
|
82
|
+
function tracksDir(projectFolder) {
|
|
83
|
+
return path.join(projectFolder, '.ccweb', TRACKS_DIRNAME);
|
|
84
|
+
}
|
|
85
|
+
function trackPath(projectFolder, filename) {
|
|
86
|
+
return path.join(tracksDir(projectFolder), filename);
|
|
87
|
+
}
|
|
88
|
+
function listTracks(projectFolder) {
|
|
89
|
+
const dir = tracksDir(projectFolder);
|
|
90
|
+
if (!fs.existsSync(dir))
|
|
91
|
+
return [];
|
|
92
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
93
|
+
const out = [];
|
|
94
|
+
for (const e of entries) {
|
|
95
|
+
if (!e.isFile() || !e.name.endsWith(TRACK_EXT))
|
|
96
|
+
continue;
|
|
97
|
+
const full = path.join(dir, e.name);
|
|
98
|
+
try {
|
|
99
|
+
const st = fs.statSync(full);
|
|
100
|
+
out.push({ filename: e.name, size: st.size, mtime: st.mtimeMs });
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// skip unreadable
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return out.sort((a, b) => a.filename.localeCompare(b.filename));
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Read a track. Refuses to follow symlinks — if the on-disk entry is a
|
|
110
|
+
* symlink, returns null. This prevents an attacker with write access to
|
|
111
|
+
* `.ccweb/tracks/` from planting `attack.tr -> /etc/passwd` and reading
|
|
112
|
+
* arbitrary files via the GET endpoint. Symmetric guard in saveTrack
|
|
113
|
+
* (rejects writing to a path whose existing target is a symlink).
|
|
114
|
+
*/
|
|
115
|
+
function loadTrack(projectFolder, filename) {
|
|
116
|
+
const p = trackPath(projectFolder, filename);
|
|
117
|
+
try {
|
|
118
|
+
const st = fs.lstatSync(p);
|
|
119
|
+
if (!st.isFile())
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
try {
|
|
126
|
+
return fs.readFileSync(p, 'utf8');
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function saveTrack(projectFolder, filename, source) {
|
|
133
|
+
const dir = tracksDir(projectFolder);
|
|
134
|
+
try {
|
|
135
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
136
|
+
const p = trackPath(projectFolder, filename);
|
|
137
|
+
// Reject if the target already exists and is a symlink — same
|
|
138
|
+
// guard as loadTrack. Without this, an attacker who can write the
|
|
139
|
+
// symlink could redirect saves to arbitrary FS locations.
|
|
140
|
+
try {
|
|
141
|
+
const st = fs.lstatSync(p);
|
|
142
|
+
if (st.isSymbolicLink())
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
// ENOENT — fine, we'll create a new file
|
|
147
|
+
}
|
|
148
|
+
const tmp = p + '.tmp-' + process.pid;
|
|
149
|
+
fs.writeFileSync(tmp, source, 'utf8');
|
|
150
|
+
fs.renameSync(tmp, p);
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function deleteTrack(projectFolder, filename) {
|
|
158
|
+
const p = trackPath(projectFolder, filename);
|
|
159
|
+
if (!fs.existsSync(p))
|
|
160
|
+
return false;
|
|
161
|
+
try {
|
|
162
|
+
fs.unlinkSync(p);
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/** Absolute path used by TrackRunner when starting a run. */
|
|
170
|
+
function resolveTrackPath(projectFolder, filename) {
|
|
171
|
+
return trackPath(projectFolder, filename);
|
|
172
|
+
}
|
|
173
|
+
// ── Global tracks (per-user templates) ──────────────────────────────────
|
|
174
|
+
function globalTracksDir(username) {
|
|
175
|
+
return path.join(os.homedir(), '.ccweb', 'users', username, TRACKS_DIRNAME);
|
|
176
|
+
}
|
|
177
|
+
function globalTrackPath(username, filename) {
|
|
178
|
+
return path.join(globalTracksDir(username), filename);
|
|
179
|
+
}
|
|
180
|
+
function listGlobalTracks(username) {
|
|
181
|
+
const dir = globalTracksDir(username);
|
|
182
|
+
if (!fs.existsSync(dir))
|
|
183
|
+
return [];
|
|
184
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
185
|
+
const out = [];
|
|
186
|
+
for (const e of entries) {
|
|
187
|
+
if (!e.isFile() || !e.name.endsWith(TRACK_EXT))
|
|
188
|
+
continue;
|
|
189
|
+
const full = path.join(dir, e.name);
|
|
190
|
+
try {
|
|
191
|
+
const st = fs.statSync(full);
|
|
192
|
+
out.push({ filename: e.name, size: st.size, mtime: st.mtimeMs });
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
// skip
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return out.sort((a, b) => a.filename.localeCompare(b.filename));
|
|
199
|
+
}
|
|
200
|
+
function loadGlobalTrack(username, filename) {
|
|
201
|
+
const p = globalTrackPath(username, filename);
|
|
202
|
+
try {
|
|
203
|
+
const st = fs.lstatSync(p);
|
|
204
|
+
if (!st.isFile())
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
try {
|
|
211
|
+
return fs.readFileSync(p, 'utf8');
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
function saveGlobalTrack(username, filename, source) {
|
|
218
|
+
const dir = globalTracksDir(username);
|
|
219
|
+
try {
|
|
220
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
221
|
+
const p = globalTrackPath(username, filename);
|
|
222
|
+
try {
|
|
223
|
+
const st = fs.lstatSync(p);
|
|
224
|
+
if (st.isSymbolicLink())
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
// ENOENT — fine
|
|
229
|
+
}
|
|
230
|
+
const tmp = p + '.tmp-' + process.pid;
|
|
231
|
+
fs.writeFileSync(tmp, source, 'utf8');
|
|
232
|
+
fs.renameSync(tmp, p);
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
catch {
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
function deleteGlobalTrack(username, filename) {
|
|
240
|
+
const p = globalTrackPath(username, filename);
|
|
241
|
+
if (!fs.existsSync(p))
|
|
242
|
+
return false;
|
|
243
|
+
try {
|
|
244
|
+
fs.unlinkSync(p);
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
catch {
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function resolveGlobalTrackPath(username, filename) {
|
|
252
|
+
return globalTrackPath(username, filename);
|
|
253
|
+
}
|
|
254
|
+
//# sourceMappingURL=store.js.map
|