@te-river/opencode-team-mode 1.5.4 → 1.5.6
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 +732 -634
- package/README.zh-CN.md +655 -576
- package/dist/agents.d.ts +6 -1
- package/dist/agents.d.ts.map +1 -1
- package/dist/agents.js +103 -522
- package/dist/agents.js.map +1 -1
- package/dist/approval-gate.d.ts +16 -0
- package/dist/approval-gate.d.ts.map +1 -1
- package/dist/approval-gate.js +8 -1
- package/dist/approval-gate.js.map +1 -1
- package/dist/blackboard.d.ts.map +1 -1
- package/dist/blackboard.js +3 -2
- package/dist/blackboard.js.map +1 -1
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +7 -6
- package/dist/commands.js.map +1 -1
- package/dist/envprotect/bash-classify.d.ts +42 -0
- package/dist/envprotect/bash-classify.d.ts.map +1 -0
- package/dist/envprotect/bash-classify.js +221 -0
- package/dist/envprotect/bash-classify.js.map +1 -0
- package/dist/envprotect/gate-predicates.d.ts +57 -0
- package/dist/envprotect/gate-predicates.d.ts.map +1 -0
- package/dist/envprotect/gate-predicates.js +174 -0
- package/dist/envprotect/gate-predicates.js.map +1 -0
- package/dist/envprotect/hook.d.ts +45 -0
- package/dist/envprotect/hook.d.ts.map +1 -0
- package/dist/envprotect/hook.js +158 -0
- package/dist/envprotect/hook.js.map +1 -0
- package/dist/envprotect/path-classify.d.ts +16 -0
- package/dist/envprotect/path-classify.d.ts.map +1 -0
- package/dist/envprotect/path-classify.js +72 -0
- package/dist/envprotect/path-classify.js.map +1 -0
- package/dist/envprotect/patterns.d.ts +77 -0
- package/dist/envprotect/patterns.d.ts.map +1 -0
- package/dist/envprotect/patterns.js +182 -0
- package/dist/envprotect/patterns.js.map +1 -0
- package/dist/envprotect.d.ts +19 -217
- package/dist/envprotect.d.ts.map +1 -1
- package/dist/envprotect.js +18 -803
- package/dist/envprotect.js.map +1 -1
- package/dist/fs-safe.d.ts +16 -0
- package/dist/fs-safe.d.ts.map +1 -0
- package/dist/fs-safe.js +56 -0
- package/dist/fs-safe.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -6
- package/dist/index.js.map +1 -1
- package/dist/prompts/lead.d.ts +7 -0
- package/dist/prompts/lead.d.ts.map +1 -0
- package/dist/prompts/lead.js +230 -0
- package/dist/prompts/lead.js.map +1 -0
- package/dist/prompts/shared.d.ts +8 -0
- package/dist/prompts/shared.d.ts.map +1 -0
- package/dist/prompts/shared.js +118 -0
- package/dist/prompts/shared.js.map +1 -0
- package/dist/prompts/specialists.d.ts +12 -0
- package/dist/prompts/specialists.d.ts.map +1 -0
- package/dist/prompts/specialists.js +218 -0
- package/dist/prompts/specialists.js.map +1 -0
- package/dist/shell-text.d.ts +14 -0
- package/dist/shell-text.d.ts.map +1 -0
- package/dist/shell-text.js +16 -0
- package/dist/shell-text.js.map +1 -0
- package/dist/tm/args-schema.d.ts +36 -0
- package/dist/tm/args-schema.d.ts.map +1 -0
- package/dist/tm/args-schema.js +191 -0
- package/dist/tm/args-schema.js.map +1 -0
- package/dist/tm/browser.d.ts +52 -0
- package/dist/tm/browser.d.ts.map +1 -0
- package/dist/tm/browser.js +361 -0
- package/dist/tm/browser.js.map +1 -0
- package/dist/tm/client-unwrap.d.ts +38 -0
- package/dist/tm/client-unwrap.d.ts.map +1 -0
- package/dist/tm/client-unwrap.js +113 -0
- package/dist/tm/client-unwrap.js.map +1 -0
- package/dist/tm/config.d.ts +46 -18
- package/dist/tm/config.d.ts.map +1 -1
- package/dist/tm/config.js +60 -17
- package/dist/tm/config.js.map +1 -1
- package/dist/tm/guard.d.ts.map +1 -1
- package/dist/tm/guard.js +4 -7
- package/dist/tm/guard.js.map +1 -1
- package/dist/tm/index.d.ts +15 -5
- package/dist/tm/index.d.ts.map +1 -1
- package/dist/tm/index.js +95 -19
- package/dist/tm/index.js.map +1 -1
- package/dist/tm/memory.d.ts +82 -0
- package/dist/tm/memory.d.ts.map +1 -0
- package/dist/tm/memory.js +350 -0
- package/dist/tm/memory.js.map +1 -0
- package/dist/tm/pipelines.d.ts +58 -0
- package/dist/tm/pipelines.d.ts.map +1 -0
- package/dist/tm/pipelines.js +301 -0
- package/dist/tm/pipelines.js.map +1 -0
- package/dist/tm/preview.d.ts +6 -1
- package/dist/tm/preview.d.ts.map +1 -1
- package/dist/tm/preview.js +31 -8
- package/dist/tm/preview.js.map +1 -1
- package/dist/tm/ptc/budgets.d.ts +38 -0
- package/dist/tm/ptc/budgets.d.ts.map +1 -0
- package/dist/tm/ptc/budgets.js +59 -0
- package/dist/tm/ptc/budgets.js.map +1 -0
- package/dist/tm/ptc/contract.d.ts +131 -0
- package/dist/tm/ptc/contract.d.ts.map +1 -0
- package/dist/tm/ptc/contract.js +47 -0
- package/dist/tm/ptc/contract.js.map +1 -0
- package/dist/tm/ptc/driver.d.ts +37 -0
- package/dist/tm/ptc/driver.d.ts.map +1 -0
- package/dist/tm/ptc/driver.js +181 -0
- package/dist/tm/ptc/driver.js.map +1 -0
- package/dist/tm/ptc/engines.d.ts +32 -0
- package/dist/tm/ptc/engines.d.ts.map +1 -0
- package/dist/tm/ptc/engines.js +201 -0
- package/dist/tm/ptc/engines.js.map +1 -0
- package/dist/tm/ptc/gate.d.ts +28 -0
- package/dist/tm/ptc/gate.d.ts.map +1 -0
- package/dist/tm/ptc/gate.js +127 -0
- package/dist/tm/ptc/gate.js.map +1 -0
- package/dist/tm/ptc/index.d.ts +19 -0
- package/dist/tm/ptc/index.d.ts.map +1 -0
- package/dist/tm/ptc/index.js +15 -0
- package/dist/tm/ptc/index.js.map +1 -0
- package/dist/tm/ptc/pscan.d.ts +11 -0
- package/dist/tm/ptc/pscan.d.ts.map +1 -0
- package/dist/tm/ptc/pscan.js +27 -0
- package/dist/tm/ptc/pscan.js.map +1 -0
- package/dist/tm/ptc/summary.d.ts +17 -0
- package/dist/tm/ptc/summary.d.ts.map +1 -0
- package/dist/tm/ptc/summary.js +107 -0
- package/dist/tm/ptc/summary.js.map +1 -0
- package/dist/tm/ptc/tool.d.ts +35 -0
- package/dist/tm/ptc/tool.d.ts.map +1 -0
- package/dist/tm/ptc/tool.js +135 -0
- package/dist/tm/ptc/tool.js.map +1 -0
- package/dist/tm/ptc.d.ts +45 -26
- package/dist/tm/ptc.d.ts.map +1 -1
- package/dist/tm/ptc.js +71 -45
- package/dist/tm/ptc.js.map +1 -1
- package/dist/tm/result.d.ts +34 -0
- package/dist/tm/result.d.ts.map +1 -0
- package/dist/tm/result.js +87 -0
- package/dist/tm/result.js.map +1 -0
- package/dist/tm/shell-bridge.d.ts +22 -0
- package/dist/tm/shell-bridge.d.ts.map +1 -0
- package/dist/tm/shell-bridge.js +70 -0
- package/dist/tm/shell-bridge.js.map +1 -0
- package/dist/tm/store.d.ts.map +1 -1
- package/dist/tm/store.js +2 -1
- package/dist/tm/store.js.map +1 -1
- package/dist/tm/tools.d.ts +13 -71
- package/dist/tm/tools.d.ts.map +1 -1
- package/dist/tm/tools.js +23 -656
- package/dist/tm/tools.js.map +1 -1
- package/dist/tm/webfetch.d.ts +94 -0
- package/dist/tm/webfetch.d.ts.map +1 -0
- package/dist/tm/webfetch.js +225 -0
- package/dist/tm/webfetch.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tm_ptc_run — public contract types + the frozen engine seam.
|
|
3
|
+
*
|
|
4
|
+
* Design: .git/opencode-team/.../ptc-run/02-architect-ptc-run-design.md §2/§3.
|
|
5
|
+
* Everything in this module is CONTRACT — frozen since M1 so M2's engines and
|
|
6
|
+
* M3's registration could land without touching the driver or the tool.
|
|
7
|
+
* (Split out of the former monolithic ptc.ts; behavior unchanged.)
|
|
8
|
+
*
|
|
9
|
+
* Governance is REUSED, never forked (D6 lock): the bridge calls the exact
|
|
10
|
+
* four exported pipelines, so threshold offload, P2/P3, R6 and handle/TTL
|
|
11
|
+
* semantics apply to every bridged call verbatim. PTC is NOT a bypass layer.
|
|
12
|
+
*/
|
|
13
|
+
import type { TmPhase } from "../result.js";
|
|
14
|
+
/** The five PTC run statuses (design §2). */
|
|
15
|
+
export declare const PTC_STATUS_VALUES: readonly ["ok", "stopped-error-budget", "stopped-call-budget", "timeout", "engine-error"];
|
|
16
|
+
export type PtcStatus = (typeof PTC_STATUS_VALUES)[number];
|
|
17
|
+
export type BridgeTool = "tm_read" | "tm_grep" | "tm_bash" | "tm_fetch";
|
|
18
|
+
/** Bridge allow set — read-only; tm_ptc_run itself is excluded (no nesting). */
|
|
19
|
+
export declare const BRIDGE_ALLOW: readonly BridgeTool[];
|
|
20
|
+
/** Phases safe to retry once (idempotent read-only bridges; design §4.2). */
|
|
21
|
+
export declare const RETRYABLE_PHASES: readonly TmPhase[];
|
|
22
|
+
/** Error body the bridge surfaces (T1.4 shape: tool/phase/message/line?). */
|
|
23
|
+
export interface PtcErrorBody {
|
|
24
|
+
tool: string;
|
|
25
|
+
phase: TmPhase;
|
|
26
|
+
message: string;
|
|
27
|
+
line?: number;
|
|
28
|
+
}
|
|
29
|
+
/** A single bridged-call outcome (design §2 program protocol). */
|
|
30
|
+
export type PtcCallResult = {
|
|
31
|
+
ok: true;
|
|
32
|
+
data: unknown;
|
|
33
|
+
} | {
|
|
34
|
+
ok: false;
|
|
35
|
+
error: PtcErrorBody;
|
|
36
|
+
};
|
|
37
|
+
/** The bridge the engine drives — every call runs the gate-wrapped pipelines. */
|
|
38
|
+
export interface PtcBridge {
|
|
39
|
+
call(tool: BridgeTool, args: Record<string, unknown>): Promise<PtcCallResult>;
|
|
40
|
+
}
|
|
41
|
+
/** Parent → engine: run the program. */
|
|
42
|
+
export interface PtcRunRequest {
|
|
43
|
+
program: string;
|
|
44
|
+
/** monotonic token so a caller can correlate a call with its response. */
|
|
45
|
+
startDeadlineMs: number;
|
|
46
|
+
}
|
|
47
|
+
/** Engine → driver: a single bridged call to execute under the gate. */
|
|
48
|
+
export interface PtcRpcRequest {
|
|
49
|
+
t: "call";
|
|
50
|
+
id: number;
|
|
51
|
+
tool: BridgeTool;
|
|
52
|
+
args: Record<string, unknown>;
|
|
53
|
+
}
|
|
54
|
+
/** Driver → engine: the gated result of a call. */
|
|
55
|
+
export interface PtcRpcResponse {
|
|
56
|
+
t: "result";
|
|
57
|
+
id: number;
|
|
58
|
+
r: PtcCallResult;
|
|
59
|
+
}
|
|
60
|
+
/** Driver → engine: stop the run (budget / time hit); engine must unwind. */
|
|
61
|
+
export interface PtcRpcAbort {
|
|
62
|
+
t: "abort";
|
|
63
|
+
id: number;
|
|
64
|
+
reason: "timeout" | "error-budget" | "call-budget";
|
|
65
|
+
}
|
|
66
|
+
export type PtcEngineMessage = PtcRpcRequest | PtcRpcResponse | PtcRpcAbort;
|
|
67
|
+
export type PtcEngineName = "worker" | "inline";
|
|
68
|
+
/**
|
|
69
|
+
* The engine seam — FROZEN. InlineSequentialEngine shipped in M1,
|
|
70
|
+
* WorkerEngine + InlineVmEngine in M2; a future engine implements this same
|
|
71
|
+
* shape and neither the driver nor the tool changes.
|
|
72
|
+
*/
|
|
73
|
+
export interface PtcEngine {
|
|
74
|
+
readonly name: PtcEngineName;
|
|
75
|
+
/**
|
|
76
|
+
* Run `program`, driving every bridge call through `bridge` (already
|
|
77
|
+
* gate-wrapped by the driver). Resolve with the program's return value;
|
|
78
|
+
* reject with a `PtcStopSignal` for a budget/time stop, or any other Error
|
|
79
|
+
* for an engine/program fault. `signal` lets the driver race a timeout.
|
|
80
|
+
*/
|
|
81
|
+
run(program: string, bridge: PtcBridge, signal: AbortSignal): Promise<unknown>;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* The stop signal unwinding a program on a budget/time hit. Thrown by the
|
|
85
|
+
* StepGate (call/error budget, pre-call deadline) and rejected through the
|
|
86
|
+
* engines' abort promises (wall-clock timeout); caught by the driver, which
|
|
87
|
+
* maps it to a status. Never escapes as an engine-error.
|
|
88
|
+
*/
|
|
89
|
+
export declare class PtcStopSignal extends Error {
|
|
90
|
+
readonly reason: "timeout" | "error-budget" | "call-budget";
|
|
91
|
+
constructor(reason: "timeout" | "error-budget" | "call-budget");
|
|
92
|
+
}
|
|
93
|
+
/** Short display code for a ref: the `steps/<id>` step segment. Shared by
|
|
94
|
+
* the gate (success table) and the summary renderer (error refs). */
|
|
95
|
+
export declare function shortRefCode(ref: string): string;
|
|
96
|
+
export interface PtcStepRecord {
|
|
97
|
+
n: number;
|
|
98
|
+
tool: BridgeTool;
|
|
99
|
+
ok: boolean;
|
|
100
|
+
ms: number;
|
|
101
|
+
/** ok rows: estimated tokens (inline text) or the offload handle's tokens. */
|
|
102
|
+
tokens: number;
|
|
103
|
+
/** ok rows: "inline" or a short ref code for an offloaded payload. */
|
|
104
|
+
dest: string;
|
|
105
|
+
/** ok rows: the offload ref (when the data was a handle), else null. */
|
|
106
|
+
ref?: string | null;
|
|
107
|
+
/** err rows only. */
|
|
108
|
+
phase?: TmPhase;
|
|
109
|
+
line?: number;
|
|
110
|
+
retry?: boolean;
|
|
111
|
+
message?: string;
|
|
112
|
+
errorRef?: string;
|
|
113
|
+
}
|
|
114
|
+
export interface PtcRunOutcome {
|
|
115
|
+
label: string;
|
|
116
|
+
status: PtcStatus;
|
|
117
|
+
steps: PtcStepRecord[];
|
|
118
|
+
okCount: number;
|
|
119
|
+
errCount: number;
|
|
120
|
+
retries: number;
|
|
121
|
+
calls: number;
|
|
122
|
+
ms: number;
|
|
123
|
+
engine: PtcEngineName;
|
|
124
|
+
degraded: boolean;
|
|
125
|
+
returnValue: unknown;
|
|
126
|
+
returned: boolean;
|
|
127
|
+
/** set when the program threw (status=engine-error). */
|
|
128
|
+
engineError?: PtcErrorBody;
|
|
129
|
+
parentStepId: string;
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../../src/tm/ptc/contract.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tm_ptc_run — public contract types + the frozen engine seam.
|
|
3
|
+
*
|
|
4
|
+
* Design: .git/opencode-team/.../ptc-run/02-architect-ptc-run-design.md §2/§3.
|
|
5
|
+
* Everything in this module is CONTRACT — frozen since M1 so M2's engines and
|
|
6
|
+
* M3's registration could land without touching the driver or the tool.
|
|
7
|
+
* (Split out of the former monolithic ptc.ts; behavior unchanged.)
|
|
8
|
+
*
|
|
9
|
+
* Governance is REUSED, never forked (D6 lock): the bridge calls the exact
|
|
10
|
+
* four exported pipelines, so threshold offload, P2/P3, R6 and handle/TTL
|
|
11
|
+
* semantics apply to every bridged call verbatim. PTC is NOT a bypass layer.
|
|
12
|
+
*/
|
|
13
|
+
import { shorten } from "../config.js";
|
|
14
|
+
// ---------- statuses + bridge surface (design §2) ---------------------------
|
|
15
|
+
/** The five PTC run statuses (design §2). */
|
|
16
|
+
export const PTC_STATUS_VALUES = [
|
|
17
|
+
"ok",
|
|
18
|
+
"stopped-error-budget",
|
|
19
|
+
"stopped-call-budget",
|
|
20
|
+
"timeout",
|
|
21
|
+
"engine-error",
|
|
22
|
+
];
|
|
23
|
+
/** Bridge allow set — read-only; tm_ptc_run itself is excluded (no nesting). */
|
|
24
|
+
export const BRIDGE_ALLOW = ["tm_read", "tm_grep", "tm_bash", "tm_fetch"];
|
|
25
|
+
/** Phases safe to retry once (idempotent read-only bridges; design §4.2). */
|
|
26
|
+
export const RETRYABLE_PHASES = ["client", "execute", "store"];
|
|
27
|
+
/**
|
|
28
|
+
* The stop signal unwinding a program on a budget/time hit. Thrown by the
|
|
29
|
+
* StepGate (call/error budget, pre-call deadline) and rejected through the
|
|
30
|
+
* engines' abort promises (wall-clock timeout); caught by the driver, which
|
|
31
|
+
* maps it to a status. Never escapes as an engine-error.
|
|
32
|
+
*/
|
|
33
|
+
export class PtcStopSignal extends Error {
|
|
34
|
+
reason;
|
|
35
|
+
constructor(reason) {
|
|
36
|
+
super(`ptc-stop:${reason}`);
|
|
37
|
+
this.reason = reason;
|
|
38
|
+
this.name = "PtcStopSignal";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** Short display code for a ref: the `steps/<id>` step segment. Shared by
|
|
42
|
+
* the gate (success table) and the summary renderer (error refs). */
|
|
43
|
+
export function shortRefCode(ref) {
|
|
44
|
+
const m = /\/steps\/([^/]+)\/result/.exec(ref);
|
|
45
|
+
return m ? m[1] : shorten(ref, 24);
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../../../src/tm/ptc/contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,+EAA+E;AAE/E,6CAA6C;AAC7C,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,IAAI;IACJ,sBAAsB;IACtB,qBAAqB;IACrB,SAAS;IACT,cAAc;CACN,CAAA;AAKV,gFAAgF;AAChF,MAAM,CAAC,MAAM,YAAY,GAA0B,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,CAAC,CAAA;AAEhG,6EAA6E;AAC7E,MAAM,CAAC,MAAM,gBAAgB,GAAuB,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC,CAAA;AAuElF;;;;;GAKG;AACH,MAAM,OAAO,aAAc,SAAQ,KAAK;IACjB;IAArB,YAAqB,MAAkD;QACrE,KAAK,CAAC,YAAY,MAAM,EAAE,CAAC,CAAA;QADR,WAAM,GAAN,MAAM,CAA4C;QAErE,IAAI,CAAC,IAAI,GAAG,eAAe,CAAA;IAC7B,CAAC;CACF;AAED;sEACsE;AACtE,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,MAAM,CAAC,GAAG,0BAA0B,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC9C,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;AACpC,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tm_ptc_run — the run driver: engine selection (auto / worker / inline),
|
|
3
|
+
* the static pre-scan handoff, wall-clock timeout, status mapping, and the
|
|
4
|
+
* trajectory parent events. Split out of the former monolithic ptc.ts;
|
|
5
|
+
* behavior unchanged.
|
|
6
|
+
*/
|
|
7
|
+
import type { TmConfig } from "../config.js";
|
|
8
|
+
import type { RunStore } from "../store.js";
|
|
9
|
+
import type { PtcBridge, PtcEngine, PtcRunOutcome } from "./contract.js";
|
|
10
|
+
import type { PtcBudgets } from "./budgets.js";
|
|
11
|
+
export interface EngineSelection {
|
|
12
|
+
engine: PtcEngine;
|
|
13
|
+
/** true when the auto chain degraded from worker to inline. */
|
|
14
|
+
degraded: boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Select the PTC engine based on the TM_PTC_ENGINE mode.
|
|
18
|
+
* - "worker": WorkerEngine only (throws on failure → engine-error status).
|
|
19
|
+
* - "inline": InlineVmEngine only (script timeout for pre-await busy-loops).
|
|
20
|
+
* - "auto" (default): worker-first — the REAL auto-degrade happens in
|
|
21
|
+
* runPtc, which re-runs the whole program on InlineVmEngine when a worker
|
|
22
|
+
* run returns engine-error.
|
|
23
|
+
*/
|
|
24
|
+
export declare function selectEngine(mode: "auto" | "worker" | "inline", bridge: PtcBridge): EngineSelection;
|
|
25
|
+
export interface RunPtcOptions {
|
|
26
|
+
program: string;
|
|
27
|
+
label: string;
|
|
28
|
+
budgets: PtcBudgets;
|
|
29
|
+
parentStepId: string;
|
|
30
|
+
cfg: TmConfig;
|
|
31
|
+
store?: RunStore;
|
|
32
|
+
bridge: PtcBridge;
|
|
33
|
+
engine?: PtcEngine;
|
|
34
|
+
now?: () => number;
|
|
35
|
+
}
|
|
36
|
+
export declare function runPtc(o: RunPtcOptions): Promise<PtcRunOutcome>;
|
|
37
|
+
//# sourceMappingURL=driver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../../../src/tm/ptc/driver.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAa,MAAM,eAAe,CAAA;AAMnF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAI9C,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,SAAS,CAAA;IACjB,+DAA+D;IAC/D,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,EAAE,MAAM,EAAE,SAAS,GAAG,eAAe,CAQnG;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,UAAU,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,GAAG,EAAE,QAAQ,CAAA;IACb,KAAK,CAAC,EAAE,QAAQ,CAAA;IAChB,MAAM,EAAE,SAAS,CAAA;IACjB,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CACnB;AAED,wBAAsB,MAAM,CAAC,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAwIrE"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tm_ptc_run — the run driver: engine selection (auto / worker / inline),
|
|
3
|
+
* the static pre-scan handoff, wall-clock timeout, status mapping, and the
|
|
4
|
+
* trajectory parent events. Split out of the former monolithic ptc.ts;
|
|
5
|
+
* behavior unchanged.
|
|
6
|
+
*/
|
|
7
|
+
import * as crypto from "node:crypto";
|
|
8
|
+
import { PtcStopSignal } from "./contract.js";
|
|
9
|
+
import { createGateBridge } from "./gate.js";
|
|
10
|
+
import { InlineVmEngine, WorkerEngine } from "./engines.js";
|
|
11
|
+
import { staticPscan } from "./pscan.js";
|
|
12
|
+
/**
|
|
13
|
+
* Select the PTC engine based on the TM_PTC_ENGINE mode.
|
|
14
|
+
* - "worker": WorkerEngine only (throws on failure → engine-error status).
|
|
15
|
+
* - "inline": InlineVmEngine only (script timeout for pre-await busy-loops).
|
|
16
|
+
* - "auto" (default): worker-first — the REAL auto-degrade happens in
|
|
17
|
+
* runPtc, which re-runs the whole program on InlineVmEngine when a worker
|
|
18
|
+
* run returns engine-error.
|
|
19
|
+
*/
|
|
20
|
+
export function selectEngine(mode, bridge) {
|
|
21
|
+
void bridge;
|
|
22
|
+
if (mode === "inline") {
|
|
23
|
+
return { engine: new InlineVmEngine(), degraded: false };
|
|
24
|
+
}
|
|
25
|
+
// auto and worker both start on the worker engine (construction never
|
|
26
|
+
// throws — no spawn until run()).
|
|
27
|
+
return { engine: new WorkerEngine(), degraded: false };
|
|
28
|
+
}
|
|
29
|
+
export async function runPtc(o) {
|
|
30
|
+
const now = o.now ?? Date.now;
|
|
31
|
+
const start = now();
|
|
32
|
+
const deadlineAt = start + o.budgets.timeoutMs;
|
|
33
|
+
// engine selection — explicit override or auto/worker/inline from config.
|
|
34
|
+
let engine;
|
|
35
|
+
let degraded = false;
|
|
36
|
+
if (o.engine) {
|
|
37
|
+
engine = o.engine;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
const sel = selectEngine(o.cfg.ptcEngine, o.bridge);
|
|
41
|
+
engine = sel.engine;
|
|
42
|
+
degraded = sel.degraded;
|
|
43
|
+
}
|
|
44
|
+
// static pre-scan — reject programs with banned tokens before any
|
|
45
|
+
// engine runs. Shape: engine-error with the pscan tokens listed.
|
|
46
|
+
// (Design §3: "辅助手段,声明不作安全边界".)
|
|
47
|
+
const pscan = staticPscan(o.program);
|
|
48
|
+
if (pscan.rejected) {
|
|
49
|
+
return {
|
|
50
|
+
label: o.label,
|
|
51
|
+
status: "engine-error",
|
|
52
|
+
steps: [],
|
|
53
|
+
okCount: 0,
|
|
54
|
+
errCount: 0,
|
|
55
|
+
retries: 0,
|
|
56
|
+
calls: 0,
|
|
57
|
+
ms: 0,
|
|
58
|
+
engine: engine.name,
|
|
59
|
+
degraded,
|
|
60
|
+
returnValue: undefined,
|
|
61
|
+
returned: false,
|
|
62
|
+
engineError: {
|
|
63
|
+
tool: "tm_ptc_run",
|
|
64
|
+
phase: "args",
|
|
65
|
+
message: `程序包含禁止标识符(${pscan.tokens.join(", ")}),已拒绝执行。`,
|
|
66
|
+
},
|
|
67
|
+
parentStepId: o.parentStepId,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
// Auto-degrade: if the selected engine throws (not a PtcStopSignal),
|
|
71
|
+
// and we're in auto mode with no explicit override, retry with InlineVmEngine.
|
|
72
|
+
const tryRun = async (eng) => {
|
|
73
|
+
const state = { calls: 0, errors: 0, retries: 0, steps: [] };
|
|
74
|
+
const gate = createGateBridge(o.bridge, o.parentStepId, o.budgets, state, {
|
|
75
|
+
now,
|
|
76
|
+
deadlineAt,
|
|
77
|
+
store: o.store,
|
|
78
|
+
});
|
|
79
|
+
// parent call event (design §6)
|
|
80
|
+
o.store?.appendTrajectory({
|
|
81
|
+
tool: "tm_ptc_run",
|
|
82
|
+
step_id: o.parentStepId,
|
|
83
|
+
event: "call",
|
|
84
|
+
label: o.label,
|
|
85
|
+
program_sha256: crypto.createHash("sha256").update(o.program).digest("hex"),
|
|
86
|
+
budgets: o.budgets,
|
|
87
|
+
});
|
|
88
|
+
const ac = new AbortController();
|
|
89
|
+
const remaining = Math.max(0, deadlineAt - now());
|
|
90
|
+
const timer = setTimeout(() => ac.abort(), remaining);
|
|
91
|
+
let status;
|
|
92
|
+
let returnValue;
|
|
93
|
+
let returned = false;
|
|
94
|
+
let engineError;
|
|
95
|
+
try {
|
|
96
|
+
returnValue = await eng.run(o.program, gate, ac.signal);
|
|
97
|
+
returned = true;
|
|
98
|
+
status = state.stopReason ? mapStop(state.stopReason) : "ok";
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
if (err instanceof PtcStopSignal) {
|
|
102
|
+
status = mapStop(err.reason);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
status = "engine-error";
|
|
106
|
+
const line = extractLine(err);
|
|
107
|
+
engineError = {
|
|
108
|
+
tool: "tm_ptc_run",
|
|
109
|
+
phase: "execute",
|
|
110
|
+
message: err instanceof Error ? err.message : String(err ?? "engine error"),
|
|
111
|
+
...(line != null ? { line } : {}),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
clearTimeout(timer);
|
|
117
|
+
}
|
|
118
|
+
const ms = now() - start;
|
|
119
|
+
const outcome = {
|
|
120
|
+
label: o.label,
|
|
121
|
+
status,
|
|
122
|
+
steps: state.steps,
|
|
123
|
+
okCount: state.steps.filter((s) => s.ok).length,
|
|
124
|
+
errCount: state.steps.filter((s) => !s.ok).length,
|
|
125
|
+
retries: state.retries,
|
|
126
|
+
calls: state.calls,
|
|
127
|
+
ms,
|
|
128
|
+
engine: eng.name,
|
|
129
|
+
degraded,
|
|
130
|
+
returnValue,
|
|
131
|
+
returned,
|
|
132
|
+
...(engineError ? { engineError } : {}),
|
|
133
|
+
parentStepId: o.parentStepId,
|
|
134
|
+
};
|
|
135
|
+
o.store?.appendTrajectory({
|
|
136
|
+
tool: "tm_ptc_run",
|
|
137
|
+
step_id: o.parentStepId,
|
|
138
|
+
event: "finish",
|
|
139
|
+
status: outcome.status,
|
|
140
|
+
calls: outcome.calls,
|
|
141
|
+
errors: outcome.errCount,
|
|
142
|
+
retries: outcome.retries,
|
|
143
|
+
ms: outcome.ms,
|
|
144
|
+
});
|
|
145
|
+
return outcome;
|
|
146
|
+
};
|
|
147
|
+
// Auto mode: try worker first; on engine-error → degrade to inline.
|
|
148
|
+
if (!o.engine && o.cfg.ptcEngine === "auto" && engine.name === "worker") {
|
|
149
|
+
const result = await tryRun(engine);
|
|
150
|
+
if (result.status === "engine-error") {
|
|
151
|
+
// Degrade to inline-vm and re-run.
|
|
152
|
+
const inlineEngine = new InlineVmEngine();
|
|
153
|
+
const fallback = await tryRun(inlineEngine);
|
|
154
|
+
fallback.degraded = true;
|
|
155
|
+
fallback.engine = "inline";
|
|
156
|
+
return fallback;
|
|
157
|
+
}
|
|
158
|
+
return result;
|
|
159
|
+
}
|
|
160
|
+
return tryRun(engine);
|
|
161
|
+
}
|
|
162
|
+
function mapStop(reason) {
|
|
163
|
+
if (reason === "timeout")
|
|
164
|
+
return "timeout";
|
|
165
|
+
if (reason === "error-budget")
|
|
166
|
+
return "stopped-error-budget";
|
|
167
|
+
return "stopped-call-budget";
|
|
168
|
+
}
|
|
169
|
+
/** Best-effort line extraction from a program-side thrown error stack. */
|
|
170
|
+
function extractLine(err) {
|
|
171
|
+
const s = err instanceof Error ? err.stack ?? "" : String(err ?? "");
|
|
172
|
+
const m = /:(\d+):/.exec(s);
|
|
173
|
+
if (m) {
|
|
174
|
+
const n = Number(m[1]);
|
|
175
|
+
if (Number.isFinite(n))
|
|
176
|
+
return n;
|
|
177
|
+
}
|
|
178
|
+
const m2 = /line[:#]?\s*(\d+)/i.exec(s);
|
|
179
|
+
return m2 ? Number(m2[1]) : undefined;
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=driver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driver.js","sourceRoot":"","sources":["../../../src/tm/ptc/driver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tm_ptc_run — the three engines behind the frozen `PtcEngine` seam.
|
|
3
|
+
* Split out of the former monolithic ptc.ts; behavior unchanged.
|
|
4
|
+
*
|
|
5
|
+
* M1 legacy: InlineSequentialEngine (test-only — runs on the MAIN thread,
|
|
6
|
+
* no sandbox, no timeout; a post-await busy loop blocks the host event loop
|
|
7
|
+
* irrecoverably).
|
|
8
|
+
* M2 primary: WorkerEngine (worker_threads + MessagePort RPC, env:{},
|
|
9
|
+
* resourceLimits, hard `terminate()` wall-clock kill; bootstrap as a
|
|
10
|
+
* build-time string, strict-mode program body).
|
|
11
|
+
* M2 fallback: InlineVmEngine (node:vm runInNewContext — the script timeout
|
|
12
|
+
* kills PRE-await synchronous busy-loops; a POST-await busy loop blocks the
|
|
13
|
+
* host event loop irrecoverably, documented — prefer worker/auto).
|
|
14
|
+
*/
|
|
15
|
+
import type { PtcBridge, PtcEngine, PtcEngineName } from "./contract.js";
|
|
16
|
+
export declare class InlineSequentialEngine implements PtcEngine {
|
|
17
|
+
readonly name: PtcEngineName;
|
|
18
|
+
run(program: string, bridge: PtcBridge, signal: AbortSignal): Promise<unknown>;
|
|
19
|
+
}
|
|
20
|
+
export declare class WorkerEngine implements PtcEngine {
|
|
21
|
+
readonly name: PtcEngineName;
|
|
22
|
+
run(program: string, bridge: PtcBridge, signal: AbortSignal): Promise<unknown>;
|
|
23
|
+
}
|
|
24
|
+
export declare class InlineVmEngine implements PtcEngine {
|
|
25
|
+
readonly name: PtcEngineName;
|
|
26
|
+
/** Script execution timeout in ms (kills pre-await synchronous
|
|
27
|
+
* busy-loops). Injectable so tests can pin the kill fast. */
|
|
28
|
+
private readonly compileTimeoutMs;
|
|
29
|
+
constructor(compileTimeoutMs?: number);
|
|
30
|
+
run(program: string, bridge: PtcBridge, signal: AbortSignal): Promise<unknown>;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=engines.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engines.d.ts","sourceRoot":"","sources":["../../../src/tm/ptc/engines.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAiC,MAAM,eAAe,CAAA;AAYvG,qBAAa,sBAAuB,YAAW,SAAS;IACtD,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAW;IACjC,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;CAyBrF;AAID,qBAAa,YAAa,YAAW,SAAS;IAC5C,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAW;IAEjC,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;CA8GrF;AAID,qBAAa,cAAe,YAAW,SAAS;IAC9C,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAW;IACvC;mEAC+D;IAC/D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAQ;gBAC7B,gBAAgB,SAAS;IAI/B,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;CAuBrF"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tm_ptc_run — the three engines behind the frozen `PtcEngine` seam.
|
|
3
|
+
* Split out of the former monolithic ptc.ts; behavior unchanged.
|
|
4
|
+
*
|
|
5
|
+
* M1 legacy: InlineSequentialEngine (test-only — runs on the MAIN thread,
|
|
6
|
+
* no sandbox, no timeout; a post-await busy loop blocks the host event loop
|
|
7
|
+
* irrecoverably).
|
|
8
|
+
* M2 primary: WorkerEngine (worker_threads + MessagePort RPC, env:{},
|
|
9
|
+
* resourceLimits, hard `terminate()` wall-clock kill; bootstrap as a
|
|
10
|
+
* build-time string, strict-mode program body).
|
|
11
|
+
* M2 fallback: InlineVmEngine (node:vm runInNewContext — the script timeout
|
|
12
|
+
* kills PRE-await synchronous busy-loops; a POST-await busy loop blocks the
|
|
13
|
+
* host event loop irrecoverably, documented — prefer worker/auto).
|
|
14
|
+
*/
|
|
15
|
+
import * as vm from "node:vm";
|
|
16
|
+
import { PtcStopSignal } from "./contract.js";
|
|
17
|
+
/** Build the `tm` facade the program body sees (one method per bridge tool). */
|
|
18
|
+
function makeFacade(bridge) {
|
|
19
|
+
const one = (tool) => (args) => bridge.call(tool, args && typeof args === "object" ? args : {});
|
|
20
|
+
return { read: one("tm_read"), grep: one("tm_grep"), bash: one("tm_bash"), fetch: one("tm_fetch") };
|
|
21
|
+
}
|
|
22
|
+
export class InlineSequentialEngine {
|
|
23
|
+
name = "inline";
|
|
24
|
+
async run(program, bridge, signal) {
|
|
25
|
+
// M1 legacy engine, kept test-only: the program runs as a trusted async
|
|
26
|
+
// function body on the MAIN thread — no sandbox, no timeout, and a
|
|
27
|
+
// post-await busy loop blocks the host event loop irrecoverably (same
|
|
28
|
+
// residual as InlineVmEngine). Production runs WorkerEngine (auto
|
|
29
|
+
// default) or InlineVmEngine.
|
|
30
|
+
const AsyncFunction = Object.getPrototypeOf(async function () { }).constructor;
|
|
31
|
+
const tm = makeFacade(bridge);
|
|
32
|
+
let abortHandler;
|
|
33
|
+
const abortP = new Promise((_, rej) => {
|
|
34
|
+
// The driver only aborts on wall-clock timeout (budget stops flow through
|
|
35
|
+
// the gate as PtcStopSignal).
|
|
36
|
+
abortHandler = () => rej(new PtcStopSignal("timeout"));
|
|
37
|
+
if (signal.aborted)
|
|
38
|
+
abortHandler();
|
|
39
|
+
else
|
|
40
|
+
signal.addEventListener("abort", abortHandler, { once: true });
|
|
41
|
+
});
|
|
42
|
+
try {
|
|
43
|
+
const fn = new AsyncFunction("tm", `"use strict";\n${program}`);
|
|
44
|
+
return await Promise.race([fn(tm), abortP]);
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
if (abortHandler)
|
|
48
|
+
signal.removeEventListener("abort", abortHandler);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// ---------- worker engine (MessagePort RPC over worker_threads) --------------
|
|
53
|
+
export class WorkerEngine {
|
|
54
|
+
name = "worker";
|
|
55
|
+
async run(program, bridge, signal) {
|
|
56
|
+
const { Worker } = await import("node:worker_threads");
|
|
57
|
+
// Build the worker bootstrap source as a regular string (ts-safe).
|
|
58
|
+
// The worker receives {program, startDeadlineMs} via its first message,
|
|
59
|
+
// creates the tm facade, runs the program, and sends RPC call requests
|
|
60
|
+
// back to the driver which executes them through the gate bridge.
|
|
61
|
+
const src = [
|
|
62
|
+
'"use strict";',
|
|
63
|
+
'const { parentPort } = require("node:worker_threads");',
|
|
64
|
+
"parentPort.on(" + JSON.stringify("message") + ", async function onMsg(msg) {",
|
|
65
|
+
" if (msg && msg.t === " + JSON.stringify("run") + ") {",
|
|
66
|
+
" const program = msg.program;",
|
|
67
|
+
" const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;",
|
|
68
|
+
" const callMap = new Map();",
|
|
69
|
+
" let nextId = 0;",
|
|
70
|
+
' const one = function(tool) { return function(args) { return new Promise(function(resolve, reject) {',
|
|
71
|
+
" const id = nextId++;",
|
|
72
|
+
" callMap.set(id, { resolve: resolve, reject: reject });",
|
|
73
|
+
' parentPort.postMessage({ t: "call", id: id, tool: tool, args: args || {} });',
|
|
74
|
+
" }); }; };",
|
|
75
|
+
" var tm = { read: one(" + JSON.stringify("tm_read") + "), grep: one(" + JSON.stringify("tm_grep") + "), bash: one(" + JSON.stringify("tm_bash") + "), fetch: one(" + JSON.stringify("tm_fetch") + ") };",
|
|
76
|
+
' parentPort.on("message", function(inner) {',
|
|
77
|
+
' if (inner && inner.t === "result" && callMap.has(inner.id)) {',
|
|
78
|
+
" callMap.get(inner.id).resolve(inner.r);",
|
|
79
|
+
" callMap.delete(inner.id);",
|
|
80
|
+
' } else if (inner && inner.t === "abort") {',
|
|
81
|
+
" for (const e of callMap.values()) e.reject(new Error(" + JSON.stringify("ptc-stop:") + " + inner.reason));",
|
|
82
|
+
" callMap.clear();",
|
|
83
|
+
" }",
|
|
84
|
+
" });",
|
|
85
|
+
" try {",
|
|
86
|
+
// strict-mode body, same as the inline engines (they prefix the program
|
|
87
|
+
// with "use strict"; the worker builds the body string here)
|
|
88
|
+
" var body = " + JSON.stringify('"use strict";\n') + " + program;",
|
|
89
|
+
" var fn = new AsyncFunction(" + JSON.stringify("tm") + ", body);",
|
|
90
|
+
" var result = await fn(tm);",
|
|
91
|
+
' parentPort.postMessage({ t: "done", result: result });',
|
|
92
|
+
" } catch (err) {",
|
|
93
|
+
' parentPort.postMessage({ t: "error", message: err instanceof Error ? err.message : String(err), stack: err instanceof Error ? err.stack : undefined });',
|
|
94
|
+
" }",
|
|
95
|
+
" }",
|
|
96
|
+
"});",
|
|
97
|
+
].join("\n");
|
|
98
|
+
return new Promise((resolve, reject) => {
|
|
99
|
+
let settled = false;
|
|
100
|
+
const w = new Worker(src, {
|
|
101
|
+
eval: true,
|
|
102
|
+
env: {},
|
|
103
|
+
resourceLimits: { maxOldGenerationSizeMb: 128, maxYoungGenerationSizeMb: 16 },
|
|
104
|
+
});
|
|
105
|
+
function settle(fn) {
|
|
106
|
+
if (settled)
|
|
107
|
+
return;
|
|
108
|
+
settled = true;
|
|
109
|
+
fn();
|
|
110
|
+
}
|
|
111
|
+
w.on("message", (msg) => {
|
|
112
|
+
if (!msg || settled)
|
|
113
|
+
return;
|
|
114
|
+
if (msg.t === "done") {
|
|
115
|
+
settle(() => {
|
|
116
|
+
w.terminate();
|
|
117
|
+
resolve(msg.result);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
else if (msg.t === "error") {
|
|
121
|
+
settle(() => {
|
|
122
|
+
w.terminate();
|
|
123
|
+
const err = new Error(typeof msg.message === "string" ? msg.message : "worker error");
|
|
124
|
+
if (typeof msg.stack === "string")
|
|
125
|
+
err.stack = msg.stack;
|
|
126
|
+
reject(err);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
else if (msg.t === "call") {
|
|
130
|
+
// Driver executes the bridge call through the gate and replies.
|
|
131
|
+
const req = msg;
|
|
132
|
+
bridge
|
|
133
|
+
.call(req.tool, req.args)
|
|
134
|
+
.then((r) => {
|
|
135
|
+
if (!settled) {
|
|
136
|
+
w.postMessage({ t: "result", id: req.id, r });
|
|
137
|
+
}
|
|
138
|
+
})
|
|
139
|
+
.catch(() => {
|
|
140
|
+
if (!settled) {
|
|
141
|
+
w.postMessage({
|
|
142
|
+
t: "result",
|
|
143
|
+
id: req.id,
|
|
144
|
+
r: { ok: false, error: { tool: req.tool, phase: "execute", message: "bridge call failed" } },
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
w.on("error", (err) => {
|
|
151
|
+
settle(() => reject(err instanceof Error ? err : new Error(String(err))));
|
|
152
|
+
});
|
|
153
|
+
// Wire signal abort → terminate the worker.
|
|
154
|
+
const onAbort = () => {
|
|
155
|
+
settle(() => {
|
|
156
|
+
w.terminate().then(() => reject(new PtcStopSignal("timeout")));
|
|
157
|
+
});
|
|
158
|
+
};
|
|
159
|
+
if (signal.aborted)
|
|
160
|
+
onAbort();
|
|
161
|
+
else
|
|
162
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
163
|
+
// Send the run request.
|
|
164
|
+
w.postMessage({ t: "run", program });
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// ---------- inline-vm fallback engine (node:vm with script timeout) ----------
|
|
169
|
+
export class InlineVmEngine {
|
|
170
|
+
name = "inline";
|
|
171
|
+
/** Script execution timeout in ms (kills pre-await synchronous
|
|
172
|
+
* busy-loops). Injectable so tests can pin the kill fast. */
|
|
173
|
+
compileTimeoutMs;
|
|
174
|
+
constructor(compileTimeoutMs = 30_000) {
|
|
175
|
+
this.compileTimeoutMs = compileTimeoutMs;
|
|
176
|
+
}
|
|
177
|
+
async run(program, bridge, signal) {
|
|
178
|
+
const tm = makeFacade(bridge);
|
|
179
|
+
let abortHandler;
|
|
180
|
+
const abortP = new Promise((_, rej) => {
|
|
181
|
+
abortHandler = () => rej(new PtcStopSignal("timeout"));
|
|
182
|
+
if (signal.aborted)
|
|
183
|
+
abortHandler();
|
|
184
|
+
else
|
|
185
|
+
signal.addEventListener("abort", abortHandler, { once: true });
|
|
186
|
+
});
|
|
187
|
+
try {
|
|
188
|
+
// The async-IIFE is the program wrapper: `return` stays legal in the
|
|
189
|
+
// body, the `tm` facade rides the context globals, and the script's
|
|
190
|
+
// completion value IS the program's promise. The timeout kills
|
|
191
|
+
// pre-await synchronous busy-loops (see the module doc).
|
|
192
|
+
const promise = vm.runInNewContext(`(async () => {\n"use strict";\n${program}\n})()`, { tm }, { timeout: this.compileTimeoutMs });
|
|
193
|
+
return await Promise.race([promise, abortP]);
|
|
194
|
+
}
|
|
195
|
+
finally {
|
|
196
|
+
if (abortHandler)
|
|
197
|
+
signal.removeEventListener("abort", abortHandler);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=engines.js.map
|