pi-background-tasks 2.5.0 → 2.6.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/BACKGROUND-TASKS-INSTRUCTIONS.md +1 -1
- package/README.md +70 -25
- package/TESTING.md +42 -2
- package/TEST_PLAN.md +7 -4
- package/dist/extensions/anthropic-attribution-child.js +4 -0
- package/dist/extensions/anthropic-attribution-child.js.map +1 -0
- package/dist/extensions/anthropic-attribution.js +107 -0
- package/dist/extensions/anthropic-attribution.js.map +1 -0
- package/dist/extensions/background-tasks.js +2 -0
- package/dist/extensions/background-tasks.js.map +1 -0
- package/dist/extensions/delegate-child.js +2 -0
- package/dist/extensions/delegate-child.js.map +1 -0
- package/dist/extensions/fusion-child.js +2 -0
- package/dist/extensions/fusion-child.js.map +1 -0
- package/dist/package.json +5 -0
- package/dist/src/core/anthropic-attribution-path.js +24 -0
- package/dist/src/core/anthropic-attribution-path.js.map +1 -0
- package/dist/src/core/anthropic-attribution.js +2247 -0
- package/dist/src/core/anthropic-attribution.js.map +1 -0
- package/dist/src/core/attested-pi-contract.js +5 -0
- package/dist/src/core/attested-pi-contract.js.map +1 -0
- package/dist/src/core/attested-pi-run.js +749 -0
- package/dist/src/core/attested-pi-run.js.map +1 -0
- package/dist/src/core/canonical-json.js +19 -0
- package/dist/src/core/canonical-json.js.map +1 -0
- package/dist/src/core/common.js +787 -0
- package/dist/src/core/common.js.map +1 -0
- package/dist/src/core/config.js +78 -0
- package/dist/src/core/config.js.map +1 -0
- package/dist/src/core/context/parent-snapshot.js +75 -0
- package/dist/src/core/context/parent-snapshot.js.map +1 -0
- package/dist/src/core/context/token-budget.js +631 -0
- package/dist/src/core/context/token-budget.js.map +1 -0
- package/dist/src/core/context/visible-conversation-v2.js +390 -0
- package/dist/src/core/context/visible-conversation-v2.js.map +1 -0
- package/dist/src/core/delegate/artifacts.js +357 -0
- package/dist/src/core/delegate/artifacts.js.map +1 -0
- package/dist/src/core/delegate/budget.js +266 -0
- package/dist/src/core/delegate/budget.js.map +1 -0
- package/dist/src/core/delegate/facade-contract.js +7 -0
- package/dist/src/core/delegate/facade-contract.js.map +1 -0
- package/dist/src/core/delegate/hook-contract-evidence.json +18 -0
- package/dist/src/core/delegate/hook-contract.js +124 -0
- package/dist/src/core/delegate/hook-contract.js.map +1 -0
- package/dist/src/core/delegate/launch.js +366 -0
- package/dist/src/core/delegate/launch.js.map +1 -0
- package/dist/src/core/delegate/result-package.js +293 -0
- package/dist/src/core/delegate/result-package.js.map +1 -0
- package/dist/src/core/delegate/runner.js +398 -0
- package/dist/src/core/delegate/runner.js.map +1 -0
- package/dist/src/core/delegate/seed.js +334 -0
- package/dist/src/core/delegate/seed.js.map +1 -0
- package/dist/src/core/delegate/types.js +103 -0
- package/dist/src/core/delegate/types.js.map +1 -0
- package/dist/src/core/durable-fs.js +372 -0
- package/dist/src/core/durable-fs.js.map +1 -0
- package/dist/src/core/extension-api.js +382 -0
- package/dist/src/core/extension-api.js.map +1 -0
- package/dist/src/core/fusion/artifacts.js +654 -0
- package/dist/src/core/fusion/artifacts.js.map +1 -0
- package/dist/src/core/fusion/budget.js +949 -0
- package/dist/src/core/fusion/budget.js.map +1 -0
- package/dist/src/core/fusion/child-protocol.js +176 -0
- package/dist/src/core/fusion/child-protocol.js.map +1 -0
- package/dist/src/core/fusion/claude-cache.js +156 -0
- package/dist/src/core/fusion/claude-cache.js.map +1 -0
- package/dist/src/core/fusion/clean-context.js +64 -0
- package/dist/src/core/fusion/clean-context.js.map +1 -0
- package/dist/src/core/fusion/config.js +349 -0
- package/dist/src/core/fusion/config.js.map +1 -0
- package/dist/src/core/fusion/context.js +184 -0
- package/dist/src/core/fusion/context.js.map +1 -0
- package/dist/src/core/fusion/evaluation.js +696 -0
- package/dist/src/core/fusion/evaluation.js.map +1 -0
- package/dist/src/core/fusion/facade-contract.js +3 -0
- package/dist/src/core/fusion/facade-contract.js.map +1 -0
- package/dist/src/core/fusion/orchestrator.js +867 -0
- package/dist/src/core/fusion/orchestrator.js.map +1 -0
- package/dist/src/core/fusion/output-contract.js +27 -0
- package/dist/src/core/fusion/output-contract.js.map +1 -0
- package/dist/src/core/fusion/pi-child.js +1741 -0
- package/dist/src/core/fusion/pi-child.js.map +1 -0
- package/dist/src/core/fusion/prompts.js +260 -0
- package/dist/src/core/fusion/prompts.js.map +1 -0
- package/dist/src/core/fusion/result-package.js +857 -0
- package/dist/src/core/fusion/result-package.js.map +1 -0
- package/dist/src/core/fusion/source-policy.js +259 -0
- package/dist/src/core/fusion/source-policy.js.map +1 -0
- package/dist/src/core/fusion/types.js +207 -0
- package/dist/src/core/fusion/types.js.map +1 -0
- package/dist/src/core/fusion/web-fetch.js +777 -0
- package/dist/src/core/fusion/web-fetch.js.map +1 -0
- package/dist/src/core/fusion/workflows.js +126 -0
- package/dist/src/core/fusion/workflows.js.map +1 -0
- package/dist/src/core/lazy-module.js +181 -0
- package/dist/src/core/lazy-module.js.map +1 -0
- package/dist/src/core/pi-launch.js +431 -0
- package/dist/src/core/pi-launch.js.map +1 -0
- package/dist/src/core/registry.js +3331 -0
- package/dist/src/core/registry.js.map +1 -0
- package/dist/src/core/reload-shell-owner.js +1396 -0
- package/dist/src/core/reload-shell-owner.js.map +1 -0
- package/dist/src/core/shell-policy.js +80 -0
- package/dist/src/core/shell-policy.js.map +1 -0
- package/dist/src/core/task-durable.js +51 -0
- package/dist/src/core/task-durable.js.map +1 -0
- package/dist/src/core/update-check.js +92 -0
- package/dist/src/core/update-check.js.map +1 -0
- package/dist/src/core/windows-taskkill.js +185 -0
- package/dist/src/core/windows-taskkill.js.map +1 -0
- package/dist/src/delegate-child-extension.js +776 -0
- package/dist/src/delegate-child-extension.js.map +1 -0
- package/dist/src/delegate-extension.js +746 -0
- package/dist/src/delegate-extension.js.map +1 -0
- package/dist/src/extension.js +953 -0
- package/dist/src/extension.js.map +1 -0
- package/dist/src/fusion-child-extension.js +760 -0
- package/dist/src/fusion-child-extension.js.map +1 -0
- package/dist/src/fusion-extension.js +1030 -0
- package/dist/src/fusion-extension.js.map +1 -0
- package/dist/src/ui/background-tasks-manager.js +689 -0
- package/dist/src/ui/background-tasks-manager.js.map +1 -0
- package/dist/src/ui/fusion-model-selector.js +277 -0
- package/dist/src/ui/fusion-model-selector.js.map +1 -0
- package/docs/INDEX.md +35 -33
- package/docs/api/eventbus-v1.md +21 -5
- package/docs/choose-a-workflow.md +2 -0
- package/docs/commands/bg-clear.md +3 -3
- package/docs/commands/bg-update.md +3 -3
- package/docs/commands/bg.md +18 -6
- package/docs/commands/claude-cache.md +4 -4
- package/docs/commands/fusion-models.md +49 -4
- package/docs/commands/fusion.md +3 -3
- package/docs/commands/jobs.md +3 -3
- package/docs/commands/kill.md +3 -3
- package/docs/commands/logs.md +3 -3
- package/docs/commands/task-manager.md +5 -5
- package/docs/concepts/completion-delivery.md +6 -2
- package/docs/getting-started.md +7 -1
- package/docs/manifest.json +228 -42
- package/docs/operations/configuration.md +58 -5
- package/docs/operations/releasing.md +4 -2
- package/docs/operations/testing.md +22 -0
- package/docs/operations/troubleshooting.md +6 -2
- package/docs/read-before-edit.md +44 -31
- package/docs/reference/runtime-contracts.md +87 -51
- package/docs/reference/shortcuts-and-dock.md +28 -14
- package/docs/subsystems/anthropic-attribution.md +23 -11
- package/docs/subsystems/attested-pi-runs.md +12 -7
- package/docs/subsystems/background-task-runtime.md +53 -11
- package/docs/subsystems/child-launch-durability-and-safety.md +28 -9
- package/docs/subsystems/delegation.md +16 -3
- package/docs/subsystems/docs-freshness-gate.md +14 -7
- package/docs/subsystems/fusion.md +36 -11
- package/docs/subsystems/host-ui-and-telemetry.md +22 -9
- package/docs/tools/bg_delegate.md +3 -1
- package/docs/tools/bg_kill.md +3 -1
- package/docs/tools/bg_logs.md +3 -1
- package/docs/tools/bg_result.md +5 -3
- package/docs/tools/bg_run.md +31 -5
- package/docs/tools/bg_run_pi_attested.md +3 -1
- package/docs/tools/bg_status.md +3 -1
- package/docs/tools/fusion_investigate.md +3 -1
- package/docs/tools/fusion_reason.md +3 -1
- package/docs/tools/fusion_research.md +3 -1
- package/docs/tools/fusion_validate.md +3 -1
- package/extensions/anthropic-attribution-child.ts +3 -0
- package/extensions/anthropic-attribution.ts +166 -1
- package/package.json +12 -10
- package/src/core/anthropic-attribution-path.ts +5 -4
- package/src/core/anthropic-attribution.ts +293 -113
- package/src/core/attested-pi-contract.ts +4 -0
- package/src/core/attested-pi-run.ts +468 -81
- package/src/core/canonical-json.ts +21 -0
- package/src/core/common.ts +450 -40
- package/src/core/config.ts +121 -0
- package/src/core/context/visible-conversation-v2.ts +3 -6
- package/src/core/delegate/artifacts.ts +13 -9
- package/src/core/delegate/budget.ts +13 -6
- package/src/core/delegate/facade-contract.ts +6 -0
- package/src/core/delegate/result-package.ts +32 -14
- package/src/core/delegate/runner.ts +129 -58
- package/src/core/delegate/seed.ts +5 -7
- package/src/core/durable-fs.ts +178 -30
- package/src/core/extension-api.ts +36 -8
- package/src/core/fusion/artifacts.ts +17 -16
- package/src/core/fusion/clean-context.ts +8 -5
- package/src/core/fusion/config.ts +2 -1
- package/src/core/fusion/context.ts +2 -6
- package/src/core/fusion/facade-contract.ts +2 -0
- package/src/core/fusion/orchestrator.ts +3 -3
- package/src/core/fusion/prompts.ts +1 -1
- package/src/core/fusion/result-package.ts +259 -72
- package/src/core/fusion/source-policy.ts +43 -17
- package/src/core/lazy-module.ts +215 -0
- package/src/core/pi-launch.ts +390 -65
- package/src/core/registry.ts +2010 -381
- package/src/core/reload-shell-owner.ts +1662 -0
- package/src/core/shell-policy.ts +134 -0
- package/src/core/task-durable.ts +67 -0
- package/src/delegate-extension.ts +404 -144
- package/src/extension.ts +387 -114
- package/src/fusion-extension.ts +202 -96
package/src/core/common.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { statSync, type WriteStream } from 'node:fs';
|
|
1
|
+
import { accessSync, constants, statSync, type WriteStream } from 'node:fs';
|
|
2
2
|
import { open } from 'node:fs/promises';
|
|
3
|
-
import { extname, isAbsolute, join, win32 } from 'node:path';
|
|
3
|
+
import { basename, delimiter, extname, isAbsolute, join, resolve, win32 } from 'node:path';
|
|
4
4
|
import { DEFAULT_MAX_BYTES } from '@earendil-works/pi-coding-agent';
|
|
5
5
|
import type { BackgroundTaskChildProcess } from './registry.js';
|
|
6
6
|
import type { DelegateBudgetRouteSource, DelegateExtensionMode } from './delegate/types.js';
|
|
@@ -12,6 +12,44 @@ export const TERMINAL_TASK_STATUS_VALUES = ['completed', 'failed', 'killed'] as
|
|
|
12
12
|
export type TaskStatus = (typeof TASK_STATUS_VALUES)[number];
|
|
13
13
|
export type TerminalTaskStatus = (typeof TERMINAL_TASK_STATUS_VALUES)[number];
|
|
14
14
|
export type KillKind = 'user' | 'timeout' | 'output_cap' | 'shutdown';
|
|
15
|
+
export type ReloadShellStopKind = KillKind | 'handoff_expired';
|
|
16
|
+
|
|
17
|
+
export type TerminalPublicationState = 'pending' | 'delivered' | 'abandoned';
|
|
18
|
+
export type TerminalPublicationAbandonReason =
|
|
19
|
+
| 'registry_shutdown'
|
|
20
|
+
| 'publisher_closed'
|
|
21
|
+
| 'gate_rejected'
|
|
22
|
+
| 'retry_exhausted'
|
|
23
|
+
| 'retention_limit'
|
|
24
|
+
| 'reload_handoff_expired';
|
|
25
|
+
|
|
26
|
+
export type ReloadSurvivalErrorCode =
|
|
27
|
+
| 'pi_bg_survive_reload_invalid'
|
|
28
|
+
| 'pi_bg_survive_reload_requires_non_agent'
|
|
29
|
+
| 'pi_bg_survive_reload_unsupported_task_kind'
|
|
30
|
+
| 'pi_bg_reload_owner_unavailable'
|
|
31
|
+
| 'pi_bg_reload_owner_protocol_incompatible'
|
|
32
|
+
| 'pi_bg_reload_owner_activation_conflict'
|
|
33
|
+
| 'pi_bg_reload_owner_stale_claim'
|
|
34
|
+
| 'pi_bg_reload_handoff_expired';
|
|
35
|
+
|
|
36
|
+
export class ReloadSurvivalError extends Error {
|
|
37
|
+
constructor(
|
|
38
|
+
readonly code: ReloadSurvivalErrorCode,
|
|
39
|
+
message: string,
|
|
40
|
+
) {
|
|
41
|
+
super(`${code}: ${message}`);
|
|
42
|
+
this.name = 'ReloadSurvivalError';
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function rejectSurvivalForTaskKind(value: object, kind: string): void {
|
|
47
|
+
if (!Object.prototype.hasOwnProperty.call(value, 'surviveReload')) return;
|
|
48
|
+
throw new ReloadSurvivalError(
|
|
49
|
+
'pi_bg_survive_reload_unsupported_task_kind',
|
|
50
|
+
`${kind} does not support surviveReload; only ordinary isAgent:false shell tasks may survive reload`,
|
|
51
|
+
);
|
|
52
|
+
}
|
|
15
53
|
|
|
16
54
|
export type JsonObject = Readonly<Record<PropertyKey, unknown>>;
|
|
17
55
|
|
|
@@ -36,6 +74,150 @@ export interface TaskToolUsage {
|
|
|
36
74
|
byName: Record<string, number>;
|
|
37
75
|
}
|
|
38
76
|
|
|
77
|
+
export interface ReloadSurvivalSnapshotV1 {
|
|
78
|
+
schemaVersion: 'pi-background-tasks.reload-shell.v1';
|
|
79
|
+
authority: 'same-process-live-owner';
|
|
80
|
+
hostPid: number;
|
|
81
|
+
sessionId: string;
|
|
82
|
+
cwdRealpath: string;
|
|
83
|
+
launchNonce: string;
|
|
84
|
+
completionId: string;
|
|
85
|
+
spawnedAt: number;
|
|
86
|
+
childPid: number;
|
|
87
|
+
timeoutDeadlineAt?: number | undefined;
|
|
88
|
+
outputCapBytes: number;
|
|
89
|
+
posixProcessGroupId?: number | undefined;
|
|
90
|
+
windowsTreeRootPid?: number | undefined;
|
|
91
|
+
leaseGeneration: number;
|
|
92
|
+
handoffCount: number;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface ReloadShellIdentityV1 {
|
|
96
|
+
readonly hostPid: number;
|
|
97
|
+
readonly sessionId: string;
|
|
98
|
+
readonly cwdRealpath: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface ReloadShellActivationLeaseV1 {
|
|
102
|
+
readonly protocol: 'pi-background-tasks.reload-shell-owner.v1';
|
|
103
|
+
readonly hubNonce: string;
|
|
104
|
+
readonly identityKey: string;
|
|
105
|
+
readonly generation: number;
|
|
106
|
+
readonly activationNonce: string;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface ReloadShellActivationClaimV1 {
|
|
110
|
+
readonly protocol: 'pi-background-tasks.reload-shell-owner.v1';
|
|
111
|
+
readonly hubNonce: string;
|
|
112
|
+
readonly claimNonce: string;
|
|
113
|
+
readonly identity: ReloadShellIdentityV1;
|
|
114
|
+
readonly identityKey: string;
|
|
115
|
+
readonly generation: number;
|
|
116
|
+
readonly activationNonce: string;
|
|
117
|
+
readonly expiresAt?: number | undefined;
|
|
118
|
+
readonly executions: readonly ReloadableShellExecutionV1[];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export interface ReloadShellProcessV1 {
|
|
122
|
+
readonly pid?: number | undefined;
|
|
123
|
+
stdout?: {
|
|
124
|
+
on(event: 'data', listener: (data: Buffer | string) => void): unknown;
|
|
125
|
+
off?(event: 'data', listener: (data: Buffer | string) => void): unknown;
|
|
126
|
+
} | null | undefined;
|
|
127
|
+
stderr?: {
|
|
128
|
+
on(event: 'data', listener: (data: Buffer | string) => void): unknown;
|
|
129
|
+
off?(event: 'data', listener: (data: Buffer | string) => void): unknown;
|
|
130
|
+
} | null | undefined;
|
|
131
|
+
kill(signal?: NodeJS.Signals): boolean;
|
|
132
|
+
on(event: 'error', listener: (error: Error) => void): unknown;
|
|
133
|
+
on(
|
|
134
|
+
event: 'close',
|
|
135
|
+
listener: (code: number | null, signal: NodeJS.Signals | null) => void,
|
|
136
|
+
): unknown;
|
|
137
|
+
off?(event: 'error', listener: (error: Error) => void): unknown;
|
|
138
|
+
off?(
|
|
139
|
+
event: 'close',
|
|
140
|
+
listener: (code: number | null, signal: NodeJS.Signals | null) => void,
|
|
141
|
+
): unknown;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export interface ReloadShellOwnerEventSinkV1 {
|
|
145
|
+
readonly onChanged: (execution: ReloadableShellExecutionV1) => void;
|
|
146
|
+
readonly onTerminal: (execution: ReloadableShellExecutionV1) => void;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export type ReloadShellNotificationState = 'disabled' | 'pending' | 'sending' | 'delivered';
|
|
150
|
+
|
|
151
|
+
export interface ReloadableShellExecutionV1 {
|
|
152
|
+
readonly protocol: 'pi-background-tasks.reload-shell-owner.v1';
|
|
153
|
+
readonly launchNonce: string;
|
|
154
|
+
readonly completionId: string;
|
|
155
|
+
readonly task: BgTask;
|
|
156
|
+
child: ReloadShellProcessV1 | undefined;
|
|
157
|
+
outputStream: WriteStream | undefined;
|
|
158
|
+
readonly spawnedAt: number;
|
|
159
|
+
readonly timeoutDeadlineAt?: number | undefined;
|
|
160
|
+
readonly outputCapBytes: number;
|
|
161
|
+
readonly terminal: Promise<BgTask>;
|
|
162
|
+
readonly requestStop: (kind: ReloadShellStopKind, reason?: string) => Promise<BgTask>;
|
|
163
|
+
phase: 'starting' | 'running' | 'stop_requested' | 'finalizing' | 'terminal' | 'released';
|
|
164
|
+
closeObservation?: {
|
|
165
|
+
code: number | null;
|
|
166
|
+
signal: NodeJS.Signals | null;
|
|
167
|
+
observedAt: number;
|
|
168
|
+
} | undefined;
|
|
169
|
+
admissionCommitted: boolean;
|
|
170
|
+
notificationState: ReloadShellNotificationState;
|
|
171
|
+
readonly commitInitialMetadata: (signal?: AbortSignal) => Promise<void>;
|
|
172
|
+
readonly failAdmission: (error: Error) => void;
|
|
173
|
+
readonly setOwnerEventSink: (sink: ReloadShellOwnerEventSinkV1 | undefined) => void;
|
|
174
|
+
readonly markAdmissionCommitted: (generation: number, handoffCount: number) => void;
|
|
175
|
+
readonly updateLeaseAudit: (generation: number, handoffCount: number) => void;
|
|
176
|
+
readonly abandonReloadHandoff: () => void;
|
|
177
|
+
readonly beginNotification: (lease: ReloadShellActivationLeaseV1) => string | undefined;
|
|
178
|
+
readonly finishNotification: (token: string, delivered: boolean) => void;
|
|
179
|
+
readonly releaseResources: () => void;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export interface ReloadShellHostAdapterV1 {
|
|
183
|
+
readonly activationNonce: string;
|
|
184
|
+
readonly onBound: (lease: ReloadShellActivationLeaseV1) => void;
|
|
185
|
+
readonly onChanged: (execution: ReloadableShellExecutionV1) => void;
|
|
186
|
+
readonly onTerminal: (execution: ReloadableShellExecutionV1) => void;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export interface ReloadShellOwnerHubV1 {
|
|
190
|
+
readonly protocol: 'pi-background-tasks.reload-shell-owner.v1';
|
|
191
|
+
readonly hubNonce: string;
|
|
192
|
+
beginActivation(
|
|
193
|
+
identity: ReloadShellIdentityV1,
|
|
194
|
+
startReason: string,
|
|
195
|
+
activationNonce: string,
|
|
196
|
+
): ReloadShellActivationClaimV1;
|
|
197
|
+
commitActivation(
|
|
198
|
+
claim: ReloadShellActivationClaimV1,
|
|
199
|
+
adapter: ReloadShellHostAdapterV1,
|
|
200
|
+
): ReloadShellActivationLeaseV1;
|
|
201
|
+
abortActivation(claim: ReloadShellActivationClaimV1, error: unknown): void;
|
|
202
|
+
beginReloadHandoff(
|
|
203
|
+
lease: ReloadShellActivationLeaseV1,
|
|
204
|
+
): readonly ReloadableShellExecutionV1[];
|
|
205
|
+
releaseActivation(lease: ReloadShellActivationLeaseV1): void;
|
|
206
|
+
registerExecution(
|
|
207
|
+
lease: ReloadShellActivationLeaseV1,
|
|
208
|
+
execution: ReloadableShellExecutionV1,
|
|
209
|
+
): void;
|
|
210
|
+
markAdmissionCommitted(
|
|
211
|
+
lease: ReloadShellActivationLeaseV1,
|
|
212
|
+
execution: ReloadableShellExecutionV1,
|
|
213
|
+
): void;
|
|
214
|
+
releaseExecution(
|
|
215
|
+
leaseOrClaim: ReloadShellActivationLeaseV1 | ReloadShellActivationClaimV1,
|
|
216
|
+
execution: ReloadableShellExecutionV1,
|
|
217
|
+
): void;
|
|
218
|
+
isCurrentLease(lease: ReloadShellActivationLeaseV1): boolean;
|
|
219
|
+
}
|
|
220
|
+
|
|
39
221
|
export interface BgTaskSnapshot {
|
|
40
222
|
id: string;
|
|
41
223
|
name?: string | undefined;
|
|
@@ -51,6 +233,8 @@ export interface BgTaskSnapshot {
|
|
|
51
233
|
pid?: number | undefined;
|
|
52
234
|
bytesWritten: number;
|
|
53
235
|
isAgent: boolean;
|
|
236
|
+
surviveReload: boolean;
|
|
237
|
+
reloadSurvival?: ReloadSurvivalSnapshotV1 | undefined;
|
|
54
238
|
error?: string | undefined;
|
|
55
239
|
notified: boolean;
|
|
56
240
|
notifyOnCompletion: boolean;
|
|
@@ -61,6 +245,8 @@ export interface BgTaskSnapshot {
|
|
|
61
245
|
toolUsage?: TaskToolUsage | undefined;
|
|
62
246
|
model?: string | undefined;
|
|
63
247
|
telemetryUnavailableReason?: string | undefined;
|
|
248
|
+
/** Immutable non-secret shell selection for ordinary shell tasks. */
|
|
249
|
+
shellPolicy?: ShellPolicySnapshot | undefined;
|
|
64
250
|
attestationPath?: string | undefined;
|
|
65
251
|
delegate?: DelegateTaskFacts | undefined;
|
|
66
252
|
fusion?: FusionTaskFacts | undefined;
|
|
@@ -130,6 +316,10 @@ export interface BgTask extends Omit<BgTaskSnapshot, 'name'> {
|
|
|
130
316
|
wrapperAbsPath?: string | undefined;
|
|
131
317
|
attestationAbsPath?: string | undefined;
|
|
132
318
|
child?: BackgroundTaskChildProcess | undefined;
|
|
319
|
+
/** Immutable in-memory ownership captured from a detached POSIX spawn; never restored from metadata. */
|
|
320
|
+
ownedPosixProcessGroupId?: number | undefined;
|
|
321
|
+
/** One-way latch preventing any later signal after group authority is released. */
|
|
322
|
+
posixProcessGroupSignalAuthorityReleased?: boolean | undefined;
|
|
133
323
|
stream?: WriteStream | undefined;
|
|
134
324
|
timeoutHandle?: NodeJS.Timeout | undefined;
|
|
135
325
|
killKind?: KillKind | undefined;
|
|
@@ -137,8 +327,14 @@ export interface BgTask extends Omit<BgTaskSnapshot, 'name'> {
|
|
|
137
327
|
killEscalationTimer?: NodeJS.Timeout | undefined;
|
|
138
328
|
capExceeded?: boolean | undefined;
|
|
139
329
|
finalized?: boolean | undefined;
|
|
140
|
-
|
|
330
|
+
/** True only after the terminal EventBus emitter returns successfully; abandonment is never delivery. */
|
|
331
|
+
terminalPublished: boolean;
|
|
332
|
+
terminalPublicationState: TerminalPublicationState;
|
|
333
|
+
terminalPublicationAbandonReason?: TerminalPublicationAbandonReason | undefined;
|
|
334
|
+
terminalPublishAttempts: number;
|
|
141
335
|
terminalPublishInFlight?: boolean | undefined;
|
|
336
|
+
/** True only while the synchronous terminal emitter itself is on the stack. */
|
|
337
|
+
terminalEmitInFlight?: boolean | undefined;
|
|
142
338
|
terminalPublishRetryHandle?: NodeJS.Timeout | undefined;
|
|
143
339
|
/** Optional protocol barrier used by EventBus run requests so early child exits cannot publish before the run response is observable. */
|
|
144
340
|
terminalPublicationGate?: Promise<void> | undefined;
|
|
@@ -152,6 +348,12 @@ export interface BgTask extends Omit<BgTaskSnapshot, 'name'> {
|
|
|
152
348
|
attestedPi?: AttestedPiTaskFiles | undefined;
|
|
153
349
|
delegate?: DelegateTaskFacts | undefined;
|
|
154
350
|
fusion?: FusionTaskFacts | undefined;
|
|
351
|
+
/** In-memory same-process authority for an opted ordinary shell task; never serialized. */
|
|
352
|
+
reloadExecution?: ReloadableShellExecutionV1 | undefined;
|
|
353
|
+
/** Fresh-registry terminal host delivery state for an imported owner execution. */
|
|
354
|
+
reloadHostDeliveryInFlight?: boolean | undefined;
|
|
355
|
+
reloadHostDeliverySettled?: boolean | undefined;
|
|
356
|
+
reloadHostNotificationSettled?: boolean | undefined;
|
|
155
357
|
/** Cancellation hook for an in-process managed task such as Fusion. */
|
|
156
358
|
managedCancel?: (() => void) | undefined;
|
|
157
359
|
managedCancelRequested?: boolean | undefined;
|
|
@@ -248,6 +450,7 @@ export interface StartTaskOptions {
|
|
|
248
450
|
timeoutSeconds?: number | undefined;
|
|
249
451
|
notifyOnCompletion?: boolean | undefined;
|
|
250
452
|
triggerOnCompletion?: boolean | undefined;
|
|
453
|
+
surviveReload?: boolean | undefined;
|
|
251
454
|
/** @internal EventBus protocol barrier; callers should not set this outside the extension service. */
|
|
252
455
|
terminalPublicationGate?: Promise<void> | undefined;
|
|
253
456
|
}
|
|
@@ -407,10 +610,12 @@ export function parseBgCommandArgs(args: string): {
|
|
|
407
610
|
name?: string;
|
|
408
611
|
command: string;
|
|
409
612
|
isAgent: boolean;
|
|
613
|
+
surviveReload: boolean;
|
|
410
614
|
} {
|
|
411
615
|
let input = args.trim();
|
|
412
616
|
let name: string | undefined;
|
|
413
617
|
let isAgent = false;
|
|
618
|
+
let surviveReload = false;
|
|
414
619
|
|
|
415
620
|
while (input) {
|
|
416
621
|
let consumed = false;
|
|
@@ -458,6 +663,28 @@ export function parseBgCommandArgs(args: string): {
|
|
|
458
663
|
}
|
|
459
664
|
if (consumed) continue;
|
|
460
665
|
|
|
666
|
+
if (
|
|
667
|
+
input === '--survive-reload' ||
|
|
668
|
+
input.startsWith('--survive-reload ') ||
|
|
669
|
+
input.startsWith('--survive-reload\t')
|
|
670
|
+
) {
|
|
671
|
+
if (surviveReload) {
|
|
672
|
+
throw new ReloadSurvivalError(
|
|
673
|
+
'pi_bg_survive_reload_invalid',
|
|
674
|
+
'/bg accepts --survive-reload at most once',
|
|
675
|
+
);
|
|
676
|
+
}
|
|
677
|
+
surviveReload = true;
|
|
678
|
+
input = input.slice('--survive-reload'.length).trimStart();
|
|
679
|
+
continue;
|
|
680
|
+
}
|
|
681
|
+
if (input.startsWith('--survive-reload=')) {
|
|
682
|
+
throw new ReloadSurvivalError(
|
|
683
|
+
'pi_bg_survive_reload_invalid',
|
|
684
|
+
'/bg accepts only the bare --survive-reload flag',
|
|
685
|
+
);
|
|
686
|
+
}
|
|
687
|
+
|
|
461
688
|
if (input === '--') {
|
|
462
689
|
input = '';
|
|
463
690
|
break;
|
|
@@ -469,7 +696,15 @@ export function parseBgCommandArgs(args: string): {
|
|
|
469
696
|
break;
|
|
470
697
|
}
|
|
471
698
|
|
|
472
|
-
|
|
699
|
+
if (surviveReload && isAgent) {
|
|
700
|
+
throw new ReloadSurvivalError(
|
|
701
|
+
'pi_bg_survive_reload_requires_non_agent',
|
|
702
|
+
'surviveReload requires isAgent:false',
|
|
703
|
+
);
|
|
704
|
+
}
|
|
705
|
+
return name
|
|
706
|
+
? { name, command: input, isAgent, surviveReload }
|
|
707
|
+
: { command: input, isAgent, surviveReload };
|
|
473
708
|
}
|
|
474
709
|
|
|
475
710
|
export function formatDuration(ms: number): string {
|
|
@@ -611,7 +846,23 @@ export function shellQuote(value: string): string {
|
|
|
611
846
|
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
612
847
|
}
|
|
613
848
|
|
|
614
|
-
export type ShellDialect = 'cmd' | 'posix';
|
|
849
|
+
export type ShellDialect = 'cmd' | 'posix' | 'user-non-posix';
|
|
850
|
+
export type ShellPolicyDialect = ShellDialect | 'bash';
|
|
851
|
+
export type ShellPolicyName = 'inherit' | 'bash' | 'sh' | 'cmd';
|
|
852
|
+
|
|
853
|
+
/** Non-secret launch facts persisted for ordinary shell tasks. */
|
|
854
|
+
export interface ShellPolicySnapshot {
|
|
855
|
+
readonly policy: ShellPolicyName;
|
|
856
|
+
readonly executable: string;
|
|
857
|
+
readonly argvPrefix: readonly string[];
|
|
858
|
+
readonly dialect: ShellPolicyDialect;
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
/** One immutable shell selection shared by guidance and every ordinary spawn in an activation. */
|
|
862
|
+
export interface ResolvedShellPolicy extends ShellPolicySnapshot {
|
|
863
|
+
readonly supportsPosixFunctionWrapper: boolean;
|
|
864
|
+
readonly windowsVerbatimArguments: boolean;
|
|
865
|
+
}
|
|
615
866
|
|
|
616
867
|
export interface ShellInvocation {
|
|
617
868
|
shell: string;
|
|
@@ -633,6 +884,19 @@ type ShellCandidateResult =
|
|
|
633
884
|
| { readonly found: true }
|
|
634
885
|
| { readonly found: false; readonly diagnostic: string };
|
|
635
886
|
|
|
887
|
+
const POSIX_FUNCTION_SHELLS = new Set([
|
|
888
|
+
'sh',
|
|
889
|
+
'dash',
|
|
890
|
+
'ash',
|
|
891
|
+
'ksh',
|
|
892
|
+
'ksh93',
|
|
893
|
+
'mksh',
|
|
894
|
+
'pdksh',
|
|
895
|
+
'zsh',
|
|
896
|
+
'yash',
|
|
897
|
+
'posh',
|
|
898
|
+
]);
|
|
899
|
+
|
|
636
900
|
function failShellInvocation(message: string): never {
|
|
637
901
|
throw new ShellInvocationError(message);
|
|
638
902
|
}
|
|
@@ -641,6 +905,24 @@ function shellErrorMessage(error: unknown): string {
|
|
|
641
905
|
return error instanceof Error ? error.message : String(error);
|
|
642
906
|
}
|
|
643
907
|
|
|
908
|
+
function freezeShellPolicy(
|
|
909
|
+
policy: Omit<ResolvedShellPolicy, 'argvPrefix'> & { argvPrefix: readonly string[] },
|
|
910
|
+
): ResolvedShellPolicy {
|
|
911
|
+
return Object.freeze({
|
|
912
|
+
...policy,
|
|
913
|
+
argvPrefix: Object.freeze([...policy.argvPrefix]),
|
|
914
|
+
});
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
export function shellPolicySnapshot(policy: ResolvedShellPolicy): ShellPolicySnapshot {
|
|
918
|
+
return Object.freeze({
|
|
919
|
+
policy: policy.policy,
|
|
920
|
+
executable: policy.executable,
|
|
921
|
+
argvPrefix: Object.freeze([...policy.argvPrefix]),
|
|
922
|
+
dialect: policy.dialect,
|
|
923
|
+
});
|
|
924
|
+
}
|
|
925
|
+
|
|
644
926
|
function isWindowsExecutablePath(path: string): boolean {
|
|
645
927
|
const extension = extname(path).toLowerCase();
|
|
646
928
|
return extension === '.exe' || extension === '.com';
|
|
@@ -696,51 +978,176 @@ function resolveWindowsBash(env: NodeJS.ProcessEnv): string {
|
|
|
696
978
|
failShellInvocation(`PI_BG_SHELL=bash could not resolve bash.exe or bash.com on PATH${suffix}`);
|
|
697
979
|
}
|
|
698
980
|
|
|
699
|
-
function
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
}
|
|
981
|
+
function validatePosixShellPath(path: string, label: string): string {
|
|
982
|
+
if (path.length === 0) failShellInvocation(`${label} is empty`);
|
|
983
|
+
if (!isAbsolute(path)) failShellInvocation(`${label} must be an absolute path`);
|
|
984
|
+
let stats: ReturnType<typeof statSync>;
|
|
985
|
+
try {
|
|
986
|
+
stats = statSync(path);
|
|
987
|
+
} catch (error) {
|
|
988
|
+
failShellInvocation(`${label} stat failed: ${shellErrorMessage(error)}`);
|
|
989
|
+
}
|
|
990
|
+
if (!stats.isFile()) failShellInvocation(`${label} must point to a regular file`);
|
|
991
|
+
try {
|
|
992
|
+
accessSync(path, constants.X_OK);
|
|
993
|
+
} catch (error) {
|
|
994
|
+
failShellInvocation(`${label} must be executable: ${shellErrorMessage(error)}`);
|
|
995
|
+
}
|
|
996
|
+
return path;
|
|
706
997
|
}
|
|
707
998
|
|
|
708
|
-
function
|
|
709
|
-
|
|
999
|
+
function inspectPosixShellCandidate(path: string): boolean {
|
|
1000
|
+
try {
|
|
1001
|
+
const stats = statSync(path);
|
|
1002
|
+
if (!stats.isFile()) return false;
|
|
1003
|
+
accessSync(path, constants.X_OK);
|
|
1004
|
+
return true;
|
|
1005
|
+
} catch {
|
|
1006
|
+
return false;
|
|
1007
|
+
}
|
|
710
1008
|
}
|
|
711
1009
|
|
|
712
|
-
|
|
713
|
-
|
|
1010
|
+
function resolvePosixExecutable(
|
|
1011
|
+
name: 'bash' | 'sh',
|
|
1012
|
+
env: NodeJS.ProcessEnv,
|
|
1013
|
+
activationCwd: string,
|
|
1014
|
+
): string {
|
|
1015
|
+
const binCandidate = `/bin/${name}`;
|
|
1016
|
+
if (inspectPosixShellCandidate(binCandidate)) return binCandidate;
|
|
1017
|
+
const pathValue = env['PATH'] ?? '';
|
|
1018
|
+
for (const entry of pathValue.split(delimiter)) {
|
|
1019
|
+
if (entry.length === 0) continue;
|
|
1020
|
+
const directory = isAbsolute(entry) ? entry : resolve(activationCwd, entry);
|
|
1021
|
+
const candidate = join(directory, name);
|
|
1022
|
+
if (inspectPosixShellCandidate(candidate)) return candidate;
|
|
1023
|
+
}
|
|
1024
|
+
failShellInvocation(
|
|
1025
|
+
`PI_BG_POSIX_SHELL=${name} could not resolve executable ${binCandidate} or ${name} on PATH`,
|
|
1026
|
+
);
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
function inheritedPosixDialect(executable: string): ShellPolicyDialect {
|
|
1030
|
+
const name = basename(executable).toLowerCase();
|
|
1031
|
+
if (name === 'bash') return 'bash';
|
|
1032
|
+
return POSIX_FUNCTION_SHELLS.has(name) ? 'posix' : 'user-non-posix';
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
/** Resolve one activation-stable policy. New POSIX variables are intentionally ignored on Windows. */
|
|
1036
|
+
export function resolveShellPolicy(
|
|
714
1037
|
platform: NodeJS.Platform = process.platform,
|
|
715
1038
|
env: NodeJS.ProcessEnv = process.env,
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
1039
|
+
activationCwd: string = process.cwd(),
|
|
1040
|
+
): ResolvedShellPolicy {
|
|
1041
|
+
if (platform === 'win32') {
|
|
1042
|
+
const requestedShell = env['PI_BG_SHELL'];
|
|
1043
|
+
const requestedPath = env['PI_BG_SHELL_PATH'];
|
|
1044
|
+
if (requestedShell === undefined) {
|
|
1045
|
+
if (requestedPath !== undefined)
|
|
1046
|
+
failShellInvocation('PI_BG_SHELL_PATH requires PI_BG_SHELL');
|
|
1047
|
+
const comSpec = env['ComSpec'];
|
|
1048
|
+
return freezeShellPolicy({
|
|
1049
|
+
policy: 'cmd',
|
|
1050
|
+
executable: comSpec && comSpec.length > 0 ? comSpec : 'cmd.exe',
|
|
1051
|
+
argvPrefix: ['/d', '/s', '/c'],
|
|
1052
|
+
dialect: 'cmd',
|
|
1053
|
+
supportsPosixFunctionWrapper: false,
|
|
1054
|
+
windowsVerbatimArguments: true,
|
|
1055
|
+
});
|
|
1056
|
+
}
|
|
1057
|
+
if (requestedShell !== 'cmd' && requestedShell !== 'bash') {
|
|
1058
|
+
failShellInvocation('PI_BG_SHELL must be exactly cmd or bash');
|
|
1059
|
+
}
|
|
1060
|
+
const explicitPath =
|
|
1061
|
+
requestedPath !== undefined
|
|
1062
|
+
? validateWindowsShellPath(requestedPath, 'PI_BG_SHELL_PATH')
|
|
1063
|
+
: undefined;
|
|
1064
|
+
if (requestedShell === 'cmd') {
|
|
1065
|
+
const comSpec = env['ComSpec'];
|
|
1066
|
+
return freezeShellPolicy({
|
|
1067
|
+
policy: 'cmd',
|
|
1068
|
+
executable: explicitPath ?? (comSpec && comSpec.length > 0 ? comSpec : 'cmd.exe'),
|
|
1069
|
+
argvPrefix: ['/d', '/s', '/c'],
|
|
1070
|
+
dialect: 'cmd',
|
|
1071
|
+
supportsPosixFunctionWrapper: false,
|
|
1072
|
+
windowsVerbatimArguments: true,
|
|
1073
|
+
});
|
|
1074
|
+
}
|
|
1075
|
+
return freezeShellPolicy({
|
|
1076
|
+
policy: 'bash',
|
|
1077
|
+
executable: explicitPath ?? resolveWindowsBash(env),
|
|
1078
|
+
argvPrefix: ['-c'],
|
|
1079
|
+
dialect: 'bash',
|
|
1080
|
+
supportsPosixFunctionWrapper: true,
|
|
1081
|
+
windowsVerbatimArguments: false,
|
|
1082
|
+
});
|
|
720
1083
|
}
|
|
721
1084
|
|
|
722
|
-
const
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
failShellInvocation('PI_BG_SHELL must be exactly cmd or bash');
|
|
1085
|
+
const configuredPolicy = env['PI_BG_POSIX_SHELL'];
|
|
1086
|
+
if (
|
|
1087
|
+
configuredPolicy !== undefined &&
|
|
1088
|
+
configuredPolicy !== 'inherit' &&
|
|
1089
|
+
configuredPolicy !== 'bash' &&
|
|
1090
|
+
configuredPolicy !== 'sh'
|
|
1091
|
+
) {
|
|
1092
|
+
failShellInvocation('PI_BG_POSIX_SHELL must be exactly inherit, bash, or sh');
|
|
731
1093
|
}
|
|
732
|
-
const
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
1094
|
+
const policy = configuredPolicy ?? 'inherit';
|
|
1095
|
+
const configuredPath = env['PI_BG_POSIX_SHELL_PATH'];
|
|
1096
|
+
if (policy === 'inherit') {
|
|
1097
|
+
if (configuredPath !== undefined) {
|
|
1098
|
+
failShellInvocation(
|
|
1099
|
+
'PI_BG_POSIX_SHELL_PATH requires PI_BG_POSIX_SHELL=bash or PI_BG_POSIX_SHELL=sh',
|
|
1100
|
+
);
|
|
1101
|
+
}
|
|
1102
|
+
const inherited = env['SHELL'];
|
|
1103
|
+
const executable = inherited && inherited.length > 0 ? inherited : '/bin/sh';
|
|
1104
|
+
const dialect = inheritedPosixDialect(executable);
|
|
1105
|
+
return freezeShellPolicy({
|
|
1106
|
+
policy,
|
|
1107
|
+
executable,
|
|
1108
|
+
argvPrefix: ['-c'],
|
|
1109
|
+
dialect,
|
|
1110
|
+
supportsPosixFunctionWrapper: dialect === 'bash' || dialect === 'posix',
|
|
1111
|
+
windowsVerbatimArguments: false,
|
|
1112
|
+
});
|
|
742
1113
|
}
|
|
743
|
-
|
|
1114
|
+
|
|
1115
|
+
const executable =
|
|
1116
|
+
configuredPath !== undefined
|
|
1117
|
+
? validatePosixShellPath(configuredPath, 'PI_BG_POSIX_SHELL_PATH')
|
|
1118
|
+
: resolvePosixExecutable(policy, env, activationCwd);
|
|
1119
|
+
return freezeShellPolicy({
|
|
1120
|
+
policy,
|
|
1121
|
+
executable,
|
|
1122
|
+
argvPrefix: ['-c'],
|
|
1123
|
+
dialect: policy === 'bash' ? 'bash' : 'posix',
|
|
1124
|
+
supportsPosixFunctionWrapper: true,
|
|
1125
|
+
windowsVerbatimArguments: false,
|
|
1126
|
+
});
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
export function shellInvocationForPolicy(
|
|
1130
|
+
command: string,
|
|
1131
|
+
policy: ResolvedShellPolicy,
|
|
1132
|
+
): ShellInvocation {
|
|
1133
|
+
const dialect: ShellDialect = policy.dialect === 'bash' ? 'posix' : policy.dialect;
|
|
1134
|
+
return {
|
|
1135
|
+
shell: policy.executable,
|
|
1136
|
+
args:
|
|
1137
|
+
policy.dialect === 'cmd'
|
|
1138
|
+
? [...policy.argvPrefix, `"${command}"`]
|
|
1139
|
+
: [...policy.argvPrefix, command],
|
|
1140
|
+
dialect,
|
|
1141
|
+
windowsVerbatimArguments: policy.windowsVerbatimArguments,
|
|
1142
|
+
};
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
export function shellInvocation(
|
|
1146
|
+
command: string,
|
|
1147
|
+
platform: NodeJS.Platform = process.platform,
|
|
1148
|
+
env: NodeJS.ProcessEnv = process.env,
|
|
1149
|
+
): ShellInvocation {
|
|
1150
|
+
return shellInvocationForPolicy(command, resolveShellPolicy(platform, env));
|
|
744
1151
|
}
|
|
745
1152
|
|
|
746
1153
|
export function normalizeMaxBytes(value: unknown, fallback = DEFAULT_LOG_BYTES): number {
|
|
@@ -764,6 +1171,8 @@ export function snapshot(task: BgTask): BgTaskSnapshot {
|
|
|
764
1171
|
pid: task.pid,
|
|
765
1172
|
bytesWritten: task.bytesWritten,
|
|
766
1173
|
isAgent: task.isAgent,
|
|
1174
|
+
surviveReload: task.surviveReload === true,
|
|
1175
|
+
reloadSurvival: task.reloadSurvival,
|
|
767
1176
|
error: task.error,
|
|
768
1177
|
notified: task.notified,
|
|
769
1178
|
notifyOnCompletion: task.notifyOnCompletion,
|
|
@@ -774,6 +1183,7 @@ export function snapshot(task: BgTask): BgTaskSnapshot {
|
|
|
774
1183
|
toolUsage: task.toolUsage,
|
|
775
1184
|
model: task.model,
|
|
776
1185
|
telemetryUnavailableReason: task.telemetryUnavailableReason,
|
|
1186
|
+
shellPolicy: task.shellPolicy,
|
|
777
1187
|
attestationPath: task.attestationPath,
|
|
778
1188
|
delegate: task.delegate,
|
|
779
1189
|
fusion: task.fusion,
|