@dsh-cc/subagent-task 0.5.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/LICENSE +201 -0
- package/README.i18n.yaml +6 -0
- package/README.md +214 -0
- package/README.zh.md +100 -0
- package/lib/background-start.d.ts +207 -0
- package/lib/background-start.d.ts.map +1 -0
- package/lib/background-start.js +354 -0
- package/lib/background-start.js.map +1 -0
- package/lib/catalog.d.ts +99 -0
- package/lib/catalog.d.ts.map +1 -0
- package/lib/catalog.js +197 -0
- package/lib/catalog.js.map +1 -0
- package/lib/epoch-collector.d.ts +126 -0
- package/lib/epoch-collector.d.ts.map +1 -0
- package/lib/epoch-collector.js +243 -0
- package/lib/epoch-collector.js.map +1 -0
- package/lib/index.d.ts +62 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +143 -0
- package/lib/index.js.map +1 -0
- package/lib/preload-tools.d.ts +66 -0
- package/lib/preload-tools.d.ts.map +1 -0
- package/lib/preload-tools.js +101 -0
- package/lib/preload-tools.js.map +1 -0
- package/lib/registry.d.ts +49 -0
- package/lib/registry.d.ts.map +1 -0
- package/lib/registry.js +66 -0
- package/lib/registry.js.map +1 -0
- package/lib/resume-capture.d.ts +107 -0
- package/lib/resume-capture.d.ts.map +1 -0
- package/lib/resume-capture.js +232 -0
- package/lib/resume-capture.js.map +1 -0
- package/lib/sanitize-filter.d.ts +27 -0
- package/lib/sanitize-filter.d.ts.map +1 -0
- package/lib/sanitize-filter.js +95 -0
- package/lib/sanitize-filter.js.map +1 -0
- package/lib/strip-instructions.d.ts +47 -0
- package/lib/strip-instructions.d.ts.map +1 -0
- package/lib/strip-instructions.js +77 -0
- package/lib/strip-instructions.js.map +1 -0
- package/lib/suppress-settled.d.ts +45 -0
- package/lib/suppress-settled.d.ts.map +1 -0
- package/lib/suppress-settled.js +80 -0
- package/lib/suppress-settled.js.map +1 -0
- package/lib/tool.d.ts +49 -0
- package/lib/tool.d.ts.map +1 -0
- package/lib/tool.js +247 -0
- package/lib/tool.js.map +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The dsh-cc epoch collector: inline first-epoch collection of a continuable
|
|
3
|
+
* subagent child with zero harness changes (normative design:
|
|
4
|
+
* `docs/plans/2026-09-10-epoch-collector-dsh-cc.md`).
|
|
5
|
+
*
|
|
6
|
+
* One shared `subagent/start` + `subagent/end` listener pair and one watch
|
|
7
|
+
* map (`Map<childId, { runId?, resolve }>`) serve every collector of the
|
|
8
|
+
* process. The reservation is placed BEFORE `startContinuable` so an
|
|
9
|
+
* immediate settle cannot fall between start and subscription; the runId is
|
|
10
|
+
* captured from the child's first `subagent/start` and the end event is
|
|
11
|
+
* matched by runId (a cold-resumed later epoch has a new runId and never
|
|
12
|
+
* satisfies a stale watcher). The shared listeners are disposed when the map
|
|
13
|
+
* empties.
|
|
14
|
+
*
|
|
15
|
+
* This module is the ONE-FILE swap seam (§7): when upstream later ships the
|
|
16
|
+
* collectable continuable handle, only this file's `collectFirstEpoch`
|
|
17
|
+
* implementation is replaced — the Task tool and TUI surfaces are untouched.
|
|
18
|
+
*
|
|
19
|
+
* @module @dsh-cc/subagent-task/epoch-collector
|
|
20
|
+
*/
|
|
21
|
+
/** The one shared watch map (per-process singleton, §3 "Parallel collects"). */
|
|
22
|
+
const watches = new Map();
|
|
23
|
+
/** The bus the shared listener pair is currently subscribed to. */
|
|
24
|
+
let watchedBus;
|
|
25
|
+
/** Disposer of the shared listener pair on {@link watchedBus}. */
|
|
26
|
+
let disposeWatchers;
|
|
27
|
+
function ensureWatchers(bus) {
|
|
28
|
+
if (disposeWatchers !== undefined && watchedBus === bus)
|
|
29
|
+
return;
|
|
30
|
+
// A collect on a different bus (never happens in production, where every
|
|
31
|
+
// collector shares the one cordis context) re-subscribes on the new bus.
|
|
32
|
+
if (disposeWatchers !== undefined)
|
|
33
|
+
disposeWatchers();
|
|
34
|
+
const offStart = bus.on('subagent/start', info => {
|
|
35
|
+
const entry = watches.get(String(info.id));
|
|
36
|
+
if (entry !== undefined && entry.runId === undefined)
|
|
37
|
+
entry.runId = String(info.runId);
|
|
38
|
+
});
|
|
39
|
+
const offEnd = bus.on('subagent/end', info => {
|
|
40
|
+
const runId = String(info.runId);
|
|
41
|
+
for (const [childId, entry] of watches) {
|
|
42
|
+
if (entry.runId !== runId)
|
|
43
|
+
continue;
|
|
44
|
+
watches.delete(childId);
|
|
45
|
+
const output = info.lastAssistantMessage;
|
|
46
|
+
entry.resolve({
|
|
47
|
+
stopReason: String(info.stopReason),
|
|
48
|
+
...(output !== undefined ? { output } : {}),
|
|
49
|
+
});
|
|
50
|
+
if (watches.size === 0 && disposeWatchers !== undefined)
|
|
51
|
+
disposeWatchers();
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
watchedBus = bus;
|
|
56
|
+
disposeWatchers = () => {
|
|
57
|
+
offStart?.();
|
|
58
|
+
offEnd?.();
|
|
59
|
+
watchedBus = undefined;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function release(childId) {
|
|
63
|
+
watches.delete(childId);
|
|
64
|
+
if (watches.size === 0 && disposeWatchers !== undefined)
|
|
65
|
+
disposeWatchers();
|
|
66
|
+
}
|
|
67
|
+
/** Instrumentation for tests and diagnostics: live watch entries. */
|
|
68
|
+
export function epochWatchSize() {
|
|
69
|
+
return watches.size;
|
|
70
|
+
}
|
|
71
|
+
// ── Duplicate-notice suppression bookkeeping (§5) ─────────────────────────
|
|
72
|
+
/**
|
|
73
|
+
* The pop-once "collected" set: senderSessionIds whose `subagent-settled`
|
|
74
|
+
* notice must be dropped because the epoch was consumed inline. Entries are
|
|
75
|
+
* popped by the suppression pre-step listener on first delivery, so a later
|
|
76
|
+
* epoch of the same child delivers normally.
|
|
77
|
+
*/
|
|
78
|
+
const collectedForSuppression = new Set();
|
|
79
|
+
/** Mark a child's settlement notice for drop (done at collect reservation). */
|
|
80
|
+
export function markCollectedForSuppression(childId) {
|
|
81
|
+
collectedForSuppression.add(childId);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Un-mark a child (a promoted child is never suppressed — its notice flows
|
|
85
|
+
* normally; Slice 3's `promote()` calls this).
|
|
86
|
+
*/
|
|
87
|
+
export function releaseCollectedForSuppression(childId) {
|
|
88
|
+
collectedForSuppression.delete(childId);
|
|
89
|
+
}
|
|
90
|
+
/** Whether a child's settlement notice is currently marked for drop. */
|
|
91
|
+
export function isCollectedForSuppression(childId) {
|
|
92
|
+
return collectedForSuppression.has(childId);
|
|
93
|
+
}
|
|
94
|
+
const registrations = new Map();
|
|
95
|
+
/** Registry key: parentSessionId + toolCallToken. */
|
|
96
|
+
export function collectorKey(parentSessionId, toolCallToken) {
|
|
97
|
+
return `${parentSessionId}\u0000${toolCallToken}`;
|
|
98
|
+
}
|
|
99
|
+
export function registerCollector(key, handle) {
|
|
100
|
+
registrations.set(key, handle);
|
|
101
|
+
}
|
|
102
|
+
export function unregisterCollector(key) {
|
|
103
|
+
registrations.delete(key);
|
|
104
|
+
}
|
|
105
|
+
export function collectorFor(key) {
|
|
106
|
+
return registrations.get(key);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* All live registrations of ONE parent session (the TUI busy-branch Ctrl+B
|
|
110
|
+
* query, F9): every armed collect whose compound key starts with the session
|
|
111
|
+
* prefix. A promoted/settled/aborted collect unregisters itself, so an
|
|
112
|
+
* armed entry here is exactly a promotable foreground wait.
|
|
113
|
+
*/
|
|
114
|
+
export function collectorsForSession(parentSessionId) {
|
|
115
|
+
const prefix = `${parentSessionId}\u0000`;
|
|
116
|
+
const found = [];
|
|
117
|
+
for (const [key, handle] of registrations) {
|
|
118
|
+
if (key.startsWith(prefix))
|
|
119
|
+
found.push(handle);
|
|
120
|
+
}
|
|
121
|
+
return found;
|
|
122
|
+
}
|
|
123
|
+
/** Instrumentation for tests and diagnostics: live registration count. */
|
|
124
|
+
export function registeredCollectorCount() {
|
|
125
|
+
return registrations.size;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Collect a continuable child's first epoch inline. Never awaits the parent's
|
|
129
|
+
* inbound messages — only bus events (§3 deadlock rule).
|
|
130
|
+
*/
|
|
131
|
+
export async function collectFirstEpoch(deps) {
|
|
132
|
+
const { bus, childId, agent, signal, subagents, start } = deps;
|
|
133
|
+
markCollectedForSuppression(childId);
|
|
134
|
+
let resolveEntry;
|
|
135
|
+
const entry = { resolve: terminal => resolveEntry(terminal) };
|
|
136
|
+
const epochPromise = new Promise(resolve => {
|
|
137
|
+
resolveEntry = resolve;
|
|
138
|
+
});
|
|
139
|
+
let interrupted = false;
|
|
140
|
+
let promoted = false;
|
|
141
|
+
let settled = false;
|
|
142
|
+
let raceAbort;
|
|
143
|
+
const abortPromise = new Promise(resolve => {
|
|
144
|
+
raceAbort = resolve;
|
|
145
|
+
});
|
|
146
|
+
let resolvePromoted;
|
|
147
|
+
const promotedPromise = new Promise(resolve => {
|
|
148
|
+
resolvePromoted = resolve;
|
|
149
|
+
});
|
|
150
|
+
// The promotion-registry registration (§6): registered BEFORE start, so a
|
|
151
|
+
// Ctrl+B fired during the still-in-flight `startContinuable` finds the
|
|
152
|
+
// armed handle; unregistered on EVERY resolution path (settle, abort,
|
|
153
|
+
// promote, start-throw) — a resolved collect is never promotable.
|
|
154
|
+
const registrationKey = deps.parentSessionId !== undefined && deps.toolCallToken !== undefined
|
|
155
|
+
? collectorKey(deps.parentSessionId, deps.toolCallToken)
|
|
156
|
+
: undefined;
|
|
157
|
+
const registration = {
|
|
158
|
+
childId,
|
|
159
|
+
promote() {
|
|
160
|
+
// Idempotent: a collect already resolved (settled) or already promoted
|
|
161
|
+
// never re-releases, re-un-suppresses, or re-resolves.
|
|
162
|
+
if (settled || promoted)
|
|
163
|
+
return;
|
|
164
|
+
promoted = true;
|
|
165
|
+
// Release the watch: the runId-matched `subagent/end` arriving later
|
|
166
|
+
// resolves nothing — the epoch is no longer awaited (§6).
|
|
167
|
+
release(childId);
|
|
168
|
+
// The promoted child's eventual settlement notice flows NORMALLY
|
|
169
|
+
// (exactly-once, un-suppressed).
|
|
170
|
+
releaseCollectedForSuppression(childId);
|
|
171
|
+
resolvePromoted();
|
|
172
|
+
},
|
|
173
|
+
abort() {
|
|
174
|
+
if (settled || interrupted)
|
|
175
|
+
return;
|
|
176
|
+
onAbort();
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
const onAbort = () => {
|
|
180
|
+
if (interrupted)
|
|
181
|
+
return;
|
|
182
|
+
interrupted = true;
|
|
183
|
+
// Interrupt exactly once (M5); an absent/settled target is an accepted
|
|
184
|
+
// no-op, and an admission throw must never block the prompt resolve.
|
|
185
|
+
if (subagents?.interrupt !== undefined) {
|
|
186
|
+
try {
|
|
187
|
+
subagents.interrupt(childId, { kind: 'ancestor', agent });
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
// Degraded: the prompt resolve below is still prompt and observable.
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
raceAbort?.({ kind: 'aborted', stopReason: 'aborted' });
|
|
194
|
+
};
|
|
195
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
196
|
+
// Reserve BEFORE start (§8 race register).
|
|
197
|
+
watches.set(childId, entry);
|
|
198
|
+
ensureWatchers(bus);
|
|
199
|
+
if (registrationKey !== undefined)
|
|
200
|
+
registerCollector(registrationKey, registration);
|
|
201
|
+
const finish = () => {
|
|
202
|
+
settled = true;
|
|
203
|
+
if (registrationKey !== undefined)
|
|
204
|
+
unregisterCollector(registrationKey);
|
|
205
|
+
signal.removeEventListener('abort', onAbort);
|
|
206
|
+
};
|
|
207
|
+
try {
|
|
208
|
+
await start();
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
finish();
|
|
212
|
+
release(childId);
|
|
213
|
+
releaseCollectedForSuppression(childId);
|
|
214
|
+
throw error;
|
|
215
|
+
}
|
|
216
|
+
if (signal.aborted)
|
|
217
|
+
onAbort();
|
|
218
|
+
// Pre-acceptance promotion (§6): a promote() that fired while
|
|
219
|
+
// `startContinuable` was still in flight resolves the tool call AS SOON AS
|
|
220
|
+
// start resolves — the child is accepted, its id durable, the epoch never
|
|
221
|
+
// awaited. The watch was already released by promote(); the settled notice
|
|
222
|
+
// was already un-suppressed.
|
|
223
|
+
if (promoted) {
|
|
224
|
+
finish();
|
|
225
|
+
return { kind: 'promoted' };
|
|
226
|
+
}
|
|
227
|
+
const outcome = await Promise.race([
|
|
228
|
+
epochPromise.then((terminal) => ({ kind: 'epoch', ...terminal })),
|
|
229
|
+
abortPromise,
|
|
230
|
+
promotedPromise.then(() => ({ kind: 'promoted' })),
|
|
231
|
+
]);
|
|
232
|
+
finish();
|
|
233
|
+
if (outcome.kind === 'aborted') {
|
|
234
|
+
// Keep the watch entry armed ONLY to drive suppression bookkeeping: the
|
|
235
|
+
// child's real `subagent/end` arrives later and releases the entry.
|
|
236
|
+
return outcome;
|
|
237
|
+
}
|
|
238
|
+
// Epoch end already released the entry (and disposed the shared listeners
|
|
239
|
+
// when the map emptied); the suppression mark stays until the pop-once
|
|
240
|
+
// listener consumes the duplicated settled notice.
|
|
241
|
+
return outcome;
|
|
242
|
+
}
|
|
243
|
+
//# sourceMappingURL=epoch-collector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"epoch-collector.js","sourceRoot":"","sources":["../src/epoch-collector.ts"],"names":[],"mappings":"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"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code-compatible Task tool and per-workspace subagent catalog for the
|
|
3
|
+
* DeepSeek Harness. Mounts:
|
|
4
|
+
* - the `subagent_fork` tool (CC display name `Task`) with `subagent_type`
|
|
5
|
+
* dispatch over the session workspace's `.claude/agents` definitions;
|
|
6
|
+
* - the `Available subagents` system-prompt section rendered per workspace;
|
|
7
|
+
* - the reserved tool names that keep disabled harness rows restrictable;
|
|
8
|
+
* - a pre-step strip listener that removes the harness `agent-instructions`
|
|
9
|
+
* workspace baseline from delegated children so each child keeps its own
|
|
10
|
+
* persona instead of also loading the parent's CLAUDE.md / AGENTS.md.
|
|
11
|
+
*
|
|
12
|
+
* The `ccModelRoutes` service (from `@dsh-cc/model-aliases`) supplies
|
|
13
|
+
* the spawn-time alias resolver; when absent, every child inherits its
|
|
14
|
+
* parent's route (the builtin fallback).
|
|
15
|
+
*
|
|
16
|
+
* @module @dsh-cc/subagent-task
|
|
17
|
+
*/
|
|
18
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
19
|
+
import { type ResumePinsConfig } from './resume-capture.ts';
|
|
20
|
+
export { AgentRegistry } from './registry.ts';
|
|
21
|
+
export { registerTaskTool, TASK_TOOL, MAX_LIVE_CONTINUABLE_CHILDREN, CLAUDE_CODE_DISABLE_BACKGROUND_TASKS, backgroundTasksDisabled, } from './tool.ts';
|
|
22
|
+
export { collectFirstEpoch, collectorFor, collectorKey, registerCollector, unregisterCollector, collectorsForSession, registeredCollectorCount, markCollectedForSuppression, releaseCollectedForSuppression, isCollectedForSuppression, } from './epoch-collector.ts';
|
|
23
|
+
export type { CollectorRegistration, EpochOutcome, EpochTerminal, } from './epoch-collector.ts';
|
|
24
|
+
export { mountAgentCatalog } from './catalog.ts';
|
|
25
|
+
export { mountStripWorkspaceInstructions, isDelegated, isAgentInstructions, } from './strip-instructions.ts';
|
|
26
|
+
export { isSubagentSettledNotice, mountSettledNoticeSuppression, } from './suppress-settled.ts';
|
|
27
|
+
export type { ResumePinsConfig, CaptureInput } from './resume-capture.ts';
|
|
28
|
+
export { SpawnPinCapture, overlayRoute, probeWorkspace } from './resume-capture.ts';
|
|
29
|
+
/** Cordis plugin id. */
|
|
30
|
+
export declare const name = "cc-subagent-task";
|
|
31
|
+
/** Section name for the background-subagent contract. */
|
|
32
|
+
export declare const BACKGROUND_SECTION_NAME = "cc:subagent-background";
|
|
33
|
+
export declare const BACKGROUND_SECTION_TEXT: string;
|
|
34
|
+
/**
|
|
35
|
+
* Register the static background-loop system-prompt section (same contract the
|
|
36
|
+
* Task tool description teaches, stated once so it survives description
|
|
37
|
+
* trimming). No-op when the system-prompt seam is absent.
|
|
38
|
+
* @param ctx - the plug context.
|
|
39
|
+
* @returns the section disposer, or undefined when the seam is absent.
|
|
40
|
+
*/
|
|
41
|
+
export declare function mountBackgroundSection(ctx: Context): (() => void) | undefined;
|
|
42
|
+
/** Plugin configuration. */
|
|
43
|
+
export interface TaskPluginConfig {
|
|
44
|
+
/**
|
|
45
|
+
* Spawn-time resume-pin capture (plan §4.3/§4.5) for continuable background
|
|
46
|
+
* children. Absent (default) → zero behavior change: no pin writes, no
|
|
47
|
+
* preflight, identical spawns.
|
|
48
|
+
*/
|
|
49
|
+
readonly resumePins?: ResumePinsConfig;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Mount the Task tool, the agents catalog, and the workspace-instruction
|
|
53
|
+
* strip. Safe when either the tools or the system-prompt seam is absent
|
|
54
|
+
* (the corresponding mount skips); the pre-step listener only needs
|
|
55
|
+
* `ctx.on`, so it mounts regardless.
|
|
56
|
+
* @param ctx - the plug context.
|
|
57
|
+
* @param config - plugin configuration; omitted `resumePins` still arms capture
|
|
58
|
+
* when the resume-pins plugin's `resumePinStore` service is mounted (plan
|
|
59
|
+
* §4.10); with neither, capture is disabled.
|
|
60
|
+
*/
|
|
61
|
+
export declare function apply(ctx: Context, config?: TaskPluginConfig): void;
|
|
62
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAOlD,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAO5E,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,EACL,gBAAgB,EAChB,SAAS,EACT,6BAA6B,EAC7B,oCAAoC,EACpC,uBAAuB,GACxB,MAAM,WAAW,CAAA;AAClB,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,oBAAoB,EACpB,wBAAwB,EACxB,2BAA2B,EAC3B,8BAA8B,EAC9B,yBAAyB,GAC1B,MAAM,sBAAsB,CAAA;AAC7B,YAAY,EACV,qBAAqB,EACrB,YAAY,EACZ,aAAa,GACd,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAChD,OAAO,EACL,+BAA+B,EAC/B,WAAW,EACX,mBAAmB,GACpB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACL,uBAAuB,EACvB,6BAA6B,GAC9B,MAAM,uBAAuB,CAAA;AAC9B,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AACzE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAEnF,wBAAwB;AACxB,eAAO,MAAM,IAAI,qBAAqB,CAAA;AAEtC,yDAAyD;AACzD,eAAO,MAAM,uBAAuB,2BAA2B,CAAA;AAK/D,eAAO,MAAM,uBAAuB,QAwBxB,CAAA;AAEZ;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAU7E;AAED,4BAA4B;AAC5B,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,gBAAgB,CAAA;CACvC;AAED;;;;;;;;;GASG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,GAAE,gBAAqB,GAAG,IAAI,CAuBvE"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code-compatible Task tool and per-workspace subagent catalog for the
|
|
3
|
+
* DeepSeek Harness. Mounts:
|
|
4
|
+
* - the `subagent_fork` tool (CC display name `Task`) with `subagent_type`
|
|
5
|
+
* dispatch over the session workspace's `.claude/agents` definitions;
|
|
6
|
+
* - the `Available subagents` system-prompt section rendered per workspace;
|
|
7
|
+
* - the reserved tool names that keep disabled harness rows restrictable;
|
|
8
|
+
* - a pre-step strip listener that removes the harness `agent-instructions`
|
|
9
|
+
* workspace baseline from delegated children so each child keeps its own
|
|
10
|
+
* persona instead of also loading the parent's CLAUDE.md / AGENTS.md.
|
|
11
|
+
*
|
|
12
|
+
* The `ccModelRoutes` service (from `@dsh-cc/model-aliases`) supplies
|
|
13
|
+
* the spawn-time alias resolver; when absent, every child inherits its
|
|
14
|
+
* parent's route (the builtin fallback).
|
|
15
|
+
*
|
|
16
|
+
* @module @dsh-cc/subagent-task
|
|
17
|
+
*/
|
|
18
|
+
import { PinStore } from '@dsh-cc/subagent-resume-pins';
|
|
19
|
+
import { collectorFor, collectorsForSession, registeredCollectorCount, } from "./epoch-collector.js";
|
|
20
|
+
import { SpawnPinCapture } from "./resume-capture.js";
|
|
21
|
+
import { AgentRegistry } from "./registry.js";
|
|
22
|
+
import { registerTaskTool } from "./tool.js";
|
|
23
|
+
import { mountSettledNoticeSuppression } from "./suppress-settled.js";
|
|
24
|
+
import { mountAgentCatalog } from "./catalog.js";
|
|
25
|
+
import { mountStripWorkspaceInstructions } from "./strip-instructions.js";
|
|
26
|
+
export { AgentRegistry } from "./registry.js";
|
|
27
|
+
export { registerTaskTool, TASK_TOOL, MAX_LIVE_CONTINUABLE_CHILDREN, CLAUDE_CODE_DISABLE_BACKGROUND_TASKS, backgroundTasksDisabled, } from "./tool.js";
|
|
28
|
+
export { collectFirstEpoch, collectorFor, collectorKey, registerCollector, unregisterCollector, collectorsForSession, registeredCollectorCount, markCollectedForSuppression, releaseCollectedForSuppression, isCollectedForSuppression, } from "./epoch-collector.js";
|
|
29
|
+
export { mountAgentCatalog } from "./catalog.js";
|
|
30
|
+
export { mountStripWorkspaceInstructions, isDelegated, isAgentInstructions, } from "./strip-instructions.js";
|
|
31
|
+
export { isSubagentSettledNotice, mountSettledNoticeSuppression, } from "./suppress-settled.js";
|
|
32
|
+
export { SpawnPinCapture, overlayRoute, probeWorkspace } from "./resume-capture.js";
|
|
33
|
+
/** Cordis plugin id. */
|
|
34
|
+
export const name = 'cc-subagent-task';
|
|
35
|
+
/** Section name for the background-subagent contract. */
|
|
36
|
+
export const BACKGROUND_SECTION_NAME = 'cc:subagent-background';
|
|
37
|
+
/** Order slot beside the catalog section (tool guidance owns 100–199). */
|
|
38
|
+
const BACKGROUND_SECTION_ORDER = 112;
|
|
39
|
+
export const BACKGROUND_SECTION_TEXT = [
|
|
40
|
+
'## Background subagents',
|
|
41
|
+
'',
|
|
42
|
+
'- Heuristic: if this turn\'s answer to the human depends on the child, omit `run_in_background`',
|
|
43
|
+
' (foreground — the call waits for the final text). If the human can keep talking while the',
|
|
44
|
+
' child works, pass `run_in_background: true`: the call returns promptly with a durable',
|
|
45
|
+
' `agentId` once the child accepts its first turn. Synthesize on the wake; do not poll.',
|
|
46
|
+
'- A definition with `background: true` backgrounds on omit: the call returns',
|
|
47
|
+
' `{ status: \'async_launched\' }` immediately and the real result arrives later as a wake',
|
|
48
|
+
' message — there is NO inline result to use, so never compose on one. Pass',
|
|
49
|
+
' `run_in_background: false` when this turn needs that child\'s result: it forces',
|
|
50
|
+
' synchronous collection. Explicit true/false always win over the pin.',
|
|
51
|
+
'- A background child\'s report — or its finish notice when it ends without reporting — arrives',
|
|
52
|
+
' as a waking message; do not poll.',
|
|
53
|
+
'- Control the child by that id: `list_agents` for status, `send_message` to continue the same',
|
|
54
|
+
' conversation (only the agent that started the child may continue it), `interrupt_agent` to',
|
|
55
|
+
' stop its current turn.',
|
|
56
|
+
'- A foreground wait may be user-promoted (Ctrl+B) to background while it runs: if a tool result',
|
|
57
|
+
' carries `status: \'async_launched\'` with `backgroundedByUser: true`, treat it exactly like a',
|
|
58
|
+
' background launch — the result arrives as a later wake; do not poll.',
|
|
59
|
+
'- `subagent_type: "fork"` cannot run in the background (upstream harness issue #2124); use a',
|
|
60
|
+
' plain background spawn instead.',
|
|
61
|
+
'- Exiting your session drains a background child\'s in-flight turn; its persisted session',
|
|
62
|
+
' survives and cold-resumes on the next `send_message`.',
|
|
63
|
+
].join('\n');
|
|
64
|
+
/**
|
|
65
|
+
* Register the static background-loop system-prompt section (same contract the
|
|
66
|
+
* Task tool description teaches, stated once so it survives description
|
|
67
|
+
* trimming). No-op when the system-prompt seam is absent.
|
|
68
|
+
* @param ctx - the plug context.
|
|
69
|
+
* @returns the section disposer, or undefined when the seam is absent.
|
|
70
|
+
*/
|
|
71
|
+
export function mountBackgroundSection(ctx) {
|
|
72
|
+
const seam = ctx.get('systemPrompt');
|
|
73
|
+
if (seam === undefined)
|
|
74
|
+
return undefined;
|
|
75
|
+
return seam.section({
|
|
76
|
+
name: BACKGROUND_SECTION_NAME,
|
|
77
|
+
order: BACKGROUND_SECTION_ORDER,
|
|
78
|
+
text: BACKGROUND_SECTION_TEXT,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Mount the Task tool, the agents catalog, and the workspace-instruction
|
|
83
|
+
* strip. Safe when either the tools or the system-prompt seam is absent
|
|
84
|
+
* (the corresponding mount skips); the pre-step listener only needs
|
|
85
|
+
* `ctx.on`, so it mounts regardless.
|
|
86
|
+
* @param ctx - the plug context.
|
|
87
|
+
* @param config - plugin configuration; omitted `resumePins` still arms capture
|
|
88
|
+
* when the resume-pins plugin's `resumePinStore` service is mounted (plan
|
|
89
|
+
* §4.10); with neither, capture is disabled.
|
|
90
|
+
*/
|
|
91
|
+
export function apply(ctx, config = {}) {
|
|
92
|
+
const registry = new AgentRegistry();
|
|
93
|
+
const pins = config.resumePins;
|
|
94
|
+
// Durability ordering (plan §4.6): when the resume-pins plugin is mounted
|
|
95
|
+
// its `resumePinStore` is THE store — gate, overlay, and capture must share
|
|
96
|
+
// one cache. Capture only falls back to its own config store/pinsRoot when
|
|
97
|
+
// no plugin-provided store exists (keeps the standalone config path working).
|
|
98
|
+
const sharedStore = ctx.get('resumePinStore');
|
|
99
|
+
// Production wiring (plan §4.10): the preset mounts the resume-pins plugin
|
|
100
|
+
// ahead of this row, so its service store arms capture with NO extra Task
|
|
101
|
+
// config. Explicit `resumePins` config still wins for standalone consumers.
|
|
102
|
+
const capture = pins === undefined
|
|
103
|
+
? sharedStore !== undefined
|
|
104
|
+
? new SpawnPinCapture(ctx, sharedStore)
|
|
105
|
+
: undefined
|
|
106
|
+
: new SpawnPinCapture(ctx, sharedStore ?? pins.store ?? new PinStore(pins.pinsRoot));
|
|
107
|
+
registerTaskTool(ctx, registry, capture);
|
|
108
|
+
mountAgentCatalog(ctx, registry);
|
|
109
|
+
mountBackgroundSection(ctx);
|
|
110
|
+
mountStripWorkspaceInstructions(ctx);
|
|
111
|
+
mountSettledNoticeSuppression(ctx);
|
|
112
|
+
publishCollectorRegistry(ctx);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Publish the Slice 3 promotion registry (collector doc §6) as the ROOT-realm
|
|
116
|
+
* `ccCollectorRegistry` service so the TUI busy-branch — a host-plane sibling
|
|
117
|
+
* that cannot resolve realm-interior mounts — queries the SAME live
|
|
118
|
+
* registration map the Task tool's collect path populates. Mirrors the
|
|
119
|
+
* command-agents `ccAgents` publication (CcPlugins pattern): first
|
|
120
|
+
* publication provides the name; a reclaim after an unload takes the slot
|
|
121
|
+
* back via `set`; the unload effect clears it so the TUI degrades to
|
|
122
|
+
* "nothing promotable" instead of holding a dead registry.
|
|
123
|
+
* @param ctx - the plug context.
|
|
124
|
+
*/
|
|
125
|
+
function publishCollectorRegistry(ctx) {
|
|
126
|
+
const root = ctx.root;
|
|
127
|
+
const registryService = {
|
|
128
|
+
collectorFor,
|
|
129
|
+
collectorsForSession,
|
|
130
|
+
registeredCollectorCount,
|
|
131
|
+
};
|
|
132
|
+
if (root.get('ccCollectorRegistry', false) === undefined) {
|
|
133
|
+
root.provide('ccCollectorRegistry', registryService);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
root.set('ccCollectorRegistry', registryService);
|
|
137
|
+
}
|
|
138
|
+
ctx.effect(() => () => {
|
|
139
|
+
if (root.get('ccCollectorRegistry', false) === registryService)
|
|
140
|
+
root.set('ccCollectorRegistry', undefined);
|
|
141
|
+
}, 'cc-subagent-task: clear host-realm ccCollectorRegistry publication on unload');
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spawn-time pre-activation of allow-listed deferred MCP tools for a Task
|
|
3
|
+
* child. A definition frontmatter naming an explicit deferred MCP tool
|
|
4
|
+
* (`mcp__<server>__<tool>`) leaves the child with a reserved-but-unregistered
|
|
5
|
+
* name; this module activates each such name through the duck-typed
|
|
6
|
+
* `ctx.toolSearch` seam BEFORE the child starts, so the tool is registered —
|
|
7
|
+
* process-globally — by the time the child's first tool assembly runs.
|
|
8
|
+
*
|
|
9
|
+
* Duck-typed so `src/` never imports `@dsh-cc/tool-search` — the
|
|
10
|
+
* package is a test-only devDependency; production stays pluggable (mirrors
|
|
11
|
+
* `packages/mcp/mcp-client/src/defer.ts`).
|
|
12
|
+
*
|
|
13
|
+
* @module @dsh-cc/subagent-task/preload-tools
|
|
14
|
+
*/
|
|
15
|
+
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
16
|
+
import type { ToolRestriction } from '@dsh-cc/claude-code-agents';
|
|
17
|
+
/** The structural subset of the `ctx.toolSearch` seam this module needs. */
|
|
18
|
+
export interface ToolSearchActivateSeam {
|
|
19
|
+
activate(name: string, scope?: unknown): {
|
|
20
|
+
status: 'loaded' | 'already-loaded' | 'denied' | 'unknown';
|
|
21
|
+
name: string;
|
|
22
|
+
reason?: string;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/** A structural view of the tools registry used to skip registered names. */
|
|
26
|
+
interface ToolsView {
|
|
27
|
+
get(name: string): unknown;
|
|
28
|
+
}
|
|
29
|
+
/** The outcome of one preload pass: what loaded and what did not (with why). */
|
|
30
|
+
export interface PreloadSummary {
|
|
31
|
+
preloaded: string[];
|
|
32
|
+
notices: string[];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Pre-activate the explicit deferred MCP names a definition's `tools:` allows.
|
|
36
|
+
*
|
|
37
|
+
* Selection rule: iterate the RAW allow entries. An entry is a candidate iff
|
|
38
|
+
* it is an explicit exact name (not a wildcard form) that survived into the
|
|
39
|
+
* SANITIZED allow list, is not excluded by the sanitized deny list, and is not
|
|
40
|
+
* already registered (a registered name is eager — activation is pointless).
|
|
41
|
+
* Each candidate is activated for the CALLING agent scope; `loaded` and
|
|
42
|
+
* `already-loaded` are silent successes, `denied`/`unknown` collect a notice
|
|
43
|
+
* and warn. No-op when there is no raw allow list, no calling agent, no
|
|
44
|
+
* sanitized allow list, or (single warn) no toolSearch seam.
|
|
45
|
+
*/
|
|
46
|
+
export declare function preloadDeferredFilterTools(opts: {
|
|
47
|
+
/** The definition's RAW toolRestriction (undefined → no-op). */
|
|
48
|
+
raw?: ToolRestriction | undefined;
|
|
49
|
+
/** The SANITIZED toolFilter the child will actually receive. */
|
|
50
|
+
sanitized?: ToolRestriction | undefined;
|
|
51
|
+
/** The duck-typed `ctx.toolSearch` seam (undefined → single warn + no-op). */
|
|
52
|
+
toolSearch?: ToolSearchActivateSeam | undefined;
|
|
53
|
+
/** The calling agent (`exec.agent`, undefined → no-op). */
|
|
54
|
+
agent?: Agent | undefined;
|
|
55
|
+
/** The duck-typed tools view (`ctx.tools`) used to skip registered names. */
|
|
56
|
+
tools?: ToolsView | undefined;
|
|
57
|
+
/** The warn sink (the context logger). */
|
|
58
|
+
warn: (message: string) => void;
|
|
59
|
+
}): PreloadSummary;
|
|
60
|
+
/**
|
|
61
|
+
* Render the preload summary as the Task result-text lines. Empty string when
|
|
62
|
+
* nothing happened (nothing preloaded and no notices).
|
|
63
|
+
*/
|
|
64
|
+
export declare function renderPreloadLines(summary: PreloadSummary): string;
|
|
65
|
+
export {};
|
|
66
|
+
//# sourceMappingURL=preload-tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preload-tools.d.ts","sourceRoot":"","sources":["../src/preload-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAKjE,4EAA4E;AAC5E,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG;QACvC,MAAM,EAAE,QAAQ,GAAG,gBAAgB,GAAG,QAAQ,GAAG,SAAS,CAAA;QAC1D,IAAI,EAAE,MAAM,CAAA;QACZ,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,CAAA;CACF;AAED,6EAA6E;AAC7E,UAAU,SAAS;IACjB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;CAC3B;AAED,gFAAgF;AAChF,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AAcD;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE;IAC/C,gEAAgE;IAChE,GAAG,CAAC,EAAE,eAAe,GAAG,SAAS,CAAA;IACjC,gEAAgE;IAChE,SAAS,CAAC,EAAE,eAAe,GAAG,SAAS,CAAA;IACvC,8EAA8E;IAC9E,UAAU,CAAC,EAAE,sBAAsB,GAAG,SAAS,CAAA;IAC/C,2DAA2D;IAC3D,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,CAAA;IACzB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,SAAS,GAAG,SAAS,CAAA;IAC7B,0CAA0C;IAC1C,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CAChC,GAAG,cAAc,CAuCjB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,CASlE"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spawn-time pre-activation of allow-listed deferred MCP tools for a Task
|
|
3
|
+
* child. A definition frontmatter naming an explicit deferred MCP tool
|
|
4
|
+
* (`mcp__<server>__<tool>`) leaves the child with a reserved-but-unregistered
|
|
5
|
+
* name; this module activates each such name through the duck-typed
|
|
6
|
+
* `ctx.toolSearch` seam BEFORE the child starts, so the tool is registered —
|
|
7
|
+
* process-globally — by the time the child's first tool assembly runs.
|
|
8
|
+
*
|
|
9
|
+
* Duck-typed so `src/` never imports `@dsh-cc/tool-search` — the
|
|
10
|
+
* package is a test-only devDependency; production stays pluggable (mirrors
|
|
11
|
+
* `packages/mcp/mcp-client/src/defer.ts`).
|
|
12
|
+
*
|
|
13
|
+
* @module @dsh-cc/subagent-task/preload-tools
|
|
14
|
+
*/
|
|
15
|
+
/** The MCP public-name prefix every bridged MCP tool carries on `ctx.tools`. */
|
|
16
|
+
const MCP_PUBLIC_PREFIX = 'mcp__';
|
|
17
|
+
/**
|
|
18
|
+
* Decide whether a RAW allow entry is a wildcard form (`mcp__<server>` bare,
|
|
19
|
+
* `mcp__<anything>__*` postfix, or the bare `mcp__`). Wildcards are
|
|
20
|
+
* restrict-only: their expansions are preloaded by name, never via this
|
|
21
|
+
* module (the expansion set is the sanitize step's business).
|
|
22
|
+
*/
|
|
23
|
+
function isWildcardEntry(name) {
|
|
24
|
+
if (!name.startsWith(MCP_PUBLIC_PREFIX))
|
|
25
|
+
return false;
|
|
26
|
+
const rest = name.slice(MCP_PUBLIC_PREFIX.length);
|
|
27
|
+
return rest.length === 0 || rest.endsWith('__*') || !rest.includes('__');
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Pre-activate the explicit deferred MCP names a definition's `tools:` allows.
|
|
31
|
+
*
|
|
32
|
+
* Selection rule: iterate the RAW allow entries. An entry is a candidate iff
|
|
33
|
+
* it is an explicit exact name (not a wildcard form) that survived into the
|
|
34
|
+
* SANITIZED allow list, is not excluded by the sanitized deny list, and is not
|
|
35
|
+
* already registered (a registered name is eager — activation is pointless).
|
|
36
|
+
* Each candidate is activated for the CALLING agent scope; `loaded` and
|
|
37
|
+
* `already-loaded` are silent successes, `denied`/`unknown` collect a notice
|
|
38
|
+
* and warn. No-op when there is no raw allow list, no calling agent, no
|
|
39
|
+
* sanitized allow list, or (single warn) no toolSearch seam.
|
|
40
|
+
*/
|
|
41
|
+
export function preloadDeferredFilterTools(opts) {
|
|
42
|
+
const { raw, sanitized, toolSearch, agent, tools, warn } = opts;
|
|
43
|
+
if (raw?.allow === undefined || raw.allow.length === 0)
|
|
44
|
+
return { preloaded: [], notices: [] };
|
|
45
|
+
if (agent === undefined)
|
|
46
|
+
return { preloaded: [], notices: [] };
|
|
47
|
+
if (toolSearch === undefined) {
|
|
48
|
+
warn('cc-task: no toolSearch service is mounted, so deferred MCP tools named explicitly in a '
|
|
49
|
+
+ 'subagent toolFilter cannot be pre-activated at spawn; they stay searchable-only');
|
|
50
|
+
return { preloaded: [], notices: [] };
|
|
51
|
+
}
|
|
52
|
+
const sanitizedAllow = sanitized?.allow;
|
|
53
|
+
if (sanitizedAllow === undefined)
|
|
54
|
+
return { preloaded: [], notices: [] };
|
|
55
|
+
const sanitizedDeny = sanitized?.deny;
|
|
56
|
+
const preloaded = [];
|
|
57
|
+
const notices = [];
|
|
58
|
+
for (const name of raw.allow) {
|
|
59
|
+
// Deferred tools live on the toolSearch registry, which in this
|
|
60
|
+
// composition only ever holds MCP tools; a non-MCP harness name (read,
|
|
61
|
+
// bash, reserved rows) can never be a deferred entry, and probing it
|
|
62
|
+
// would only farm spurious "unknown" notices.
|
|
63
|
+
if (!name.startsWith(MCP_PUBLIC_PREFIX))
|
|
64
|
+
continue;
|
|
65
|
+
if (isWildcardEntry(name))
|
|
66
|
+
continue;
|
|
67
|
+
if (!sanitizedAllow.includes(name))
|
|
68
|
+
continue;
|
|
69
|
+
if (sanitizedDeny !== undefined && sanitizedDeny.includes(name))
|
|
70
|
+
continue;
|
|
71
|
+
if (tools !== undefined && tools.get(name) !== undefined)
|
|
72
|
+
continue;
|
|
73
|
+
const outcome = toolSearch.activate(name, agent);
|
|
74
|
+
if (outcome.status === 'loaded' || outcome.status === 'already-loaded') {
|
|
75
|
+
preloaded.push(name);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
const reason = outcome.status === 'unknown'
|
|
79
|
+
? 'unknown to the toolSearch registry'
|
|
80
|
+
: outcome.reason?.replace(/^"[^"]*" is /, '');
|
|
81
|
+
const notice = reason !== undefined ? `${name} (${reason})` : `${name}`;
|
|
82
|
+
notices.push(notice);
|
|
83
|
+
warn(`cc-task: could not pre-activate deferred tool "${name}" for a subagent: ${notice}`);
|
|
84
|
+
}
|
|
85
|
+
return { preloaded, notices };
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Render the preload summary as the Task result-text lines. Empty string when
|
|
89
|
+
* nothing happened (nothing preloaded and no notices).
|
|
90
|
+
*/
|
|
91
|
+
export function renderPreloadLines(summary) {
|
|
92
|
+
const lines = [];
|
|
93
|
+
if (summary.preloaded.length > 0) {
|
|
94
|
+
lines.push(`Preloaded deferred tools for child: ${summary.preloaded.join(', ')}`);
|
|
95
|
+
}
|
|
96
|
+
if (summary.notices.length > 0) {
|
|
97
|
+
lines.push(`Not preloaded: ${summary.notices.join(', ')}`);
|
|
98
|
+
}
|
|
99
|
+
return lines.join('\n');
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=preload-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preload-tools.js","sourceRoot":"","sources":["../src/preload-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,gFAAgF;AAChF,MAAM,iBAAiB,GAAG,OAAO,CAAA;AAsBjC;;;;;GAKG;AACH,SAAS,eAAe,CAAC,IAAY;IACnC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC;QAAE,OAAO,KAAK,CAAA;IACrD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAA;IACjD,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;AAC1E,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,0BAA0B,CAAC,IAa1C;IACC,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI,CAAA;IAC/D,IAAI,GAAG,EAAE,KAAK,KAAK,SAAS,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAA;IAC7F,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAA;IAC9D,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,IAAI,CACF,yFAAyF;cACvF,iFAAiF,CACpF,CAAA;QACD,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAA;IACvC,CAAC;IACD,MAAM,cAAc,GAAG,SAAS,EAAE,KAAK,CAAA;IACvC,IAAI,cAAc,KAAK,SAAS;QAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAA;IACvE,MAAM,aAAa,GAAG,SAAS,EAAE,IAAI,CAAA;IACrC,MAAM,SAAS,GAAa,EAAE,CAAA;IAC9B,MAAM,OAAO,GAAa,EAAE,CAAA;IAC5B,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QAC7B,gEAAgE;QAChE,uEAAuE;QACvE,qEAAqE;QACrE,8CAA8C;QAC9C,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC;YAAE,SAAQ;QACjD,IAAI,eAAe,CAAC,IAAI,CAAC;YAAE,SAAQ;QACnC,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,SAAQ;QAC5C,IAAI,aAAa,KAAK,SAAS,IAAI,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,SAAQ;QACzE,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,SAAS;YAAE,SAAQ;QAClE,MAAM,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QAChD,IAAI,OAAO,CAAC,MAAM,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM,KAAK,gBAAgB,EAAE,CAAC;YACvE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACpB,SAAQ;QACV,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,KAAK,SAAS;YACzC,CAAC,CAAC,oCAAoC;YACtC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAA;QAC/C,MAAM,MAAM,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,CAAA;QACvE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QACpB,IAAI,CAAC,kDAAkD,IAAI,qBAAqB,MAAM,EAAE,CAAC,CAAA;IAC3F,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAA;AAC/B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAuB;IACxD,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,IAAI,OAAO,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,uCAAuC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACnF,CAAC;IACD,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,KAAK,CAAC,IAAI,CAAC,kBAAkB,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAC5D,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC"}
|