@cortexkit/aft-bridge 0.58.2 → 0.60.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bash-format.d.ts.map +1 -1
- package/dist/bash-format.js +5 -0
- package/dist/bash-format.js.map +1 -1
- package/dist/bash-hints.d.ts +76 -30
- package/dist/bash-hints.d.ts.map +1 -1
- package/dist/bash-hints.js +225 -47
- package/dist/bash-hints.js.map +1 -1
- package/dist/bash-host-fallback.d.ts +27 -0
- package/dist/bash-host-fallback.d.ts.map +1 -1
- package/dist/bash-host-fallback.js +55 -16
- package/dist/bash-host-fallback.js.map +1 -1
- package/dist/binary-identity.d.ts +13 -0
- package/dist/binary-identity.d.ts.map +1 -1
- package/dist/binary-identity.js +91 -2
- package/dist/binary-identity.js.map +1 -1
- package/dist/bridge.d.ts +45 -3
- package/dist/bridge.d.ts.map +1 -1
- package/dist/bridge.js +161 -42
- package/dist/bridge.js.map +1 -1
- package/dist/callgraph-format.d.ts.map +1 -1
- package/dist/callgraph-format.js +7 -7
- package/dist/callgraph-format.js.map +1 -1
- package/dist/child-process.d.ts.map +1 -1
- package/dist/child-process.js +10 -1
- package/dist/child-process.js.map +1 -1
- package/dist/config-error.d.ts +2 -2
- package/dist/config-error.js +2 -2
- package/dist/config-watch.d.ts +10 -6
- package/dist/config-watch.d.ts.map +1 -1
- package/dist/config-watch.js +46 -12
- package/dist/config-watch.js.map +1 -1
- package/dist/durable-log.d.ts +11 -0
- package/dist/durable-log.d.ts.map +1 -1
- package/dist/durable-log.js +67 -24
- package/dist/durable-log.js.map +1 -1
- package/dist/error-contract.d.ts +29 -5
- package/dist/error-contract.d.ts.map +1 -1
- package/dist/error-contract.js +68 -9
- package/dist/error-contract.js.map +1 -1
- package/dist/feature-config.d.ts +35 -18
- package/dist/feature-config.d.ts.map +1 -1
- package/dist/feature-config.js +236 -94
- package/dist/feature-config.js.map +1 -1
- package/dist/index.d.ts +11 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -9
- package/dist/index.js.map +1 -1
- package/dist/location-lifecycle.d.ts.map +1 -1
- package/dist/location-lifecycle.js +4 -2
- package/dist/location-lifecycle.js.map +1 -1
- package/dist/message-detach.d.ts +8 -0
- package/dist/message-detach.d.ts.map +1 -1
- package/dist/message-detach.js +32 -0
- package/dist/message-detach.js.map +1 -1
- package/dist/migration-notices.d.ts.map +1 -1
- package/dist/migration-notices.js +12 -5
- package/dist/migration-notices.js.map +1 -1
- package/dist/migration.d.ts +1 -0
- package/dist/migration.d.ts.map +1 -1
- package/dist/migration.js +39 -12
- package/dist/migration.js.map +1 -1
- package/dist/onnx-runtime.d.ts.map +1 -1
- package/dist/onnx-runtime.js +37 -32
- package/dist/onnx-runtime.js.map +1 -1
- package/dist/path-display.d.ts +5 -0
- package/dist/path-display.d.ts.map +1 -0
- package/dist/path-display.js +21 -0
- package/dist/path-display.js.map +1 -0
- package/dist/paths.d.ts +3 -0
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +47 -11
- package/dist/paths.js.map +1 -1
- package/dist/pool.d.ts +2 -0
- package/dist/pool.d.ts.map +1 -1
- package/dist/pool.js +4 -1
- package/dist/pool.js.map +1 -1
- package/dist/private-storage.d.ts +9 -0
- package/dist/private-storage.d.ts.map +1 -0
- package/dist/private-storage.js +75 -0
- package/dist/private-storage.js.map +1 -0
- package/dist/protocol.d.ts +4 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/revivable-transport.d.ts +8 -2
- package/dist/revivable-transport.d.ts.map +1 -1
- package/dist/revivable-transport.js +63 -23
- package/dist/revivable-transport.js.map +1 -1
- package/dist/storage-paths.d.ts +3 -4
- package/dist/storage-paths.d.ts.map +1 -1
- package/dist/storage-paths.js +4 -5
- package/dist/storage-paths.js.map +1 -1
- package/dist/subc-transport.d.ts +104 -7
- package/dist/subc-transport.d.ts.map +1 -1
- package/dist/subc-transport.js +955 -61
- package/dist/subc-transport.js.map +1 -1
- package/dist/tar-executable.d.ts +1 -1
- package/dist/tar-executable.d.ts.map +1 -1
- package/dist/tar-executable.js +16 -2
- package/dist/tar-executable.js.map +1 -1
- package/dist/test-child-environment.d.ts +8 -0
- package/dist/test-child-environment.d.ts.map +1 -0
- package/dist/test-child-environment.js +105 -0
- package/dist/test-child-environment.js.map +1 -0
- package/dist/transport-factory.d.ts.map +1 -1
- package/dist/transport-factory.js +5 -4
- package/dist/transport-factory.js.map +1 -1
- package/dist/transport.d.ts +39 -0
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +26 -0
- package/dist/transport.js.map +1 -1
- package/dist/zoom-format.d.ts +1 -0
- package/dist/zoom-format.d.ts.map +1 -1
- package/dist/zoom-format.js +5 -1
- package/dist/zoom-format.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bash-format.d.ts","sourceRoot":"","sources":["../src/bash-format.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAElE,gGAAgG;AAChG,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"bash-format.d.ts","sourceRoot":"","sources":["../src/bash-format.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAElE,gGAAgG;AAChG,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAsB5E;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAQzD;AAED,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC"}
|
package/dist/bash-format.js
CHANGED
|
@@ -15,6 +15,11 @@ export function formatForegroundResult(data) {
|
|
|
15
15
|
}
|
|
16
16
|
if (status === "timed_out") {
|
|
17
17
|
rendered += `\n[command timed out]`;
|
|
18
|
+
// Name the limit that killed it, so AFT's own default limit is not
|
|
19
|
+
// mistaken for the command failing.
|
|
20
|
+
if (typeof data.status_reason === "string" && data.status_reason !== "") {
|
|
21
|
+
rendered += ` ${data.status_reason}`;
|
|
22
|
+
}
|
|
18
23
|
}
|
|
19
24
|
if (typeof exit === "number" && exit !== 0) {
|
|
20
25
|
rendered += `\n[exit code: ${exit}]`;
|
package/dist/bash-format.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bash-format.js","sourceRoot":"","sources":["../src/bash-format.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAElE,gGAAgG;AAChG,MAAM,UAAU,aAAa,CAAC,EAAU;IACtC,OAAO,GAAG,MAAM,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,IAA6B;IAClE,MAAM,MAAM,GAAI,IAAI,CAAC,cAAqC,IAAI,EAAE,CAAC;IACjE,MAAM,UAAU,GAAG,IAAI,CAAC,WAAiC,CAAC;IAC1D,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,KAAK,IAAI,CAAC;IACjD,MAAM,MAAM,GAAG,IAAI,CAAC,MAA4B,CAAC;IACjD,MAAM,IAAI,GAAG,IAAI,CAAC,SAA+B,CAAC;IAClD,IAAI,QAAQ,GAAG,MAAM,CAAC;IACtB,IAAI,SAAS,IAAI,UAAU,EAAE,CAAC;QAC5B,QAAQ,IAAI,uCAAuC,UAAU,GAAG,CAAC;IACnE,CAAC;IACD,IAAI,MAAM,KAAK,WAAW,EAAE,CAAC;QAC3B,QAAQ,IAAI,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"bash-format.js","sourceRoot":"","sources":["../src/bash-format.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAElE,gGAAgG;AAChG,MAAM,UAAU,aAAa,CAAC,EAAU;IACtC,OAAO,GAAG,MAAM,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,IAA6B;IAClE,MAAM,MAAM,GAAI,IAAI,CAAC,cAAqC,IAAI,EAAE,CAAC;IACjE,MAAM,UAAU,GAAG,IAAI,CAAC,WAAiC,CAAC;IAC1D,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,KAAK,IAAI,CAAC;IACjD,MAAM,MAAM,GAAG,IAAI,CAAC,MAA4B,CAAC;IACjD,MAAM,IAAI,GAAG,IAAI,CAAC,SAA+B,CAAC;IAClD,IAAI,QAAQ,GAAG,MAAM,CAAC;IACtB,IAAI,SAAS,IAAI,UAAU,EAAE,CAAC;QAC5B,QAAQ,IAAI,uCAAuC,UAAU,GAAG,CAAC;IACnE,CAAC;IACD,IAAI,MAAM,KAAK,WAAW,EAAE,CAAC;QAC3B,QAAQ,IAAI,uBAAuB,CAAC;QACpC,mEAAmE;QACnE,oCAAoC;QACpC,IAAI,OAAO,IAAI,CAAC,aAAa,KAAK,QAAQ,IAAI,IAAI,CAAC,aAAa,KAAK,EAAE,EAAE,CAAC;YACxE,QAAQ,IAAI,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QACvC,CAAC;IACH,CAAC;IACD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;QAC3C,QAAQ,IAAI,iBAAiB,IAAI,GAAG,CAAC;IACvC,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAe;IAC9C,OAAO,CACL,MAAM,KAAK,WAAW;QACtB,MAAM,KAAK,QAAQ;QACnB,MAAM,KAAK,QAAQ;QACnB,MAAM,KAAK,WAAW;QACtB,MAAM,KAAK,cAAc,CAC1B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,EAAU;IAC9B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,WAAW,CAAC,GAAG,EAAE,CAAC;AAC3B,CAAC"}
|
package/dist/bash-hints.d.ts
CHANGED
|
@@ -4,38 +4,54 @@ export type WatchCallerRole = "worker" | "primary";
|
|
|
4
4
|
export declare const DEFAULT_PRIMARY_WATCH_TIMEOUT_MS = 30000;
|
|
5
5
|
/** Largest bash_watch timeout accepted by the OpenCode and Pi plugins' tool schemas. */
|
|
6
6
|
export declare const MAX_WATCH_TIMEOUT_MS = 1800000;
|
|
7
|
+
/**
|
|
8
|
+
* Default `bash.worker_wait_max_ms`: the longest a delegated worker's wait on
|
|
9
|
+
* one command blocks before control returns to it. Mirrors
|
|
10
|
+
* `DEFAULT_BASH_WORKER_WAIT_MAX_MS` in the engine's `config.rs`. A worker that
|
|
11
|
+
* blocked with no limit once sat behind a stuck test run for fifteen hours;
|
|
12
|
+
* with the limit it gets control back, sees the command is still running, and
|
|
13
|
+
* decides whether to wait again or kill it.
|
|
14
|
+
*/
|
|
15
|
+
export declare const DEFAULT_WORKER_WAIT_MAX_MS = 1800000;
|
|
16
|
+
/** Smallest accepted `bash.worker_wait_max_ms`; mirrors `MIN_BASH_WORKER_WAIT_MAX_MS`. */
|
|
17
|
+
export declare const MIN_WORKER_WAIT_MAX_MS = 60000;
|
|
7
18
|
/**
|
|
8
19
|
* Longest delay a JavaScript timer accepts (2^31 - 1 ms, about 24.8 days); a
|
|
9
|
-
* larger one fires almost at once.
|
|
10
|
-
*
|
|
11
|
-
* in practice means no transport timeout.
|
|
20
|
+
* larger one fires almost at once. Bridge transport timeouts derived from a
|
|
21
|
+
* configured limit are clamped to it.
|
|
12
22
|
*/
|
|
13
23
|
export declare const LONGEST_TIMER_DELAY_MS = 2147483647;
|
|
24
|
+
/**
|
|
25
|
+
* How a delegated worker's waits are bounded, worded once for every tool
|
|
26
|
+
* description. It names the setting, not its value, so the prompt prefix is
|
|
27
|
+
* the same for every user.
|
|
28
|
+
*/
|
|
29
|
+
export declare const WORKER_WAIT_LIMIT_PHRASE = "the worker wait limit (`bash.worker_wait_max_ms`, 30 minutes by default)";
|
|
14
30
|
/**
|
|
15
31
|
* Description of the bash_watch tool's sync-wait defaults, embedded in both
|
|
16
32
|
* plugins' tool descriptions. Every caller sees the same description, so it
|
|
17
33
|
* has to state both roles' real behaviour.
|
|
18
34
|
*/
|
|
19
|
-
export declare const WATCH_SYNC_DEFAULTS_DESCRIPTION = "Sync waits default to 30s in a main session (max `bash.watch_sync_max_ms`, 120s by default); in a delegated session a sync wait without a timeout waits
|
|
35
|
+
export declare const WATCH_SYNC_DEFAULTS_DESCRIPTION = "Sync waits default to 30s in a main session (max `bash.watch_sync_max_ms`, 120s by default); in a delegated session a sync wait without a timeout waits up to the worker wait limit (`bash.worker_wait_max_ms`, 30 minutes by default), then reports it is still running; watch again to keep waiting. An explicit timeout never exceeds that worker limit";
|
|
20
36
|
/**
|
|
21
37
|
* Description of the bash_watch timeout parameter. Every caller sees the same
|
|
22
38
|
* schema, so it has to be true for both roles.
|
|
23
39
|
*/
|
|
24
|
-
export declare const WATCH_TIMEOUT_PARAM_DESCRIPTION = "Sync-only timeout in milliseconds. In a main session: default 30000, max `bash.watch_sync_max_ms` (120000 by default). In a delegated session: omit it to wait
|
|
40
|
+
export declare const WATCH_TIMEOUT_PARAM_DESCRIPTION = "Sync-only timeout in milliseconds. In a main session: default 30000, max `bash.watch_sync_max_ms` (120000 by default). In a delegated session: omit it to wait up to the worker wait limit (`bash.worker_wait_max_ms`, 30 minutes by default), after which the watch reports the command is still running; a value you pass is clamped to that worker limit.";
|
|
25
41
|
/**
|
|
26
|
-
* Effective sync bash_watch deadline in milliseconds
|
|
27
|
-
* wait with no deadline, which lasts until the task exits, a pattern matches,
|
|
28
|
-
* a new message arrives, or the call is aborted.
|
|
42
|
+
* Effective sync bash_watch deadline in milliseconds.
|
|
29
43
|
*
|
|
30
44
|
* A delegated worker cannot be woken once its turn ends, so it has nothing
|
|
31
|
-
* useful to do while its command runs except wait
|
|
32
|
-
* call bash_watch again,
|
|
33
|
-
* therefore waits
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
45
|
+
* useful to do while its command runs except wait, and a short deadline only
|
|
46
|
+
* makes it call bash_watch again, re-reading its whole context each time. It
|
|
47
|
+
* therefore waits up to the worker wait limit (`workerWaitMaxMs`,
|
|
48
|
+
* `bash.worker_wait_max_ms`) by default: long enough that re-watching is
|
|
49
|
+
* rare, short enough that a stuck command cannot hold it forever. A timeout
|
|
50
|
+
* it passes is clamped to the worker limit, not to the primary cap. A
|
|
51
|
+
* primary keeps the short default and the cap because it can do other work
|
|
52
|
+
* or end its turn and be woken by the completion reminder.
|
|
37
53
|
*/
|
|
38
|
-
export declare function resolveWatchTimeoutMs(requestedMs: number | undefined, role: WatchCallerRole, capMs: number): number
|
|
54
|
+
export declare function resolveWatchTimeoutMs(requestedMs: number | undefined, role: WatchCallerRole, capMs: number, workerWaitMaxMs: number): number;
|
|
39
55
|
/**
|
|
40
56
|
* Largest bash_watch timeout a caller of this role may pass. A primary is
|
|
41
57
|
* bounded by the configured cap; a worker only by the schema maximum.
|
|
@@ -73,18 +89,48 @@ export declare function abortableSleep(ms: number, signal?: AbortSignal): Promis
|
|
|
73
89
|
*/
|
|
74
90
|
export declare function formatWatchWaited(elapsedMs: number, limitMs: number | undefined, capMs: number | undefined): string;
|
|
75
91
|
/**
|
|
76
|
-
* Appended to a bash_watch reply whose sync deadline passed without
|
|
77
|
-
* The deadline is a property of the watch, not of the command
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
*
|
|
86
|
-
|
|
87
|
-
|
|
92
|
+
* Appended to a primary's bash_watch reply whose sync deadline passed without
|
|
93
|
+
* a match. The deadline is a property of the watch, not of the command, so the
|
|
94
|
+
* caller is told the command is still running and that the completion
|
|
95
|
+
* reminder wakes it. A worker gets {@link workerWatchStillRunning} instead.
|
|
96
|
+
*/
|
|
97
|
+
export declare function watchTimeoutSteer(): string;
|
|
98
|
+
/** A duration in words: whole minutes as minutes, anything else in seconds. */
|
|
99
|
+
export declare function formatWaitDuration(ms: number): string;
|
|
100
|
+
/**
|
|
101
|
+
* The sentence naming a task's own kill deadline, from the `hard_kill` field
|
|
102
|
+
* and `started_at` of the engine's task status (`{ limit_ms, source }`), or how
|
|
103
|
+
* the task was killed when its hard kill fired (`status_reason`). It reports an
|
|
104
|
+
* absolute UTC deadline measured from command start and the approximate time
|
|
105
|
+
* remaining. Mirrors `kill_deadline_sentence` in the engine.
|
|
106
|
+
*/
|
|
107
|
+
export declare function taskKillDeadlineText(data: Record<string, unknown>, role: WatchCallerRole, nowMs?: number): string;
|
|
108
|
+
/**
|
|
109
|
+
* A wait should not hand back a still-running task just before its own kill
|
|
110
|
+
* deadline. Five seconds covers the slowest status poll and kill publication.
|
|
111
|
+
*/
|
|
112
|
+
export declare function taskKillDeadlineWithinHandoffMargin(data: Record<string, unknown>): boolean;
|
|
113
|
+
/** The last lines of `output`, so a worker can judge whether a command is stuck. */
|
|
114
|
+
export declare function outputTail(output: string | undefined): string;
|
|
115
|
+
/**
|
|
116
|
+
* Appended to a delegated worker's bash_watch reply whose deadline passed
|
|
117
|
+
* while the command still runs (by default the worker wait limit). The
|
|
118
|
+
* deadline is a property of the watch, not of the command: a worker that read
|
|
119
|
+
* a bare "timeout reached" line as its own execution failing declared a
|
|
120
|
+
* failed result while its command was still going. So it is told plainly that
|
|
121
|
+
* the command is still running, how long it has run, and its latest output,
|
|
122
|
+
* then given both moves by name: watch again to keep waiting, or kill a
|
|
123
|
+
* command that should have finished. `taskIdArg` and `timeoutParam` are the
|
|
124
|
+
* host's spellings of the bash_watch arguments.
|
|
125
|
+
*/
|
|
126
|
+
export declare function workerWatchStillRunning(options: {
|
|
127
|
+
taskId: string;
|
|
128
|
+
waitedMs: number;
|
|
129
|
+
ranMs: number | undefined;
|
|
130
|
+
output: string | undefined;
|
|
131
|
+
taskIdArg?: string;
|
|
132
|
+
timeoutParam?: string;
|
|
133
|
+
}): string;
|
|
88
134
|
/**
|
|
89
135
|
* How long a sync bash_watch with no deadline keeps retrying while every
|
|
90
136
|
* status poll times out because the bridge is busy. Without this bound a wait
|
|
@@ -110,9 +156,9 @@ export declare function interruptedWatchTail(role: WatchCallerRole, primaryTail:
|
|
|
110
156
|
* command now runs in the background. AFT's own reply already says the task
|
|
111
157
|
* won't wake the worker; this names the plugin-owned bash_watch tool, which
|
|
112
158
|
* AFT cannot assume a host has. The suggested call passes no timeout on
|
|
113
|
-
* purpose: a worker's watch without one waits
|
|
114
|
-
* any number would only make it wake and watch
|
|
115
|
-
* host's spelling of the task id argument.
|
|
159
|
+
* purpose: a worker's watch without one waits up to the worker wait limit,
|
|
160
|
+
* the longest it may, so any number would only make it wake sooner and watch
|
|
161
|
+
* again. `taskIdArg` is the host's spelling of the task id argument.
|
|
116
162
|
*/
|
|
117
163
|
export declare function workerBackgroundTaskNote(taskId: string, taskIdArg?: string): string;
|
|
118
164
|
/**
|
package/dist/bash-hints.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bash-hints.d.ts","sourceRoot":"","sources":["../src/bash-hints.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bash-hints.d.ts","sourceRoot":"","sources":["../src/bash-hints.ts"],"names":[],"mappings":"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"}
|
package/dist/bash-hints.js
CHANGED
|
@@ -1,44 +1,61 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as os from "node:os";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
+
import { relativePathEscapesRoot } from "./path-display.js";
|
|
4
5
|
/** Sync bash_watch deadline used by a primary session that passes no timeout. */
|
|
5
6
|
export const DEFAULT_PRIMARY_WATCH_TIMEOUT_MS = 30_000;
|
|
6
7
|
/** Largest bash_watch timeout accepted by the OpenCode and Pi plugins' tool schemas. */
|
|
7
8
|
export const MAX_WATCH_TIMEOUT_MS = 1_800_000;
|
|
9
|
+
/**
|
|
10
|
+
* Default `bash.worker_wait_max_ms`: the longest a delegated worker's wait on
|
|
11
|
+
* one command blocks before control returns to it. Mirrors
|
|
12
|
+
* `DEFAULT_BASH_WORKER_WAIT_MAX_MS` in the engine's `config.rs`. A worker that
|
|
13
|
+
* blocked with no limit once sat behind a stuck test run for fifteen hours;
|
|
14
|
+
* with the limit it gets control back, sees the command is still running, and
|
|
15
|
+
* decides whether to wait again or kill it.
|
|
16
|
+
*/
|
|
17
|
+
export const DEFAULT_WORKER_WAIT_MAX_MS = 1_800_000;
|
|
18
|
+
/** Smallest accepted `bash.worker_wait_max_ms`; mirrors `MIN_BASH_WORKER_WAIT_MAX_MS`. */
|
|
19
|
+
export const MIN_WORKER_WAIT_MAX_MS = 60_000;
|
|
8
20
|
/**
|
|
9
21
|
* Longest delay a JavaScript timer accepts (2^31 - 1 ms, about 24.8 days); a
|
|
10
|
-
* larger one fires almost at once.
|
|
11
|
-
*
|
|
12
|
-
* in practice means no transport timeout.
|
|
22
|
+
* larger one fires almost at once. Bridge transport timeouts derived from a
|
|
23
|
+
* configured limit are clamped to it.
|
|
13
24
|
*/
|
|
14
25
|
export const LONGEST_TIMER_DELAY_MS = 2_147_483_647;
|
|
26
|
+
/**
|
|
27
|
+
* How a delegated worker's waits are bounded, worded once for every tool
|
|
28
|
+
* description. It names the setting, not its value, so the prompt prefix is
|
|
29
|
+
* the same for every user.
|
|
30
|
+
*/
|
|
31
|
+
export const WORKER_WAIT_LIMIT_PHRASE = "the worker wait limit (`bash.worker_wait_max_ms`, 30 minutes by default)";
|
|
15
32
|
/**
|
|
16
33
|
* Description of the bash_watch tool's sync-wait defaults, embedded in both
|
|
17
34
|
* plugins' tool descriptions. Every caller sees the same description, so it
|
|
18
35
|
* has to state both roles' real behaviour.
|
|
19
36
|
*/
|
|
20
|
-
export const WATCH_SYNC_DEFAULTS_DESCRIPTION = "Sync waits default to 30s in a main session (max `bash.watch_sync_max_ms`, 120s by default); in a delegated session a sync wait without a timeout waits
|
|
37
|
+
export const WATCH_SYNC_DEFAULTS_DESCRIPTION = "Sync waits default to 30s in a main session (max `bash.watch_sync_max_ms`, 120s by default); in a delegated session a sync wait without a timeout waits up to the worker wait limit (`bash.worker_wait_max_ms`, 30 minutes by default), then reports it is still running; watch again to keep waiting. An explicit timeout never exceeds that worker limit";
|
|
21
38
|
/**
|
|
22
39
|
* Description of the bash_watch timeout parameter. Every caller sees the same
|
|
23
40
|
* schema, so it has to be true for both roles.
|
|
24
41
|
*/
|
|
25
|
-
export const WATCH_TIMEOUT_PARAM_DESCRIPTION = "Sync-only timeout in milliseconds. In a main session: default 30000, max `bash.watch_sync_max_ms` (120000 by default). In a delegated session: omit it to wait
|
|
42
|
+
export const WATCH_TIMEOUT_PARAM_DESCRIPTION = "Sync-only timeout in milliseconds. In a main session: default 30000, max `bash.watch_sync_max_ms` (120000 by default). In a delegated session: omit it to wait up to the worker wait limit (`bash.worker_wait_max_ms`, 30 minutes by default), after which the watch reports the command is still running; a value you pass is clamped to that worker limit.";
|
|
26
43
|
/**
|
|
27
|
-
* Effective sync bash_watch deadline in milliseconds
|
|
28
|
-
* wait with no deadline, which lasts until the task exits, a pattern matches,
|
|
29
|
-
* a new message arrives, or the call is aborted.
|
|
44
|
+
* Effective sync bash_watch deadline in milliseconds.
|
|
30
45
|
*
|
|
31
46
|
* A delegated worker cannot be woken once its turn ends, so it has nothing
|
|
32
|
-
* useful to do while its command runs except wait
|
|
33
|
-
* call bash_watch again,
|
|
34
|
-
* therefore waits
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
47
|
+
* useful to do while its command runs except wait, and a short deadline only
|
|
48
|
+
* makes it call bash_watch again, re-reading its whole context each time. It
|
|
49
|
+
* therefore waits up to the worker wait limit (`workerWaitMaxMs`,
|
|
50
|
+
* `bash.worker_wait_max_ms`) by default: long enough that re-watching is
|
|
51
|
+
* rare, short enough that a stuck command cannot hold it forever. A timeout
|
|
52
|
+
* it passes is clamped to the worker limit, not to the primary cap. A
|
|
53
|
+
* primary keeps the short default and the cap because it can do other work
|
|
54
|
+
* or end its turn and be woken by the completion reminder.
|
|
38
55
|
*/
|
|
39
|
-
export function resolveWatchTimeoutMs(requestedMs, role, capMs) {
|
|
56
|
+
export function resolveWatchTimeoutMs(requestedMs, role, capMs, workerWaitMaxMs) {
|
|
40
57
|
if (role === "worker")
|
|
41
|
-
return requestedMs;
|
|
58
|
+
return Math.min(requestedMs ?? workerWaitMaxMs, workerWaitMaxMs);
|
|
42
59
|
return Math.min(requestedMs ?? DEFAULT_PRIMARY_WATCH_TIMEOUT_MS, capMs);
|
|
43
60
|
}
|
|
44
61
|
/**
|
|
@@ -101,7 +118,7 @@ export function abortableSleep(ms, signal) {
|
|
|
101
118
|
export function formatWatchWaited(elapsedMs, limitMs, capMs) {
|
|
102
119
|
let limit;
|
|
103
120
|
if (limitMs === undefined)
|
|
104
|
-
limit = "no limit
|
|
121
|
+
limit = "no wait limit";
|
|
105
122
|
else if (capMs !== undefined && limitMs >= capMs)
|
|
106
123
|
limit = `limit ${limitMs}ms, the bash.watch_sync_max_ms cap`;
|
|
107
124
|
else
|
|
@@ -109,23 +126,149 @@ export function formatWatchWaited(elapsedMs, limitMs, capMs) {
|
|
|
109
126
|
return `Waited ${Math.round(elapsedMs)}ms (${limit})`;
|
|
110
127
|
}
|
|
111
128
|
/**
|
|
112
|
-
* Appended to a bash_watch reply whose sync deadline passed without
|
|
113
|
-
* The deadline is a property of the watch, not of the command
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
* still going. Each role gets only the move that applies to it: a worker must
|
|
117
|
-
* keep watching and not report, while a primary may end its turn because the
|
|
118
|
-
* completion reminder wakes it. A worker only reaches this with a timeout it
|
|
119
|
-
* passed itself, so it is told that leaving the timeout out waits until the
|
|
120
|
-
* command finishes. `timeoutParam` is the host's spelling of the bash_watch
|
|
121
|
-
* timeout argument, so the worker is told a name it can pass.
|
|
129
|
+
* Appended to a primary's bash_watch reply whose sync deadline passed without
|
|
130
|
+
* a match. The deadline is a property of the watch, not of the command, so the
|
|
131
|
+
* caller is told the command is still running and that the completion
|
|
132
|
+
* reminder wakes it. A worker gets {@link workerWatchStillRunning} instead.
|
|
122
133
|
*/
|
|
123
|
-
export function watchTimeoutSteer(
|
|
124
|
-
if (role === "worker") {
|
|
125
|
-
return `The command is still running; this is not a failure. Watch again and don't report a result until it finishes; a bash_watch without ${timeoutParam} waits until the command finishes.`;
|
|
126
|
-
}
|
|
134
|
+
export function watchTimeoutSteer() {
|
|
127
135
|
return "The command is still running; this is not a failure. Watch again, do other work, or end your turn: the completion reminder wakes you.";
|
|
128
136
|
}
|
|
137
|
+
/** A duration in words: whole minutes as minutes, anything else in seconds. */
|
|
138
|
+
export function formatWaitDuration(ms) {
|
|
139
|
+
const rounded = Math.max(0, Math.round(ms));
|
|
140
|
+
if (rounded === 60_000)
|
|
141
|
+
return "1 minute";
|
|
142
|
+
if (rounded > 0 && rounded % 60_000 === 0)
|
|
143
|
+
return `${rounded / 60_000} minutes`;
|
|
144
|
+
const seconds = (rounded / 1000).toFixed(1).replace(/\.0$/, "");
|
|
145
|
+
return `${seconds}s`;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* The sentence naming a task's own kill deadline, from the `hard_kill` field
|
|
149
|
+
* and `started_at` of the engine's task status (`{ limit_ms, source }`), or how
|
|
150
|
+
* the task was killed when its hard kill fired (`status_reason`). It reports an
|
|
151
|
+
* absolute UTC deadline measured from command start and the approximate time
|
|
152
|
+
* remaining. Mirrors `kill_deadline_sentence` in the engine.
|
|
153
|
+
*/
|
|
154
|
+
export function taskKillDeadlineText(data, role, nowMs = Date.now()) {
|
|
155
|
+
if (data.status === "timed_out") {
|
|
156
|
+
const reason = typeof data.status_reason === "string" ? data.status_reason : "";
|
|
157
|
+
return reason === ""
|
|
158
|
+
? "The task was killed by its time limit (exit 124)."
|
|
159
|
+
: `The task was ${reason}.`;
|
|
160
|
+
}
|
|
161
|
+
// A terminal task's deadline no longer matters; an unknown state (the
|
|
162
|
+
// bridge stayed busy) has none to report.
|
|
163
|
+
if (isTerminalTaskStatus(data.status) || typeof data.status !== "string")
|
|
164
|
+
return "";
|
|
165
|
+
if (data.status === "unknown")
|
|
166
|
+
return "";
|
|
167
|
+
// A remote task has no AFT hard-kill deadline (`hard_kill`); report its
|
|
168
|
+
// build-server status note instead (still queued, or when the runner will
|
|
169
|
+
// stop it). Mirrors `kill_deadline_text` in crates/aft/src/commands/bash_watch.rs.
|
|
170
|
+
if (typeof data.remote_phase_note === "string" && data.remote_phase_note !== "") {
|
|
171
|
+
const note = data.remote_phase_note;
|
|
172
|
+
return `${note.charAt(0).toUpperCase()}${note.slice(1)}.`;
|
|
173
|
+
}
|
|
174
|
+
const hardKill = data.hard_kill;
|
|
175
|
+
if (!hardKill || typeof hardKill.limit_ms !== "number") {
|
|
176
|
+
return "This task has no kill deadline.";
|
|
177
|
+
}
|
|
178
|
+
const startedAtMs = data.started_at;
|
|
179
|
+
if (typeof startedAtMs !== "number" || !Number.isSafeInteger(startedAtMs)) {
|
|
180
|
+
return "This task has no kill deadline.";
|
|
181
|
+
}
|
|
182
|
+
const limitMs = hardKill.limit_ms;
|
|
183
|
+
const limit = formatWaitDuration(limitMs);
|
|
184
|
+
const deadlineAt = startedAtMs + limitMs;
|
|
185
|
+
const when = `at ${formatKillDeadlineUtc(deadlineAt)}, when it has run ${limit}`;
|
|
186
|
+
let source;
|
|
187
|
+
if (hardKill.source === "timeout") {
|
|
188
|
+
source = "(the `timeout` you passed)";
|
|
189
|
+
}
|
|
190
|
+
else if (role === "worker") {
|
|
191
|
+
source =
|
|
192
|
+
"(its default background limit), but each wait you make on it moves that kill to at least the worker wait limit (`bash.worker_wait_max_ms`) after the wait, so it is not killed while you keep waiting; pass a `timeout` to set your own limit";
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
source = "(its default background limit) unless you pass a longer `timeout`";
|
|
196
|
+
}
|
|
197
|
+
const remaining = deadlineAt <= nowMs
|
|
198
|
+
? "; the kill deadline has passed"
|
|
199
|
+
: `; about ${formatApproximateRemaining(deadlineAt - nowMs)} remain`;
|
|
200
|
+
return `AFT kills this task ${when} ${source}${remaining}.`;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* A wait should not hand back a still-running task just before its own kill
|
|
204
|
+
* deadline. Five seconds covers the slowest status poll and kill publication.
|
|
205
|
+
*/
|
|
206
|
+
export function taskKillDeadlineWithinHandoffMargin(data) {
|
|
207
|
+
if (typeof data.status !== "string" || isTerminalTaskStatus(data.status))
|
|
208
|
+
return false;
|
|
209
|
+
const hardKill = data.hard_kill;
|
|
210
|
+
const limitMs = hardKill?.limit_ms;
|
|
211
|
+
const elapsedMs = data.elapsed_ms;
|
|
212
|
+
return (typeof limitMs === "number" &&
|
|
213
|
+
Number.isSafeInteger(limitMs) &&
|
|
214
|
+
typeof elapsedMs === "number" &&
|
|
215
|
+
Number.isSafeInteger(elapsedMs) &&
|
|
216
|
+
limitMs - elapsedMs <= 5_000);
|
|
217
|
+
}
|
|
218
|
+
function formatKillDeadlineUtc(unixMs) {
|
|
219
|
+
const date = new Date(unixMs);
|
|
220
|
+
if (!Number.isFinite(date.getTime()))
|
|
221
|
+
throw new Error("invalid bash task start time");
|
|
222
|
+
const year = String(date.getUTCFullYear()).padStart(4, "0");
|
|
223
|
+
const month = String(date.getUTCMonth() + 1).padStart(2, "0");
|
|
224
|
+
const day = String(date.getUTCDate()).padStart(2, "0");
|
|
225
|
+
const hour = String(date.getUTCHours()).padStart(2, "0");
|
|
226
|
+
const minute = String(date.getUTCMinutes()).padStart(2, "0");
|
|
227
|
+
const second = String(date.getUTCSeconds()).padStart(2, "0");
|
|
228
|
+
const millis = date.getUTCMilliseconds();
|
|
229
|
+
const fraction = millis === 0 ? "" : `.${String(millis).padStart(3, "0")}`;
|
|
230
|
+
return `${year}-${month}-${day} ${hour}:${minute}:${second}${fraction}Z`;
|
|
231
|
+
}
|
|
232
|
+
function formatApproximateRemaining(ms) {
|
|
233
|
+
if (ms >= 60_000) {
|
|
234
|
+
const minutes = Math.max(1, Math.floor((ms + 30_000) / 60_000));
|
|
235
|
+
return `${minutes} minute${minutes === 1 ? "" : "s"}`;
|
|
236
|
+
}
|
|
237
|
+
return formatWaitDuration(ms);
|
|
238
|
+
}
|
|
239
|
+
function isTerminalTaskStatus(status) {
|
|
240
|
+
return (status === "completed" ||
|
|
241
|
+
status === "failed" ||
|
|
242
|
+
status === "killed" ||
|
|
243
|
+
status === "timed_out" ||
|
|
244
|
+
status === "fate_unknown");
|
|
245
|
+
}
|
|
246
|
+
/** Most lines of a still-running command's output shown to a worker. */
|
|
247
|
+
const WORKER_OUTPUT_TAIL_LINES = 20;
|
|
248
|
+
/** The last lines of `output`, so a worker can judge whether a command is stuck. */
|
|
249
|
+
export function outputTail(output) {
|
|
250
|
+
const lines = (output ?? "").replace(/\s+$/, "").split("\n");
|
|
251
|
+
return lines.slice(-WORKER_OUTPUT_TAIL_LINES).join("\n");
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Appended to a delegated worker's bash_watch reply whose deadline passed
|
|
255
|
+
* while the command still runs (by default the worker wait limit). The
|
|
256
|
+
* deadline is a property of the watch, not of the command: a worker that read
|
|
257
|
+
* a bare "timeout reached" line as its own execution failing declared a
|
|
258
|
+
* failed result while its command was still going. So it is told plainly that
|
|
259
|
+
* the command is still running, how long it has run, and its latest output,
|
|
260
|
+
* then given both moves by name: watch again to keep waiting, or kill a
|
|
261
|
+
* command that should have finished. `taskIdArg` and `timeoutParam` are the
|
|
262
|
+
* host's spellings of the bash_watch arguments.
|
|
263
|
+
*/
|
|
264
|
+
export function workerWatchStillRunning(options) {
|
|
265
|
+
const taskIdArg = options.taskIdArg ?? "taskId";
|
|
266
|
+
const timeoutParam = options.timeoutParam ?? "timeoutMs";
|
|
267
|
+
const ran = options.ranMs === undefined ? "" : ` It has run for ${formatWaitDuration(options.ranMs)}.`;
|
|
268
|
+
const tail = outputTail(options.output);
|
|
269
|
+
const output = tail === "" ? "No output yet." : `Recent output:\n${tail}`;
|
|
270
|
+
return `The command is still running after ${formatWaitDuration(options.waitedMs)} of watching; this is not a failure.${ran} Call bash_watch({ ${taskIdArg}: "${options.taskId}" }) again to keep waiting (without ${timeoutParam} a watch waits up to the worker wait limit, then reports it is still running), or bash_kill({ ${taskIdArg}: "${options.taskId}" }) if it should have finished by now. Don't report a result until it finishes.\n${output}`;
|
|
271
|
+
}
|
|
129
272
|
/**
|
|
130
273
|
* How long a sync bash_watch with no deadline keeps retrying while every
|
|
131
274
|
* status poll times out because the bridge is busy. Without this bound a wait
|
|
@@ -153,12 +296,12 @@ export function interruptedWatchTail(role, primaryTail) {
|
|
|
153
296
|
* command now runs in the background. AFT's own reply already says the task
|
|
154
297
|
* won't wake the worker; this names the plugin-owned bash_watch tool, which
|
|
155
298
|
* AFT cannot assume a host has. The suggested call passes no timeout on
|
|
156
|
-
* purpose: a worker's watch without one waits
|
|
157
|
-
* any number would only make it wake and watch
|
|
158
|
-
* host's spelling of the task id argument.
|
|
299
|
+
* purpose: a worker's watch without one waits up to the worker wait limit,
|
|
300
|
+
* the longest it may, so any number would only make it wake sooner and watch
|
|
301
|
+
* again. `taskIdArg` is the host's spelling of the task id argument.
|
|
159
302
|
*/
|
|
160
303
|
export function workerBackgroundTaskNote(taskId, taskIdArg = "taskId") {
|
|
161
|
-
return `\n\nNOTE (subagent session): Continue with other work if you have it. If you don't, call bash_watch({ ${taskIdArg}: "${taskId}" }) to wait for completion before returning to the parent; without a timeout it waits
|
|
304
|
+
return `\n\nNOTE (subagent session): Continue with other work if you have it. If you don't, call bash_watch({ ${taskIdArg}: "${taskId}" }) to wait for completion before returning to the parent; without a timeout it waits up to ${WORKER_WAIT_LIMIT_PHRASE}, then reports it is still running; watch again to keep waiting, or call bash_kill({ ${taskIdArg}: "${taskId}" }) if it should have finished by now. Subagents don't survive turn-end and won't be woken when the command finishes.`;
|
|
162
305
|
}
|
|
163
306
|
/**
|
|
164
307
|
* Line a bash_status snapshot of a still-running task ends with. A primary is
|
|
@@ -369,7 +512,7 @@ function nextCwdAfterCd(currentCwd, firstStage, afterCd) {
|
|
|
369
512
|
}
|
|
370
513
|
function isDirInsideProject(resolvedRoot, dir) {
|
|
371
514
|
const rel = path.relative(resolvedRoot, path.resolve(dir));
|
|
372
|
-
return
|
|
515
|
+
return !relativePathEscapesRoot(rel);
|
|
373
516
|
}
|
|
374
517
|
function collectPathOperands(firstStage, startAfterCommand) {
|
|
375
518
|
const operands = [];
|
|
@@ -380,6 +523,8 @@ function collectPathOperands(firstStage, startAfterCommand) {
|
|
|
380
523
|
// the grep read as path-less ("in-project cwd") and nudged toward aft_search
|
|
381
524
|
// for a target it could not see - the logs directory, in the field.
|
|
382
525
|
let sawPattern = false;
|
|
526
|
+
let optionsEnded = false;
|
|
527
|
+
let optionValue;
|
|
383
528
|
while (index < firstStage.length) {
|
|
384
529
|
const tokenResult = readShellToken(firstStage, index);
|
|
385
530
|
if (tokenResult === null)
|
|
@@ -393,23 +538,56 @@ function collectPathOperands(firstStage, startAfterCommand) {
|
|
|
393
538
|
if (end <= index)
|
|
394
539
|
break;
|
|
395
540
|
index = skipSpaces(firstStage, end);
|
|
396
|
-
|
|
541
|
+
// A descriptor before a redirection is shell syntax, not a search path.
|
|
542
|
+
if (/^\d+$/.test(token) && /[<>]/.test(firstStage[end] ?? ""))
|
|
543
|
+
break;
|
|
544
|
+
if (optionValue) {
|
|
545
|
+
if (optionValue === "pattern" || optionValue === "file")
|
|
546
|
+
sawPattern = true;
|
|
547
|
+
optionValue = undefined;
|
|
548
|
+
continue;
|
|
549
|
+
}
|
|
550
|
+
if (!optionsEnded && token === "--") {
|
|
551
|
+
optionsEnded = true;
|
|
397
552
|
continue;
|
|
398
|
-
|
|
553
|
+
}
|
|
554
|
+
if (!optionsEnded && token.startsWith("-")) {
|
|
555
|
+
if (token === "-e" || token === "--regexp")
|
|
556
|
+
optionValue = "pattern";
|
|
557
|
+
else if (token === "-f" || token === "--file")
|
|
558
|
+
optionValue = "file";
|
|
559
|
+
else if (/^(?:--regexp=|--file=|-e.+|-f.+)/.test(token))
|
|
560
|
+
sawPattern = true;
|
|
561
|
+
else if ([
|
|
562
|
+
"-A",
|
|
563
|
+
"-B",
|
|
564
|
+
"-C",
|
|
565
|
+
"-m",
|
|
566
|
+
"--after-context",
|
|
567
|
+
"--before-context",
|
|
568
|
+
"--context",
|
|
569
|
+
"--max-count",
|
|
570
|
+
"--include",
|
|
571
|
+
"--exclude",
|
|
572
|
+
"--exclude-dir",
|
|
573
|
+
"-g",
|
|
574
|
+
"--glob",
|
|
575
|
+
"-t",
|
|
576
|
+
"--type",
|
|
577
|
+
"-T",
|
|
578
|
+
"--type-not",
|
|
579
|
+
].includes(token))
|
|
580
|
+
optionValue = "other";
|
|
581
|
+
continue;
|
|
582
|
+
}
|
|
583
|
+
if (!sawPattern) {
|
|
399
584
|
sawPattern = true;
|
|
400
585
|
continue;
|
|
401
586
|
}
|
|
402
|
-
|
|
403
|
-
operands.push(token);
|
|
587
|
+
operands.push(token);
|
|
404
588
|
}
|
|
405
589
|
return operands;
|
|
406
590
|
}
|
|
407
|
-
function looksLikePathOperand(token) {
|
|
408
|
-
return (token.includes("/") ||
|
|
409
|
-
token.startsWith("~") ||
|
|
410
|
-
token.startsWith("./") ||
|
|
411
|
-
token.startsWith("../"));
|
|
412
|
-
}
|
|
413
591
|
function isDynamicPathOperand(token) {
|
|
414
592
|
return token.startsWith("~") || token.includes("$") || token.includes("`");
|
|
415
593
|
}
|
|
@@ -430,7 +608,7 @@ function isPathInsideProject(resolvedRoot, baseCwd, operand) {
|
|
|
430
608
|
// from the project root after a `cd`), absolute/`~` operands against the FS.
|
|
431
609
|
const resolved = resolvePathOperand(baseCwd, operand);
|
|
432
610
|
const rel = path.relative(resolvedRoot, resolved);
|
|
433
|
-
return
|
|
611
|
+
return !relativePathEscapesRoot(rel);
|
|
434
612
|
}
|
|
435
613
|
function shouldSuppressResolvedPath(resolved) {
|
|
436
614
|
try {
|