@pi-unipi/background-tasks 2.16.1 → 2.17.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/README.md +21 -27
- package/package.json +3 -4
- package/src/cards.ts +76 -0
- package/src/child-process.ts +1 -1
- package/src/config.ts +0 -42
- package/src/context-visible-conversation-v2.ts +1 -1
- package/src/delegate/artifacts.ts +1 -1
- package/src/delegate/launch.ts +17 -30
- package/src/delegate/result-package.ts +1 -1
- package/src/delegate/runner.ts +1 -20
- package/src/delegate/seed.ts +1 -1
- package/src/delegate-extension.ts +16 -168
- package/src/index.ts +53 -25
- package/src/json-utils.ts +56 -0
- package/src/package-assets.ts +51 -0
- package/src/registry.ts +8 -459
- package/src/task-manager.ts +13 -2
- package/src/tools.ts +4 -189
- package/src/types.ts +17 -70
- package/extensions/anthropic-attribution.ts +0 -1
- package/extensions/fusion-child.ts +0 -1
- package/src/anthropic-attribution-path.ts +0 -21
- package/src/anthropic-attribution.ts +0 -1983
- package/src/attested-pi-run.ts +0 -612
- package/src/fixtures/fusion-golden-bytes.json +0 -310
- package/src/fixtures/fusion-validate-golden-bytes.json +0 -282
- package/src/fusion/artifacts.ts +0 -967
- package/src/fusion/budget.ts +0 -1162
- package/src/fusion/child-protocol.ts +0 -305
- package/src/fusion/claude-cache.ts +0 -207
- package/src/fusion/clean-context.ts +0 -91
- package/src/fusion/config.ts +0 -449
- package/src/fusion/context.ts +0 -265
- package/src/fusion/evaluation.ts +0 -800
- package/src/fusion/orchestrator.ts +0 -1288
- package/src/fusion/output-contract.ts +0 -34
- package/src/fusion/pi-child.ts +0 -2373
- package/src/fusion/prompts.ts +0 -345
- package/src/fusion/result-package.ts +0 -959
- package/src/fusion/source-policy.ts +0 -257
- package/src/fusion/types.ts +0 -1139
- package/src/fusion/web-fetch.ts +0 -1060
- package/src/fusion/workflows.ts +0 -184
- package/src/fusion-child-extension.ts +0 -1052
- package/src/fusion-extension.ts +0 -1293
- package/src/ui/fusion-model-selector.ts +0 -322
package/README.md
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# @pi-unipi/background-tasks
|
|
2
2
|
|
|
3
|
-
Background tasks for UniPi —
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Anthropic
|
|
3
|
+
Background tasks for UniPi — durable background shell jobs plus one read-only
|
|
4
|
+
delegated background agent, with a footer dock the user can manage while the
|
|
5
|
+
agent keeps working. Originally adopted from
|
|
6
|
+
[pi-background-tasks](https://github.com/ismailsaleekh/pi-background-tasks);
|
|
7
|
+
the Fusion council, attested Pi runs, and Anthropic attribution surfaces were
|
|
8
|
+
removed in 2.17.0 so the module does exactly one thing.
|
|
8
9
|
|
|
9
10
|
## Master toggle
|
|
10
11
|
|
|
@@ -19,37 +20,37 @@ One config key disables the entire module — no tools, no commands, no hooks, n
|
|
|
19
20
|
```
|
|
20
21
|
|
|
21
22
|
Open `/unipi:bg-settings` for the interactive settings overlay (master toggle,
|
|
22
|
-
defaults, output caps, delegate
|
|
23
|
+
defaults, output caps, delegate defaults).
|
|
23
24
|
|
|
24
25
|
## Surfaces
|
|
25
26
|
|
|
26
|
-
### Tools
|
|
27
|
+
### Tools
|
|
27
28
|
|
|
28
29
|
| Tool | Purpose |
|
|
29
30
|
| --- | --- |
|
|
30
31
|
| `bg_run` | Start a named long-running shell command; terminal notification wakes a follow-up turn by default |
|
|
31
32
|
| `bg_status` / `bg_logs` / `bg_kill` | Point-in-time inspection, bounded log reads, stop — never polling primitives |
|
|
32
33
|
| `bg_delegate` + `bg_result` | One read-only child Pi agent seeded with a frozen projection of this conversation; hash-verified answer retrieval |
|
|
33
|
-
| `bg_run_pi_attested` | Evidence-oriented direct Pi spawn with local hashes and route attestation |
|
|
34
|
-
| `fusion_reason` | 3 candidates → blind evaluator → merger on the session projection |
|
|
35
|
-
| `fusion_investigate` / `fusion_research` / `fusion_validate` | Fixed-purpose multi-model workflows on clean-task input (inspect tools / caller-URL research / advisory review) |
|
|
36
34
|
|
|
37
|
-
### Commands
|
|
35
|
+
### Commands
|
|
38
36
|
|
|
39
|
-
`/unipi:bg
|
|
40
|
-
`/unipi:
|
|
41
|
-
`/unipi:bg-settings`, `/unipi:fusion`, `/unipi:fusion-models`,
|
|
42
|
-
`/unipi:claude-cache`.
|
|
37
|
+
`/unipi:bg` (start a shell task), `/unipi:bg-tasks` (open the dock),
|
|
38
|
+
`/unipi:bg-settings`.
|
|
43
39
|
|
|
44
40
|
Shortcuts: `Shift↓` opens the task manager dock; `Ctrl+Alt+C` clears finished notices.
|
|
45
41
|
|
|
42
|
+
## What the user sees
|
|
43
|
+
|
|
44
|
+
- **Launch card** — `bg_run` results render as a tinted card (`● bg started <name> · wakes agent on completion`) so the start of a task is visible in the transcript.
|
|
45
|
+
- **Pending-wake line** — while the agent is idle but a task that will wake it is still running, a spinner line sits above the editor: `⠋ waiting on 1 bg task · <name> 12s — agent resumes automatically when done`. Without this the UI looks finished and users assume the turn is over.
|
|
46
|
+
- **Completion card** — the terminal notification renders as a tinted card (`✓ bg done <name> · exit 0 · 25s · agent woken`) with the last three output lines. Failed / stopped tasks use the error tint.
|
|
47
|
+
- **Dock** (`Shift↓`) — rows show `⏰ wakes agent` for tasks that will resume the agent, and the last output line for running shell tasks.
|
|
48
|
+
|
|
46
49
|
## Storage layout (ours — never `.pi/`)
|
|
47
50
|
|
|
48
51
|
- Runtime artifacts (task output/metadata): `$TMPDIR/unipi-bg-tasks/<session>-<pid>-<nonce>/`
|
|
49
52
|
- Durable delegate artifacts: `<workspace>/.unipi/delegate/<session>-<pid>/<task-id>/`
|
|
50
|
-
- Durable fusion artifacts: `<workspace>/.unipi/fusion/<session>-<pid>/<run-id>/`
|
|
51
53
|
- Config: `~/.unipi/config/background-tasks.json` + workspace override
|
|
52
|
-
- Fusion model config: five-slot selector persisted through `/unipi:fusion-models`
|
|
53
54
|
|
|
54
55
|
## Environment
|
|
55
56
|
|
|
@@ -67,13 +68,6 @@ Shortcuts: `Shift↓` opens the task manager dock; `Ctrl+Alt+C` clears finished
|
|
|
67
68
|
|
|
68
69
|
Treat `<background-task-notification>` as durable terminal truth — do not poll.
|
|
69
70
|
|
|
70
|
-
## Attribution
|
|
71
|
-
|
|
72
|
-
`extensions/anthropic-attribution.ts` loads first (provider-gated): Claude Code
|
|
73
|
-
subscription OAuth attribution, exact-match system-prompt sanitization, and
|
|
74
|
-
cache-retention policy for Anthropic routes. Duplicate installed copies resolve
|
|
75
|
-
ownership through an EventBus claim; later copies go inert.
|
|
76
|
-
|
|
77
71
|
## Shared registry (for sibling extensions)
|
|
78
72
|
|
|
79
73
|
Other packages can read the live task registry synchronously — no events, no polling:
|
|
@@ -94,10 +88,10 @@ treat that as "no data", e.g. the footer's glance process line does.
|
|
|
94
88
|
|
|
95
89
|
- Commands live in the `/unipi:*` namespace; env prefix is `UNIPI_BG_*`.
|
|
96
90
|
- Runtime artifacts under the OS temp root (per-registry nonce) and durable
|
|
97
|
-
delegate
|
|
91
|
+
delegate artifacts under workspace `.unipi/` — never `.pi/`.
|
|
98
92
|
- The reference's `update-check` footer surface is dropped (unipi's updater
|
|
99
93
|
module owns updates).
|
|
100
|
-
-
|
|
101
|
-
|
|
94
|
+
- Removed: attested Pi runs, the five-slot Fusion council tools, and the
|
|
95
|
+
Anthropic attribution provider override.
|
|
102
96
|
|
|
103
97
|
ISC-licensed reference: Copyright Ismail <ismailsalikhodjaev@gmail.com>.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/background-tasks",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "Background tasks for UniPi — durable shell jobs
|
|
3
|
+
"version": "2.17.0",
|
|
4
|
+
"description": "Background tasks for UniPi — durable shell jobs and delegated background agents with a footer dock",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"types": "src/index.ts",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@earendil-works/pi-ai": "^0.84.0",
|
|
13
|
-
"@pi-unipi/core": "2.
|
|
13
|
+
"@pi-unipi/core": "2.17.0",
|
|
14
14
|
"turndown": "^7.2.4"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
@@ -31,7 +31,6 @@
|
|
|
31
31
|
],
|
|
32
32
|
"pi": {
|
|
33
33
|
"extensions": [
|
|
34
|
-
"./extensions/anthropic-attribution.ts",
|
|
35
34
|
"./src/index.ts"
|
|
36
35
|
],
|
|
37
36
|
"skills": [],
|
package/src/cards.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pi-unipi/background-tasks — tinted chat cards
|
|
3
|
+
*
|
|
4
|
+
* Background-task launch/completion messages were plain single lines that got
|
|
5
|
+
* lost in the transcript. These helpers render them as padded, background-
|
|
6
|
+
* tinted boxes (same visual language as pi's tool cards) so a user scanning
|
|
7
|
+
* the chat can spot "a bg task started here" / "it finished here" at a glance.
|
|
8
|
+
*/
|
|
9
|
+
import { Box, Text } from "@earendil-works/pi-tui";
|
|
10
|
+
import { formatDuration, taskDisplayName, type BgTaskSnapshot } from "./types.js";
|
|
11
|
+
|
|
12
|
+
type ThemeLike = {
|
|
13
|
+
fg: (color: string, text: string) => string;
|
|
14
|
+
bg: (color: string, text: string) => string;
|
|
15
|
+
bold: (text: string) => string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
type CardTone = "pending" | "success" | "error";
|
|
19
|
+
|
|
20
|
+
const BG_FOR_TONE: Record<CardTone, string> = {
|
|
21
|
+
pending: "toolPendingBg",
|
|
22
|
+
success: "toolSuccessBg",
|
|
23
|
+
error: "toolErrorBg",
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
function toneFor(status: BgTaskSnapshot["status"]): CardTone {
|
|
27
|
+
if (status === "running") return "pending";
|
|
28
|
+
if (status === "completed") return "success";
|
|
29
|
+
return "error";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function statusGlyph(theme: ThemeLike, status: BgTaskSnapshot["status"]): string {
|
|
33
|
+
if (status === "running") return theme.fg("accent", "●");
|
|
34
|
+
if (status === "completed") return theme.fg("success", "✓");
|
|
35
|
+
if (status === "killed") return theme.fg("warning", "■");
|
|
36
|
+
return theme.fg("error", "✗");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function card(theme: ThemeLike, tone: CardTone, lines: string[]): Box {
|
|
40
|
+
const box = new Box(1, 0, (text) => theme.bg(BG_FOR_TONE[tone], text));
|
|
41
|
+
box.addChild(new Text(lines.join("\n"), 0, 0));
|
|
42
|
+
return box;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** `bg_run` result card: "● bg started <name> (id) · will wake agent" */
|
|
46
|
+
export function renderLaunchCard(theme: ThemeLike, task: BgTaskSnapshot): Box {
|
|
47
|
+
const wake = task.triggerOnCompletion
|
|
48
|
+
? theme.fg("dim", " · wakes agent on completion")
|
|
49
|
+
: task.notifyOnCompletion
|
|
50
|
+
? theme.fg("dim", " · notifies on completion")
|
|
51
|
+
: theme.fg("dim", " · silent");
|
|
52
|
+
const head = `${statusGlyph(theme, "running")} ${theme.fg("accent", theme.bold("bg started"))} ${theme.fg("accent", taskDisplayName(task))} ${theme.fg("dim", `(${task.id})`)}${wake}`;
|
|
53
|
+
const cmd = theme.fg("dim", `$ ${task.command.length > 120 ? `${task.command.slice(0, 120)}…` : task.command}`);
|
|
54
|
+
return card(theme, "pending", [head, cmd]);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Completion notification card: "✓ bg done <name> · exit 0 · 25s" + last output lines */
|
|
58
|
+
export function renderCompletionCard(theme: ThemeLike, task: BgTaskSnapshot | undefined): Box {
|
|
59
|
+
if (task === undefined) {
|
|
60
|
+
return card(theme, "success", [`${theme.fg("success", "✓")} ${theme.fg("accent", theme.bold("bg done"))}`]);
|
|
61
|
+
}
|
|
62
|
+
const tone = toneFor(task.status);
|
|
63
|
+
const label =
|
|
64
|
+
task.status === "completed" ? "bg done" : task.status === "killed" ? "bg stopped" : "bg failed";
|
|
65
|
+
const meta: string[] = [];
|
|
66
|
+
if (task.exitCode !== undefined && task.exitCode !== null) meta.push(`exit ${String(task.exitCode)}`);
|
|
67
|
+
if (task.endTime !== undefined) meta.push(formatDuration(task.endTime - task.startTime));
|
|
68
|
+
if (task.triggerOnCompletion) meta.push("agent woken");
|
|
69
|
+
const head = `${statusGlyph(theme, task.status)} ${theme.fg(tone === "error" ? "error" : "success", theme.bold(label))} ${theme.fg("accent", taskDisplayName(task))} ${theme.fg("dim", `(${task.id})`)}${meta.length > 0 ? theme.fg("dim", ` · ${meta.join(" · ")}`) : ""}`;
|
|
70
|
+
const lines = [head];
|
|
71
|
+
if (task.error) lines.push(theme.fg("error", task.error));
|
|
72
|
+
const tail = task.outputTail ?? [];
|
|
73
|
+
for (const line of tail) lines.push(theme.fg("toolOutput", ` ${line}`));
|
|
74
|
+
lines.push(theme.fg("dim", ` ${task.outputPath}`));
|
|
75
|
+
return card(theme, tone, lines);
|
|
76
|
+
}
|
package/src/child-process.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @pi-unipi/background-tasks — Shared child-process & context interfaces
|
|
3
3
|
*
|
|
4
|
-
* Consumed by types.ts, registry.ts,
|
|
4
|
+
* Consumed by types.ts, registry.ts, and tests.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type { SpawnOptions } from "node:child_process";
|
package/src/config.ts
CHANGED
|
@@ -34,13 +34,6 @@ export interface BackgroundTasksConfig {
|
|
|
34
34
|
maxToolCalls: number;
|
|
35
35
|
timeoutSeconds: number;
|
|
36
36
|
};
|
|
37
|
-
/** Fusion defaults. */
|
|
38
|
-
fusion: {
|
|
39
|
-
/** Five-slot model selections ('' = $current). */
|
|
40
|
-
candidates: [string, string, string];
|
|
41
|
-
evaluator: string;
|
|
42
|
-
merger: string;
|
|
43
|
-
};
|
|
44
37
|
}
|
|
45
38
|
|
|
46
39
|
export const DEFAULT_CONFIG: BackgroundTasksConfig = {
|
|
@@ -57,11 +50,6 @@ export const DEFAULT_CONFIG: BackgroundTasksConfig = {
|
|
|
57
50
|
maxToolCalls: 120,
|
|
58
51
|
timeoutSeconds: 900,
|
|
59
52
|
},
|
|
60
|
-
fusion: {
|
|
61
|
-
candidates: ["", "", ""],
|
|
62
|
-
evaluator: "",
|
|
63
|
-
merger: "",
|
|
64
|
-
},
|
|
65
53
|
};
|
|
66
54
|
|
|
67
55
|
function getGlobalConfigPath(): string {
|
|
@@ -181,28 +169,6 @@ export function validateBackgroundTasksConfig(config: unknown): string[] {
|
|
|
181
169
|
}
|
|
182
170
|
}
|
|
183
171
|
}
|
|
184
|
-
if (c.fusion !== undefined) {
|
|
185
|
-
if (typeof c.fusion !== "object" || c.fusion === null) {
|
|
186
|
-
problems.push("fusion must be an object");
|
|
187
|
-
} else {
|
|
188
|
-
const f = c.fusion as Record<string, unknown>;
|
|
189
|
-
for (const key of ["candidates", "evaluator", "merger"] as const) {
|
|
190
|
-
const value = f[key];
|
|
191
|
-
if (value === undefined) continue;
|
|
192
|
-
if (key === "candidates") {
|
|
193
|
-
if (
|
|
194
|
-
!Array.isArray(value) ||
|
|
195
|
-
value.length !== 3 ||
|
|
196
|
-
value.some((v) => typeof v !== "string")
|
|
197
|
-
) {
|
|
198
|
-
problems.push("fusion.candidates must be an array of exactly 3 strings");
|
|
199
|
-
}
|
|
200
|
-
} else if (typeof value !== "string") {
|
|
201
|
-
problems.push(`fusion.${key} must be a string`);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
172
|
return problems;
|
|
207
173
|
}
|
|
208
174
|
|
|
@@ -272,14 +238,6 @@ export function loadBackgroundTasksConfig(cwd: string): LoadedBackgroundTasksCon
|
|
|
272
238
|
? merged.delegate.autoDeliver
|
|
273
239
|
: "when_small",
|
|
274
240
|
},
|
|
275
|
-
fusion: {
|
|
276
|
-
candidates:
|
|
277
|
-
Array.isArray(merged.fusion?.candidates) && merged.fusion.candidates.length === 3
|
|
278
|
-
? ([...merged.fusion.candidates] as [string, string, string])
|
|
279
|
-
: DEFAULT_CONFIG.fusion.candidates,
|
|
280
|
-
evaluator: typeof merged.fusion?.evaluator === "string" ? merged.fusion.evaluator : "",
|
|
281
|
-
merger: typeof merged.fusion?.merger === "string" ? merged.fusion.merger : "",
|
|
282
|
-
},
|
|
283
241
|
};
|
|
284
242
|
return { config, warnings };
|
|
285
243
|
}
|
|
@@ -2,7 +2,7 @@ import { createHash } from 'node:crypto';
|
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
3
|
import { chmod, mkdir, open, readFile, rename, rm } from 'node:fs/promises';
|
|
4
4
|
import { basename, isAbsolute, join, relative, sep } from 'node:path';
|
|
5
|
-
import { canonicalJson } from '../
|
|
5
|
+
import { canonicalJson } from '../json-utils.js';
|
|
6
6
|
import { sanitizePathSegment } from '../types.js';
|
|
7
7
|
import { replaceFileDurable, writeFileDurable } from '../durable-fs.js';
|
|
8
8
|
import {
|
package/src/delegate/launch.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { randomBytes } from 'node:crypto';
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
|
+
import { packageAssetSearchHint, resolvePackageAsset } from '../package-assets.js';
|
|
3
4
|
import { mkdir } from 'node:fs/promises';
|
|
4
5
|
import { dirname, join, resolve } from 'node:path';
|
|
5
6
|
import { fileURLToPath } from 'node:url';
|
|
@@ -184,15 +185,20 @@ export function resolveDelegateChildExtensionPath(
|
|
|
184
185
|
moduleUrl = import.meta.url,
|
|
185
186
|
pathExists: (path: string) => boolean = existsSync,
|
|
186
187
|
): string {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const candidate =
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
188
|
+
// Prefer the TypeScript guard (pi loads extensions through jiti); fall back
|
|
189
|
+
// to a compiled copy when one exists.
|
|
190
|
+
const candidate =
|
|
191
|
+
resolvePackageAsset('extensions/delegate-child.ts', { moduleUrl, pathExists }) ??
|
|
192
|
+
resolvePackageAsset('extensions/delegate-child.js', { moduleUrl, pathExists });
|
|
193
|
+
if (candidate === undefined) {
|
|
194
|
+
throw new DelegateError(
|
|
195
|
+
`delegate child extension is missing: ${packageAssetSearchHint('extensions/delegate-child.ts')}`,
|
|
196
|
+
{
|
|
197
|
+
code: 'delegate_isolation_unsupported',
|
|
198
|
+
childCreated: false,
|
|
199
|
+
remediation: ['Reinstall the package; the child guard extension is required to spawn.'],
|
|
200
|
+
},
|
|
201
|
+
);
|
|
196
202
|
}
|
|
197
203
|
return candidate;
|
|
198
204
|
}
|
|
@@ -201,7 +207,7 @@ export function resolveDelegateChildExtensionPath(
|
|
|
201
207
|
* Tools the inspect capability permits.
|
|
202
208
|
*
|
|
203
209
|
* v1 is read-only by construction: no shell, no network, no edit/write, no
|
|
204
|
-
* recursive delegation
|
|
210
|
+
* recursive delegation. The list is passed to `--tools`, so it is
|
|
205
211
|
* enforced by the child's tool registry rather than by prompt text.
|
|
206
212
|
*/
|
|
207
213
|
export const DELEGATE_INSPECT_TOOLS: readonly string[] = [
|
|
@@ -223,12 +229,6 @@ export const DELEGATE_FORBIDDEN_TOOLS: readonly string[] = [
|
|
|
223
229
|
'bg_kill',
|
|
224
230
|
'bg_status',
|
|
225
231
|
'bg_logs',
|
|
226
|
-
'bg_run_pi_attested',
|
|
227
|
-
'fusion_brainstorm',
|
|
228
|
-
'fusion_reason',
|
|
229
|
-
'fusion_investigate',
|
|
230
|
-
'fusion_research',
|
|
231
|
-
'fusion_validate',
|
|
232
232
|
];
|
|
233
233
|
|
|
234
234
|
export function delegateToolsFor(capability: DelegateCapability): readonly string[] {
|
|
@@ -256,7 +256,6 @@ export interface DelegateChildArgvInput {
|
|
|
256
256
|
childSessionId: string;
|
|
257
257
|
childSessionDir: string;
|
|
258
258
|
childExtensionPath: string;
|
|
259
|
-
attributionExtensionPath?: string | undefined;
|
|
260
259
|
systemPrompt: string;
|
|
261
260
|
}
|
|
262
261
|
|
|
@@ -282,19 +281,7 @@ export function buildDelegateChildArgv(input: DelegateChildArgvInput): string[]
|
|
|
282
281
|
);
|
|
283
282
|
}
|
|
284
283
|
}
|
|
285
|
-
const extensionPaths =
|
|
286
|
-
input.route.provider === 'anthropic'
|
|
287
|
-
? [
|
|
288
|
-
input.attributionExtensionPath ??
|
|
289
|
-
(() => {
|
|
290
|
-
throw new DelegateError(
|
|
291
|
-
'Anthropic delegate launch requires the package attribution extension',
|
|
292
|
-
{ code: 'delegate_isolation_unsupported', childCreated: false },
|
|
293
|
-
);
|
|
294
|
-
})(),
|
|
295
|
-
input.childExtensionPath,
|
|
296
|
-
]
|
|
297
|
-
: [input.childExtensionPath];
|
|
284
|
+
const extensionPaths = [input.childExtensionPath];
|
|
298
285
|
|
|
299
286
|
return [
|
|
300
287
|
'--mode',
|
package/src/delegate/runner.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
|
-
import { canonicalJson } from '../
|
|
3
|
+
import { canonicalJson } from '../json-utils.js';
|
|
4
4
|
import { replaceFileDurable } from '../durable-fs.js';
|
|
5
|
-
import { resolveAnthropicAttributionExtensionPath } from '../anthropic-attribution-path.js';
|
|
6
5
|
import { join } from 'node:path';
|
|
7
6
|
import { DelegateArtifactStore, discardDelegateArtifactRoot } from './artifacts.js';
|
|
8
7
|
import {
|
|
@@ -52,7 +51,6 @@ export interface PrepareDelegateLaunchInput extends DelegatePreflightInput {
|
|
|
52
51
|
autoDeliver: DelegateAutoDeliverMode;
|
|
53
52
|
extensionMode: DelegateExtensionMode;
|
|
54
53
|
childExtensionPath?: string | undefined;
|
|
55
|
-
attributionExtensionPath?: string | undefined;
|
|
56
54
|
env?: NodeJS.ProcessEnv | undefined;
|
|
57
55
|
now?: (() => Date) | undefined;
|
|
58
56
|
}
|
|
@@ -72,22 +70,6 @@ export async function prepareDelegateLaunch(
|
|
|
72
70
|
// its child guard must refuse rather than spawn an unguarded child.
|
|
73
71
|
const childExtensionPath =
|
|
74
72
|
input.childExtensionPath ?? resolveDelegateChildExtensionPath();
|
|
75
|
-
let attributionExtensionPath: string | undefined;
|
|
76
|
-
if (input.route.provider === 'anthropic') {
|
|
77
|
-
try {
|
|
78
|
-
attributionExtensionPath =
|
|
79
|
-
input.attributionExtensionPath ?? resolveAnthropicAttributionExtensionPath();
|
|
80
|
-
} catch (error) {
|
|
81
|
-
throw new DelegateError(
|
|
82
|
-
`Anthropic delegate attribution extension could not be resolved: ${error instanceof Error ? error.message : String(error)}`,
|
|
83
|
-
{
|
|
84
|
-
code: 'delegate_isolation_unsupported',
|
|
85
|
-
childCreated: false,
|
|
86
|
-
remediation: ['Reinstall the package; Anthropic delegates require attribution.'],
|
|
87
|
-
},
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
73
|
|
|
92
74
|
const preflight = preflightDelegateLaunch(input);
|
|
93
75
|
|
|
@@ -132,7 +114,6 @@ export async function prepareDelegateLaunch(
|
|
|
132
114
|
childSessionId: preflight.childSessionId,
|
|
133
115
|
childSessionDir: childSessionDirAbs,
|
|
134
116
|
childExtensionPath,
|
|
135
|
-
attributionExtensionPath,
|
|
136
117
|
systemPrompt: preflight.childSystemPrompt,
|
|
137
118
|
});
|
|
138
119
|
const env = delegateChildEnv(
|
package/src/delegate/seed.ts
CHANGED