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
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
export type LazyModuleState = 'unloaded' | 'loading' | 'loaded' | 'failed' | 'closed';
|
|
2
|
+
|
|
3
|
+
/** Activation-local synchronous close callbacks installed by the entrypoint. */
|
|
4
|
+
export class SynchronousActivationCloseFence {
|
|
5
|
+
private closed = false;
|
|
6
|
+
private readonly callbacks = new Set<() => void>();
|
|
7
|
+
|
|
8
|
+
add(callback: () => void): void {
|
|
9
|
+
this.callbacks.add(callback);
|
|
10
|
+
if (this.closed) callback();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
close(): void {
|
|
14
|
+
this.closed = true;
|
|
15
|
+
// Re-run idempotent teardown callbacks on repeated lifecycle dispatch. The
|
|
16
|
+
// core callback deliberately clears handles assigned by racing continuations.
|
|
17
|
+
const failures: unknown[] = [];
|
|
18
|
+
for (const callback of this.callbacks) {
|
|
19
|
+
try {
|
|
20
|
+
callback();
|
|
21
|
+
} catch (error) {
|
|
22
|
+
failures.push(error);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (failures.length > 0) {
|
|
26
|
+
throw new AggregateError(
|
|
27
|
+
failures,
|
|
28
|
+
`synchronous activation close barrier failed in ${String(failures.length)} callback(s)`,
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const MODULE_ID_MAX_CHARS = 120;
|
|
35
|
+
const CAUSE_MAX_CHARS = 480;
|
|
36
|
+
const CLOSE_REASON_MAX_CHARS = 160;
|
|
37
|
+
|
|
38
|
+
function boundedSingleLine(value: string, maximum: number): string {
|
|
39
|
+
const singleLine = value.replace(/\s+/gu, ' ').trim();
|
|
40
|
+
if (singleLine.length <= maximum) return singleLine;
|
|
41
|
+
return `${singleLine.slice(0, maximum)}…`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function boundedModuleId(moduleId: string): string {
|
|
45
|
+
const bounded = boundedSingleLine(moduleId, MODULE_ID_MAX_CHARS);
|
|
46
|
+
return bounded.length > 0 ? bounded : 'unnamed-module';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function causeText(error: unknown): string {
|
|
50
|
+
if (error instanceof Error) {
|
|
51
|
+
const message = error.message.trim();
|
|
52
|
+
return boundedSingleLine(
|
|
53
|
+
message.length > 0 ? `${error.name}: ${message}` : error.name,
|
|
54
|
+
CAUSE_MAX_CHARS,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
return boundedSingleLine(String(error), CAUSE_MAX_CHARS);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
class LazyModuleLoadError extends Error {
|
|
61
|
+
readonly code = 'lazy_module_load_failed';
|
|
62
|
+
readonly moduleId: string;
|
|
63
|
+
|
|
64
|
+
constructor(moduleId: string, error: unknown) {
|
|
65
|
+
const cause = causeText(error);
|
|
66
|
+
super(`lazy_module_load_failed: deferred module ${moduleId} could not load: ${cause}`);
|
|
67
|
+
this.name = 'LazyModuleLoadError';
|
|
68
|
+
this.moduleId = moduleId;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
class LazyModuleClosedError extends Error {
|
|
73
|
+
readonly code = 'lazy_module_closed';
|
|
74
|
+
readonly moduleId: string;
|
|
75
|
+
|
|
76
|
+
constructor(moduleId: string, reason: string) {
|
|
77
|
+
super(
|
|
78
|
+
`lazy_module_closed: deferred module ${moduleId} belongs to a closed activation (${boundedSingleLine(reason, CLOSE_REASON_MAX_CHARS) || 'closed'})`,
|
|
79
|
+
);
|
|
80
|
+
this.name = 'LazyModuleClosedError';
|
|
81
|
+
this.moduleId = moduleId;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Activation-local, single-flight deferred module loader.
|
|
87
|
+
*
|
|
88
|
+
* The loader is deliberately terminal after `close()`: a Pi reload creates a
|
|
89
|
+
* fresh facade and therefore a fresh loader rather than reviving stale state.
|
|
90
|
+
*/
|
|
91
|
+
export class LazyModule<T> {
|
|
92
|
+
readonly moduleId: string;
|
|
93
|
+
private readonly importer: () => Promise<T>;
|
|
94
|
+
private currentState: LazyModuleState = 'unloaded';
|
|
95
|
+
private activationGeneration = 0;
|
|
96
|
+
private loadingPromise: Promise<T> | undefined;
|
|
97
|
+
private loadedValue: { value: T } | undefined;
|
|
98
|
+
private loadFailure: Error | undefined;
|
|
99
|
+
private closedFailure: Error | undefined;
|
|
100
|
+
|
|
101
|
+
constructor(moduleId: string, importer: () => Promise<T>) {
|
|
102
|
+
this.moduleId = boundedModuleId(moduleId);
|
|
103
|
+
this.importer = importer;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
get state(): LazyModuleState {
|
|
107
|
+
return this.currentState;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Synchronously and permanently close this activation. */
|
|
111
|
+
close(reason = 'activation closed'): void {
|
|
112
|
+
if (this.currentState === 'closed') return;
|
|
113
|
+
this.activationGeneration += 1;
|
|
114
|
+
this.currentState = 'closed';
|
|
115
|
+
this.loadedValue = undefined;
|
|
116
|
+
this.loadingPromise = undefined;
|
|
117
|
+
this.loadFailure = undefined;
|
|
118
|
+
this.closedFailure = new LazyModuleClosedError(this.moduleId, reason);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Assert immediately before an activation-owned side effect. */
|
|
122
|
+
assertOpen(expectedGeneration = this.activationGeneration): void {
|
|
123
|
+
if (
|
|
124
|
+
this.currentState === 'closed' ||
|
|
125
|
+
expectedGeneration !== this.activationGeneration
|
|
126
|
+
) {
|
|
127
|
+
throw this.closedError();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
load(): Promise<T> {
|
|
132
|
+
const generation = this.activationGeneration;
|
|
133
|
+
try {
|
|
134
|
+
this.assertOpen(generation);
|
|
135
|
+
} catch (error) {
|
|
136
|
+
return Promise.reject(error);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (this.currentState === 'loaded') {
|
|
140
|
+
const loaded = this.loadedValue;
|
|
141
|
+
if (loaded === undefined) {
|
|
142
|
+
return Promise.reject(
|
|
143
|
+
new Error(`lazy_module_invariant: ${this.moduleId} is loaded without a value`),
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
return Promise.resolve(loaded.value);
|
|
147
|
+
}
|
|
148
|
+
if (this.currentState === 'failed') {
|
|
149
|
+
const failure = this.loadFailure;
|
|
150
|
+
if (failure === undefined) {
|
|
151
|
+
return Promise.reject(
|
|
152
|
+
new Error(`lazy_module_invariant: ${this.moduleId} failed without an error`),
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
return Promise.reject(failure);
|
|
156
|
+
}
|
|
157
|
+
if (this.currentState === 'loading') {
|
|
158
|
+
const pending = this.loadingPromise;
|
|
159
|
+
if (pending === undefined) {
|
|
160
|
+
return Promise.reject(
|
|
161
|
+
new Error(`lazy_module_invariant: ${this.moduleId} is loading without a promise`),
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
return pending;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
this.currentState = 'loading';
|
|
168
|
+
// The importer itself runs in a later microtask. `loadingPromise` is stored
|
|
169
|
+
// before that callback can run, including under re-entrant test importers.
|
|
170
|
+
const pending = Promise.resolve()
|
|
171
|
+
.then(() => {
|
|
172
|
+
this.assertOpen(generation);
|
|
173
|
+
return this.importer();
|
|
174
|
+
})
|
|
175
|
+
.then(
|
|
176
|
+
(value) => {
|
|
177
|
+
this.assertOpen(generation);
|
|
178
|
+
this.loadedValue = { value };
|
|
179
|
+
this.loadingPromise = undefined;
|
|
180
|
+
this.currentState = 'loaded';
|
|
181
|
+
return value;
|
|
182
|
+
},
|
|
183
|
+
(error: unknown) => {
|
|
184
|
+
this.assertOpen(generation);
|
|
185
|
+
const failure = new LazyModuleLoadError(this.moduleId, error);
|
|
186
|
+
this.loadFailure = failure;
|
|
187
|
+
this.loadingPromise = undefined;
|
|
188
|
+
this.currentState = 'failed';
|
|
189
|
+
throw failure;
|
|
190
|
+
},
|
|
191
|
+
);
|
|
192
|
+
this.loadingPromise = pending;
|
|
193
|
+
return pending;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Load once, then invoke this caller's operation independently after the
|
|
198
|
+
* final generation check. Only module loading is shared between callers.
|
|
199
|
+
*/
|
|
200
|
+
async run<R>(operation: (module: T) => R | Promise<R>): Promise<R> {
|
|
201
|
+
const generation = this.activationGeneration;
|
|
202
|
+
this.assertOpen(generation);
|
|
203
|
+
const module = await this.load();
|
|
204
|
+
this.assertOpen(generation);
|
|
205
|
+
return operation(module);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
private closedError(): Error {
|
|
209
|
+
const failure = this.closedFailure;
|
|
210
|
+
if (failure !== undefined) return failure;
|
|
211
|
+
const created = new LazyModuleClosedError(this.moduleId, 'activation closed');
|
|
212
|
+
this.closedFailure = created;
|
|
213
|
+
return created;
|
|
214
|
+
}
|
|
215
|
+
}
|