@gajae-code/coding-agent 0.3.0 → 0.3.1
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/CHANGELOG.md +18 -0
- package/dist/types/async/job-manager.d.ts +7 -0
- package/dist/types/cli/args.d.ts +1 -1
- package/dist/types/commands/deep-interview.d.ts +3 -0
- package/dist/types/config/keybindings.d.ts +5 -0
- package/dist/types/config/settings-schema.d.ts +4 -4
- package/dist/types/debug/crash-diagnostics.d.ts +45 -0
- package/dist/types/debug/runtime-gauges.d.ts +6 -0
- package/dist/types/deep-interview/render-middleware.d.ts +1 -0
- package/dist/types/eval/py/executor.d.ts +2 -0
- package/dist/types/eval/py/kernel.d.ts +2 -0
- package/dist/types/exec/bash-executor.d.ts +10 -0
- package/dist/types/gjc-runtime/cli-write-receipt.d.ts +24 -0
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +1 -0
- package/dist/types/gjc-runtime/state-migrations.d.ts +9 -0
- package/dist/types/gjc-runtime/state-schema.d.ts +317 -0
- package/dist/types/gjc-runtime/state-writer.d.ts +10 -0
- package/dist/types/gjc-runtime/workflow-command-ref.d.ts +43 -0
- package/dist/types/harness-control-plane/control-endpoint.d.ts +3 -2
- package/dist/types/hooks/skill-state.d.ts +21 -0
- package/dist/types/internal-urls/agent-protocol.d.ts +2 -2
- package/dist/types/internal-urls/artifact-protocol.d.ts +2 -2
- package/dist/types/internal-urls/registry-helpers.d.ts +8 -7
- package/dist/types/internal-urls/types.d.ts +4 -0
- package/dist/types/lsp/index.d.ts +10 -10
- package/dist/types/modes/bridge/auth.d.ts +12 -0
- package/dist/types/modes/bridge/bridge-client-bridge.d.ts +9 -0
- package/dist/types/modes/bridge/bridge-mode.d.ts +44 -0
- package/dist/types/modes/bridge/bridge-ui-context.d.ts +88 -0
- package/dist/types/modes/bridge/event-stream.d.ts +8 -0
- package/dist/types/modes/components/custom-editor.d.ts +6 -0
- package/dist/types/modes/components/jobs-overlay-model.d.ts +31 -0
- package/dist/types/modes/components/jobs-overlay.d.ts +30 -0
- package/dist/types/modes/components/status-line/types.d.ts +2 -0
- package/dist/types/modes/components/status-line.d.ts +2 -0
- package/dist/types/modes/controllers/input-controller.d.ts +1 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +8 -0
- package/dist/types/modes/index.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -0
- package/dist/types/modes/jobs-observer.d.ts +57 -0
- package/dist/types/modes/rpc/host-tools.d.ts +1 -16
- package/dist/types/modes/rpc/host-uris.d.ts +1 -38
- package/dist/types/modes/shared/agent-wire/command-dispatch.d.ts +20 -0
- package/dist/types/modes/shared/agent-wire/command-validation.d.ts +2 -0
- package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +24 -0
- package/dist/types/modes/shared/agent-wire/handshake.d.ts +46 -0
- package/dist/types/modes/shared/agent-wire/host-tool-bridge.d.ts +16 -0
- package/dist/types/modes/shared/agent-wire/host-uri-bridge.d.ts +17 -0
- package/dist/types/modes/shared/agent-wire/protocol.d.ts +44 -0
- package/dist/types/modes/shared/agent-wire/responses.d.ts +4 -0
- package/dist/types/modes/shared/agent-wire/scopes.d.ts +18 -0
- package/dist/types/modes/shared/agent-wire/ui-request-broker.d.ts +42 -0
- package/dist/types/modes/shared/agent-wire/ui-result.d.ts +27 -0
- package/dist/types/modes/types.d.ts +1 -0
- package/dist/types/sdk.d.ts +2 -0
- package/dist/types/session/agent-session.d.ts +11 -1
- package/dist/types/skill-state/workflow-state-contract.d.ts +1 -2
- package/dist/types/skill-state/workflow-state-version.d.ts +3 -0
- package/dist/types/task/id.d.ts +7 -0
- package/dist/types/task/index.d.ts +5 -0
- package/dist/types/task/receipt.d.ts +85 -0
- package/dist/types/task/spawn-gate.d.ts +38 -0
- package/dist/types/task/types.d.ts +143 -11
- package/dist/types/tools/cron.d.ts +6 -0
- package/dist/types/tools/index.d.ts +2 -0
- package/dist/types/tools/path-utils.d.ts +1 -0
- package/dist/types/tools/subagent.d.ts +15 -0
- package/package.json +7 -7
- package/scripts/build-binary.ts +7 -0
- package/src/async/job-manager.ts +36 -0
- package/src/cli/args.ts +9 -2
- package/src/commands/deep-interview.ts +1 -0
- package/src/commands/harness.ts +289 -19
- package/src/commands/launch.ts +2 -2
- package/src/commands/state.ts +2 -1
- package/src/commands/team.ts +22 -4
- package/src/config/keybindings.ts +6 -0
- package/src/config/settings-schema.ts +6 -3
- package/src/dap/client.ts +17 -3
- package/src/debug/crash-diagnostics.ts +223 -0
- package/src/debug/runtime-gauges.ts +20 -0
- package/src/deep-interview/render-middleware.ts +6 -0
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +1 -1
- package/src/defaults/gjc/skills/ralplan/SKILL.md +31 -2
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +28 -2
- package/src/eval/py/executor.ts +21 -1
- package/src/eval/py/kernel.ts +15 -0
- package/src/exec/bash-executor.ts +41 -0
- package/src/gjc-runtime/cli-write-receipt.ts +31 -0
- package/src/gjc-runtime/deep-interview-runtime.ts +69 -32
- package/src/gjc-runtime/ralplan-runtime.ts +213 -36
- package/src/gjc-runtime/state-migrations.ts +54 -7
- package/src/gjc-runtime/state-runtime.ts +461 -64
- package/src/gjc-runtime/state-schema.ts +192 -0
- package/src/gjc-runtime/state-writer.ts +32 -1
- package/src/gjc-runtime/team-runtime.ts +177 -105
- package/src/gjc-runtime/ultragoal-runtime.ts +114 -26
- package/src/gjc-runtime/workflow-command-ref.ts +239 -0
- package/src/gjc-runtime/workflow-manifest.generated.json +108 -4
- package/src/gjc-runtime/workflow-manifest.ts +3 -1
- package/src/harness-control-plane/control-endpoint.ts +19 -8
- package/src/harness-control-plane/owner.ts +57 -10
- package/src/harness-control-plane/state-machine.ts +2 -1
- package/src/hooks/skill-state.ts +176 -26
- package/src/internal-urls/agent-protocol.ts +68 -21
- package/src/internal-urls/artifact-protocol.ts +12 -17
- package/src/internal-urls/docs-index.generated.ts +3 -2
- package/src/internal-urls/registry-helpers.ts +19 -16
- package/src/internal-urls/types.ts +4 -0
- package/src/lsp/client.ts +18 -2
- package/src/main.ts +21 -5
- package/src/modes/bridge/auth.ts +41 -0
- package/src/modes/bridge/bridge-client-bridge.ts +47 -0
- package/src/modes/bridge/bridge-mode.ts +520 -0
- package/src/modes/bridge/bridge-ui-context.ts +200 -0
- package/src/modes/bridge/event-stream.ts +70 -0
- package/src/modes/components/custom-editor.ts +101 -0
- package/src/modes/components/hook-selector.ts +61 -18
- package/src/modes/components/jobs-overlay-model.ts +109 -0
- package/src/modes/components/jobs-overlay.ts +172 -0
- package/src/modes/components/status-line/presets.ts +7 -5
- package/src/modes/components/status-line/segments.ts +25 -0
- package/src/modes/components/status-line/types.ts +2 -0
- package/src/modes/components/status-line.ts +9 -1
- package/src/modes/controllers/extension-ui-controller.ts +39 -3
- package/src/modes/controllers/input-controller.ts +97 -9
- package/src/modes/controllers/selector-controller.ts +29 -0
- package/src/modes/index.ts +1 -0
- package/src/modes/interactive-mode.ts +27 -0
- package/src/modes/jobs-observer.ts +204 -0
- package/src/modes/rpc/host-tools.ts +1 -186
- package/src/modes/rpc/host-uris.ts +1 -235
- package/src/modes/rpc/rpc-client.ts +25 -10
- package/src/modes/rpc/rpc-mode.ts +12 -381
- package/src/modes/shared/agent-wire/command-dispatch.ts +341 -0
- package/src/modes/shared/agent-wire/command-validation.ts +131 -0
- package/src/modes/shared/agent-wire/event-envelope.ts +108 -0
- package/src/modes/shared/agent-wire/handshake.ts +117 -0
- package/src/modes/shared/agent-wire/host-tool-bridge.ts +194 -0
- package/src/modes/shared/agent-wire/host-uri-bridge.ts +236 -0
- package/src/modes/shared/agent-wire/protocol.ts +96 -0
- package/src/modes/shared/agent-wire/responses.ts +17 -0
- package/src/modes/shared/agent-wire/scopes.ts +89 -0
- package/src/modes/shared/agent-wire/ui-request-broker.ts +150 -0
- package/src/modes/shared/agent-wire/ui-result.ts +48 -0
- package/src/modes/types.ts +1 -0
- package/src/prompts/tools/subagent.md +12 -7
- package/src/prompts/tools/task-summary.md +3 -9
- package/src/prompts/tools/task.md +5 -1
- package/src/sdk.ts +4 -0
- package/src/session/agent-session.ts +214 -38
- package/src/skill-state/deep-interview-mutation-guard.ts +23 -4
- package/src/skill-state/workflow-state-contract.ts +7 -4
- package/src/skill-state/workflow-state-version.ts +3 -0
- package/src/slash-commands/builtin-registry.ts +8 -0
- package/src/task/executor.ts +29 -5
- package/src/task/id.ts +33 -0
- package/src/task/index.ts +257 -67
- package/src/task/output-manager.ts +5 -4
- package/src/task/receipt.ts +297 -0
- package/src/task/render.ts +48 -131
- package/src/task/spawn-gate.ts +132 -0
- package/src/task/types.ts +48 -7
- package/src/tools/ask.ts +73 -33
- package/src/tools/ast-edit.ts +1 -0
- package/src/tools/ast-grep.ts +1 -0
- package/src/tools/bash.ts +1 -1
- package/src/tools/cron.ts +48 -0
- package/src/tools/find.ts +4 -1
- package/src/tools/index.ts +2 -0
- package/src/tools/path-utils.ts +3 -2
- package/src/tools/read.ts +1 -0
- package/src/tools/search.ts +1 -0
- package/src/tools/skill.ts +6 -1
- package/src/tools/subagent.ts +237 -84
package/src/task/index.ts
CHANGED
|
@@ -31,6 +31,7 @@ import { formatBytes, formatDuration } from "../tools/render-utils";
|
|
|
31
31
|
import {
|
|
32
32
|
type AgentDefinition,
|
|
33
33
|
type AgentProgress,
|
|
34
|
+
type ForkContextMode,
|
|
34
35
|
type ForkContextPolicy,
|
|
35
36
|
getTaskSchema,
|
|
36
37
|
type SingleResult,
|
|
@@ -46,10 +47,13 @@ import { generateCommitMessage } from "../utils/commit-message-generator";
|
|
|
46
47
|
import * as git from "../utils/git";
|
|
47
48
|
import { discoverAgents, filterVisibleAgents, getAgent } from "./discovery";
|
|
48
49
|
import { runSubprocess } from "./executor";
|
|
50
|
+
import { getTaskIdValidationError, validateAllocatedTaskId } from "./id";
|
|
49
51
|
import { AgentOutputManager } from "./output-manager";
|
|
50
52
|
import { mapWithConcurrencyLimit, Semaphore } from "./parallel";
|
|
53
|
+
import { assertNoRawTaskFields, buildTaskReceipt, buildTaskRoiSummary } from "./receipt";
|
|
51
54
|
import { renderResult, renderCall as renderTaskCall } from "./render";
|
|
52
55
|
import { getTaskSimpleModeCapabilities, type TaskSimpleMode } from "./simple-mode";
|
|
56
|
+
import { DEFAULT_SPAWN_THRESHOLD, evaluateReviewerExploreGate, evaluateSpawnGate } from "./spawn-gate";
|
|
53
57
|
import {
|
|
54
58
|
applyNestedPatches,
|
|
55
59
|
captureBaseline,
|
|
@@ -122,11 +126,37 @@ function addUsageTotals(target: Usage, usage: Partial<Usage>): void {
|
|
|
122
126
|
target.cost.total += cost.total;
|
|
123
127
|
}
|
|
124
128
|
|
|
129
|
+
function validateTaskIdsForScheduling(tasks: readonly TaskItem[]): string | undefined {
|
|
130
|
+
const invalid: string[] = [];
|
|
131
|
+
for (let i = 0; i < tasks.length; i++) {
|
|
132
|
+
const error = getTaskIdValidationError(tasks[i]?.id);
|
|
133
|
+
if (error) invalid.push(`index ${i}: ${error}`);
|
|
134
|
+
}
|
|
135
|
+
return invalid.length > 0 ? `Invalid task ids: ${invalid.join(" ")}` : undefined;
|
|
136
|
+
}
|
|
137
|
+
|
|
125
138
|
// Re-export types and utilities
|
|
126
139
|
export { loadBundledAgents as BUNDLED_AGENTS } from "./agents";
|
|
127
140
|
export { discoverCommands, expandCommand, getCommand } from "./commands";
|
|
128
141
|
export { discoverAgents, getAgent } from "./discovery";
|
|
142
|
+
export {
|
|
143
|
+
isValidAllocatedTaskId,
|
|
144
|
+
isValidTaskId,
|
|
145
|
+
TASK_ID_DESCRIPTION,
|
|
146
|
+
TASK_ID_PATTERN,
|
|
147
|
+
validateAllocatedTaskId,
|
|
148
|
+
validateTaskId,
|
|
149
|
+
} from "./id";
|
|
129
150
|
export { AgentOutputManager } from "./output-manager";
|
|
151
|
+
export type { TaskResultReceipt } from "./receipt";
|
|
152
|
+
export {
|
|
153
|
+
assertNoRawTaskFields,
|
|
154
|
+
buildTaskReceipt,
|
|
155
|
+
buildTaskRoi,
|
|
156
|
+
buildTaskRoiSummary,
|
|
157
|
+
findRawTaskLeakKeys,
|
|
158
|
+
sanitizeTaskToolDetails,
|
|
159
|
+
} from "./receipt";
|
|
130
160
|
export type {
|
|
131
161
|
AgentDefinition,
|
|
132
162
|
AgentProgress,
|
|
@@ -203,6 +233,14 @@ function validateTaskModeParams(simpleMode: TaskSimpleMode, params: TaskParams):
|
|
|
203
233
|
if (!customSchemaEnabled && params.schema !== undefined) {
|
|
204
234
|
disallowedFields.push("schema");
|
|
205
235
|
}
|
|
236
|
+
if (!contextEnabled) {
|
|
237
|
+
const inheritedTaskIds = (params.tasks ?? [])
|
|
238
|
+
.filter(task => task.inheritContext !== undefined && task.inheritContext !== "none")
|
|
239
|
+
.map(task => task.id);
|
|
240
|
+
if (inheritedTaskIds.length > 0) {
|
|
241
|
+
disallowedFields.push(`inheritContext for task(s) ${inheritedTaskIds.join(", ")}`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
206
244
|
if (disallowedFields.length === 0) {
|
|
207
245
|
return undefined;
|
|
208
246
|
}
|
|
@@ -212,22 +250,77 @@ function validateTaskModeParams(simpleMode: TaskSimpleMode, params: TaskParams):
|
|
|
212
250
|
}
|
|
213
251
|
|
|
214
252
|
if (disallowedFields.length === 1) {
|
|
215
|
-
return `task.simple is set to independent, so the task tool does not accept
|
|
253
|
+
return `task.simple is set to independent, so the task tool does not accept ${disallowedFields[0].startsWith("inheritContext") ? disallowedFields[0] : `\`${disallowedFields[0]}\``}. Put everything the subagent needs inside each task assignment.`;
|
|
216
254
|
}
|
|
217
255
|
|
|
218
|
-
return
|
|
256
|
+
return `task.simple is set to independent, so the task tool does not accept ${disallowedFields.map(field => (field.startsWith("inheritContext") ? field : `\`${field}\``)).join(", ")}. Put all required background and output expectations inside each task assignment or the selected agent definition.`;
|
|
219
257
|
}
|
|
220
258
|
|
|
221
259
|
function getForkContextPolicy(agent: AgentDefinition): ForkContextPolicy {
|
|
222
260
|
return agent.forkContext ?? "forbidden";
|
|
223
261
|
}
|
|
262
|
+
const FORK_CONTEXT_MODES = [
|
|
263
|
+
"none",
|
|
264
|
+
"receipt",
|
|
265
|
+
"last-turn",
|
|
266
|
+
"bounded",
|
|
267
|
+
"full",
|
|
268
|
+
] as const satisfies readonly ForkContextMode[];
|
|
269
|
+
const FORK_CONTEXT_MODE_SET = new Set<unknown>(FORK_CONTEXT_MODES);
|
|
270
|
+
const FORK_CONTEXT_REQUEST_MODES = ["receipt", "last-turn", "bounded", "full"] as const satisfies readonly Exclude<
|
|
271
|
+
ForkContextMode,
|
|
272
|
+
"none"
|
|
273
|
+
>[];
|
|
274
|
+
const FORK_CONTEXT_REQUEST_MODE_SET = new Set<unknown>(FORK_CONTEXT_REQUEST_MODES);
|
|
275
|
+
|
|
276
|
+
function isValidForkContextMode(value: unknown): value is ForkContextMode {
|
|
277
|
+
return FORK_CONTEXT_MODE_SET.has(value);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function requestsForkContext(
|
|
281
|
+
task: Pick<TaskItem, "inheritContext">,
|
|
282
|
+
): task is TaskItem & { inheritContext: Exclude<ForkContextMode, "none"> } {
|
|
283
|
+
return FORK_CONTEXT_REQUEST_MODE_SET.has(task.inheritContext);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function resolveForkSeedParamsForMode(
|
|
287
|
+
mode: ForkContextMode,
|
|
288
|
+
configuredMaxMessages: number | undefined,
|
|
289
|
+
configuredMaxTokens: number,
|
|
290
|
+
model: Model | undefined,
|
|
291
|
+
): { maxMessages: number; maxTokens: number } | undefined {
|
|
292
|
+
const capMessages = (defaultMaxMessages: number): number =>
|
|
293
|
+
configuredMaxMessages === undefined
|
|
294
|
+
? defaultMaxMessages
|
|
295
|
+
: Math.min(defaultMaxMessages, Math.max(0, Math.trunc(configuredMaxMessages)));
|
|
296
|
+
switch (mode) {
|
|
297
|
+
case "none":
|
|
298
|
+
return undefined;
|
|
299
|
+
case "receipt":
|
|
300
|
+
return { maxMessages: 1, maxTokens: 64 };
|
|
301
|
+
case "last-turn":
|
|
302
|
+
return { maxMessages: 2, maxTokens: 250 };
|
|
303
|
+
case "bounded":
|
|
304
|
+
return { maxMessages: capMessages(50), maxTokens: 250 };
|
|
305
|
+
case "full":
|
|
306
|
+
return { maxMessages: capMessages(500), maxTokens: resolveForkContextMaxTokens(configuredMaxTokens, model) };
|
|
307
|
+
default:
|
|
308
|
+
return undefined;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
224
311
|
|
|
225
312
|
function validateForkContextRequests(
|
|
226
313
|
tasks: readonly TaskItem[],
|
|
227
314
|
agent: AgentDefinition,
|
|
228
315
|
forkContextEnabled: boolean,
|
|
229
316
|
): string | undefined {
|
|
230
|
-
const
|
|
317
|
+
const invalidTaskIds = tasks
|
|
318
|
+
.filter(task => task.inheritContext !== undefined && !isValidForkContextMode(task.inheritContext as unknown))
|
|
319
|
+
.map(task => task.id);
|
|
320
|
+
if (invalidTaskIds.length > 0) {
|
|
321
|
+
return `Invalid inheritContext for task(s) ${invalidTaskIds.join(", ")}. Allowed modes: ${FORK_CONTEXT_MODES.join(", ")}.`;
|
|
322
|
+
}
|
|
323
|
+
const requested = tasks.filter(requestsForkContext);
|
|
231
324
|
if (requested.length === 0) return undefined;
|
|
232
325
|
const taskIds = requested.map(task => task.id).join(", ");
|
|
233
326
|
if (!forkContextEnabled) {
|
|
@@ -239,10 +332,10 @@ function validateForkContextRequests(
|
|
|
239
332
|
return undefined;
|
|
240
333
|
}
|
|
241
334
|
|
|
242
|
-
function resolveForkContextMaxTokens(configured: number, model: Model | undefined): number {
|
|
335
|
+
export function resolveForkContextMaxTokens(configured: number, model: Model | undefined): number {
|
|
243
336
|
if (configured > 0) return Math.trunc(configured);
|
|
244
337
|
const contextWindow = model?.contextWindow ?? 0;
|
|
245
|
-
return contextWindow > 0 ? Math.max(1, Math.floor(contextWindow * 0.
|
|
338
|
+
return contextWindow > 0 ? Math.max(1, Math.floor(contextWindow * 0.15)) : 15_000;
|
|
246
339
|
}
|
|
247
340
|
|
|
248
341
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -264,6 +357,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
264
357
|
readonly renderResult = renderResult;
|
|
265
358
|
readonly #discoveredAgents: AgentDefinition[];
|
|
266
359
|
readonly #blockedAgent: string | undefined;
|
|
360
|
+
readonly #spawningAgentType: string | undefined;
|
|
267
361
|
|
|
268
362
|
get parameters(): TaskToolSchemaInstance {
|
|
269
363
|
const isolationEnabled = this.session.settings.get("task.isolation.mode") !== "none";
|
|
@@ -295,6 +389,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
295
389
|
discoveredAgents: AgentDefinition[],
|
|
296
390
|
) {
|
|
297
391
|
this.#blockedAgent = $env.PI_BLOCKED_AGENT;
|
|
392
|
+
this.#spawningAgentType = session.currentAgentType;
|
|
298
393
|
this.#discoveredAgents = discoveredAgents;
|
|
299
394
|
}
|
|
300
395
|
|
|
@@ -324,10 +419,13 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
324
419
|
}
|
|
325
420
|
|
|
326
421
|
const taskItems = params.tasks ?? [];
|
|
422
|
+
const taskIdValidationError = validateTaskIdsForScheduling(taskItems);
|
|
423
|
+
if (taskIdValidationError) {
|
|
424
|
+
return createTaskModeError(taskIdValidationError);
|
|
425
|
+
}
|
|
327
426
|
if (taskItems.length === 0) {
|
|
328
427
|
return this.#executeSync(_toolCallId, params, signal, onUpdate);
|
|
329
428
|
}
|
|
330
|
-
|
|
331
429
|
const agent = getAgent(this.#discoveredAgents, params.agent);
|
|
332
430
|
if (!agent) {
|
|
333
431
|
const available =
|
|
@@ -365,6 +463,36 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
365
463
|
return createTaskModeError(forkContextValidationError);
|
|
366
464
|
}
|
|
367
465
|
|
|
466
|
+
const batchGateDecision = evaluateSpawnGate({ childCount: taskItems.length, plan: params.spawnPlan });
|
|
467
|
+
if (batchGateDecision.outcome === "rejected") {
|
|
468
|
+
return {
|
|
469
|
+
content: [
|
|
470
|
+
{
|
|
471
|
+
type: "text",
|
|
472
|
+
text: `Task spawn gate rejected this batch: ${batchGateDecision.reason}. Batches with more than ${DEFAULT_SPAWN_THRESHOLD} tasks require spawnPlan fields: ${batchGateDecision.missingFields.join(", ")}.`,
|
|
473
|
+
},
|
|
474
|
+
],
|
|
475
|
+
details: { projectAgentsDir: null, results: [], totalDurationMs: 0 },
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const reviewerExploreDecision = evaluateReviewerExploreGate({
|
|
480
|
+
spawningAgentType: this.#spawningAgentType,
|
|
481
|
+
targetAgent: params.agent,
|
|
482
|
+
plan: params.spawnPlan,
|
|
483
|
+
});
|
|
484
|
+
if (reviewerExploreDecision.outcome === "rejected") {
|
|
485
|
+
return {
|
|
486
|
+
content: [
|
|
487
|
+
{
|
|
488
|
+
type: "text",
|
|
489
|
+
text: `Task spawn gate rejected reviewer->explore: ${reviewerExploreDecision.reason}. Provide spawnPlan fields: ${reviewerExploreDecision.missingFields.join(", ")}.`,
|
|
490
|
+
},
|
|
491
|
+
],
|
|
492
|
+
details: { projectAgentsDir: null, results: [], totalDurationMs: 0 },
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
|
|
368
496
|
const manager = AsyncJobManager.instance();
|
|
369
497
|
if (!manager) {
|
|
370
498
|
return {
|
|
@@ -474,15 +602,23 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
474
602
|
}
|
|
475
603
|
const semaphore = new Semaphore(maxConcurrency);
|
|
476
604
|
const buildForkContextSeedForTask = async (task: TaskItem): Promise<ForkContextSeed | undefined> => {
|
|
477
|
-
if (task
|
|
605
|
+
if (!requestsForkContext(task)) return undefined;
|
|
478
606
|
if (!this.session.buildForkContextSeed) {
|
|
479
607
|
throw new Error("Current session cannot build fork-context seeds.");
|
|
480
608
|
}
|
|
481
|
-
const
|
|
609
|
+
const configuredMaxMessages = this.session.settings.has("task.forkContext.maxMessages")
|
|
610
|
+
? this.session.settings.get("task.forkContext.maxMessages")
|
|
611
|
+
: undefined;
|
|
482
612
|
const configuredMaxTokens = this.session.settings.get("task.forkContext.maxTokens");
|
|
613
|
+
const params = resolveForkSeedParamsForMode(
|
|
614
|
+
task.inheritContext,
|
|
615
|
+
configuredMaxMessages,
|
|
616
|
+
configuredMaxTokens,
|
|
617
|
+
this.session.model,
|
|
618
|
+
);
|
|
619
|
+
if (!params) return undefined;
|
|
483
620
|
return await this.session.buildForkContextSeed({
|
|
484
|
-
|
|
485
|
-
maxTokens: resolveForkContextMaxTokens(configuredMaxTokens, this.session.model),
|
|
621
|
+
...params,
|
|
486
622
|
signal,
|
|
487
623
|
});
|
|
488
624
|
};
|
|
@@ -501,7 +637,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
501
637
|
continue;
|
|
502
638
|
}
|
|
503
639
|
|
|
504
|
-
const uniqueId = uniqueIds[i];
|
|
640
|
+
const uniqueId = validateAllocatedTaskId(uniqueIds[i] ?? "");
|
|
505
641
|
const frozenForkSeed = await buildForkContextSeedForTask(taskItem);
|
|
506
642
|
if (frozenForkSeed) frozenForkSeeds.set(uniqueId, frozenForkSeed);
|
|
507
643
|
const singleParams: TaskParams = { ...params, tasks: [taskItem] };
|
|
@@ -548,7 +684,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
548
684
|
? "paused"
|
|
549
685
|
: singleResult?.aborted
|
|
550
686
|
? "aborted"
|
|
551
|
-
:
|
|
687
|
+
: singleResult?.status === "completed"
|
|
552
688
|
? "completed"
|
|
553
689
|
: "failed";
|
|
554
690
|
progress.durationMs = singleResult?.durationMs ?? Math.max(0, Date.now() - startedAt);
|
|
@@ -556,8 +692,13 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
556
692
|
progress.contextTokens = singleResult?.contextTokens;
|
|
557
693
|
progress.contextWindow = singleResult?.contextWindow;
|
|
558
694
|
progress.cost = singleResult?.usage?.cost.total ?? 0;
|
|
559
|
-
progress.extractedToolData =
|
|
560
|
-
progress.retryFailure = singleResult?.retryFailure
|
|
695
|
+
progress.extractedToolData = undefined;
|
|
696
|
+
progress.retryFailure = singleResult?.retryFailure
|
|
697
|
+
? {
|
|
698
|
+
attempt: singleResult.retryFailure.attempt,
|
|
699
|
+
errorMessage: singleResult.retryFailure.errorSummary,
|
|
700
|
+
}
|
|
701
|
+
: undefined;
|
|
561
702
|
progress.retryState = undefined;
|
|
562
703
|
}
|
|
563
704
|
completedJobs += 1;
|
|
@@ -915,6 +1056,44 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
915
1056
|
};
|
|
916
1057
|
}
|
|
917
1058
|
|
|
1059
|
+
const batchGateDecision = evaluateSpawnGate({ childCount: tasks.length, plan: params.spawnPlan });
|
|
1060
|
+
if (batchGateDecision.outcome === "rejected") {
|
|
1061
|
+
return {
|
|
1062
|
+
content: [
|
|
1063
|
+
{
|
|
1064
|
+
type: "text",
|
|
1065
|
+
text: `Task spawn gate rejected this batch: ${batchGateDecision.reason}. Batches with more than ${DEFAULT_SPAWN_THRESHOLD} tasks require spawnPlan fields: ${batchGateDecision.missingFields.join(", ")}.`,
|
|
1066
|
+
},
|
|
1067
|
+
],
|
|
1068
|
+
details: {
|
|
1069
|
+
projectAgentsDir,
|
|
1070
|
+
results: [],
|
|
1071
|
+
totalDurationMs: Date.now() - startTime,
|
|
1072
|
+
},
|
|
1073
|
+
};
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
const reviewerExploreDecision = evaluateReviewerExploreGate({
|
|
1077
|
+
spawningAgentType: this.#spawningAgentType,
|
|
1078
|
+
targetAgent: agentName,
|
|
1079
|
+
plan: params.spawnPlan,
|
|
1080
|
+
});
|
|
1081
|
+
if (reviewerExploreDecision.outcome === "rejected") {
|
|
1082
|
+
return {
|
|
1083
|
+
content: [
|
|
1084
|
+
{
|
|
1085
|
+
type: "text",
|
|
1086
|
+
text: `Task spawn gate rejected reviewer->explore: ${reviewerExploreDecision.reason}. Provide spawnPlan fields: ${reviewerExploreDecision.missingFields.join(", ")}.`,
|
|
1087
|
+
},
|
|
1088
|
+
],
|
|
1089
|
+
details: {
|
|
1090
|
+
projectAgentsDir,
|
|
1091
|
+
results: [],
|
|
1092
|
+
totalDurationMs: Date.now() - startTime,
|
|
1093
|
+
},
|
|
1094
|
+
};
|
|
1095
|
+
}
|
|
1096
|
+
|
|
918
1097
|
let repoRoot: string | null = null;
|
|
919
1098
|
let baseline: WorktreeBaseline | null = null;
|
|
920
1099
|
if (isIsolated) {
|
|
@@ -1040,7 +1219,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1040
1219
|
this.session.agentOutputManager ?? new AgentOutputManager(this.session.getArtifactsDir ?? (() => null));
|
|
1041
1220
|
uniqueIds = await outputManager.allocateBatch(tasks.map(t => t.id));
|
|
1042
1221
|
}
|
|
1043
|
-
const tasksWithUniqueIds = tasks.map((t, i) => ({ ...t, id: uniqueIds[i] }));
|
|
1222
|
+
const tasksWithUniqueIds = tasks.map((t, i) => ({ ...t, id: validateAllocatedTaskId(uniqueIds[i] ?? "") }));
|
|
1044
1223
|
|
|
1045
1224
|
const availableSkills = [...(this.session.skills ?? [])];
|
|
1046
1225
|
// Resolve autoload skills from agent definition against available skills
|
|
@@ -1080,15 +1259,23 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1080
1259
|
emitProgress();
|
|
1081
1260
|
|
|
1082
1261
|
const buildForkContextSeed = async (task: (typeof tasksWithUniqueIds)[number]) => {
|
|
1083
|
-
if (task
|
|
1262
|
+
if (!requestsForkContext(task)) return undefined;
|
|
1084
1263
|
if (!this.session.buildForkContextSeed) {
|
|
1085
1264
|
throw new Error("Current session cannot build fork-context seeds.");
|
|
1086
1265
|
}
|
|
1087
|
-
const
|
|
1266
|
+
const configuredMaxMessages = this.session.settings.has("task.forkContext.maxMessages")
|
|
1267
|
+
? this.session.settings.get("task.forkContext.maxMessages")
|
|
1268
|
+
: undefined;
|
|
1088
1269
|
const configuredMaxTokens = this.session.settings.get("task.forkContext.maxTokens");
|
|
1270
|
+
const params = resolveForkSeedParamsForMode(
|
|
1271
|
+
task.inheritContext,
|
|
1272
|
+
configuredMaxMessages,
|
|
1273
|
+
configuredMaxTokens,
|
|
1274
|
+
this.session.model,
|
|
1275
|
+
);
|
|
1276
|
+
if (!params) return undefined;
|
|
1089
1277
|
return await this.session.buildForkContextSeed({
|
|
1090
|
-
|
|
1091
|
-
maxTokens: resolveForkContextMaxTokens(configuredMaxTokens, this.session.model),
|
|
1278
|
+
...params,
|
|
1092
1279
|
signal,
|
|
1093
1280
|
});
|
|
1094
1281
|
};
|
|
@@ -1103,9 +1290,12 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1103
1290
|
},
|
|
1104
1291
|
) => {
|
|
1105
1292
|
const forkContextSeed = prebuiltForkContextSeeds?.get(task.id) ?? (await buildForkContextSeed(task));
|
|
1293
|
+
const forkContext = requestsForkContext(task)
|
|
1294
|
+
? { mode: task.inheritContext, clonedTokens: forkContextSeed?.metadata.approximateTokens ?? 0 }
|
|
1295
|
+
: undefined;
|
|
1106
1296
|
const taskSessionFile = overrides?.sessionFile ?? executionOverrides?.sessionFiles?.get(task.id) ?? null;
|
|
1107
1297
|
if (!isIsolated) {
|
|
1108
|
-
|
|
1298
|
+
const result = await runSubprocess({
|
|
1109
1299
|
cwd: this.session.cwd,
|
|
1110
1300
|
agent: effectiveAgent,
|
|
1111
1301
|
task: renderSubagentUserPrompt(task.assignment, simpleMode),
|
|
@@ -1149,6 +1339,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1149
1339
|
parentTelemetry: this.session.getTelemetry?.(),
|
|
1150
1340
|
forkContextSeed,
|
|
1151
1341
|
});
|
|
1342
|
+
return forkContext ? { ...result, forkContext } : result;
|
|
1152
1343
|
}
|
|
1153
1344
|
|
|
1154
1345
|
const taskStart = Date.now();
|
|
@@ -1207,7 +1398,8 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1207
1398
|
parentTelemetry: this.session.getTelemetry?.(),
|
|
1208
1399
|
forkContextSeed,
|
|
1209
1400
|
});
|
|
1210
|
-
|
|
1401
|
+
const resultWithForkContext = forkContext ? { ...result, forkContext } : result;
|
|
1402
|
+
if (mergeMode === "branch" && resultWithForkContext.exitCode === 0) {
|
|
1211
1403
|
try {
|
|
1212
1404
|
const commitMsg =
|
|
1213
1405
|
commitStyle === "ai" && this.session.modelRegistry
|
|
@@ -1227,35 +1419,40 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1227
1419
|
task.description,
|
|
1228
1420
|
commitMsg,
|
|
1229
1421
|
);
|
|
1422
|
+
const producedChanges = Boolean(commitResult?.branchName || commitResult?.nestedPatches.length);
|
|
1230
1423
|
return {
|
|
1231
|
-
...
|
|
1424
|
+
...resultWithForkContext,
|
|
1232
1425
|
branchName: commitResult?.branchName,
|
|
1233
1426
|
nestedPatches: commitResult?.nestedPatches,
|
|
1427
|
+
producedChanges,
|
|
1234
1428
|
};
|
|
1235
1429
|
} catch (mergeErr) {
|
|
1236
1430
|
// Agent succeeded but branch commit failed — clean up stale branch
|
|
1237
1431
|
const branchName = `gjc/task/${task.id}`;
|
|
1238
1432
|
await git.branch.tryDelete(repoRoot, branchName);
|
|
1239
1433
|
const msg = mergeErr instanceof Error ? mergeErr.message : String(mergeErr);
|
|
1240
|
-
return { ...
|
|
1434
|
+
return { ...resultWithForkContext, error: `Merge failed: ${msg}` };
|
|
1241
1435
|
}
|
|
1242
1436
|
}
|
|
1243
|
-
if (
|
|
1437
|
+
if (resultWithForkContext.exitCode === 0) {
|
|
1244
1438
|
try {
|
|
1245
1439
|
const delta = await captureDeltaPatch(isolationDir, taskBaseline);
|
|
1246
|
-
const
|
|
1440
|
+
const artifactId = validateAllocatedTaskId(task.id);
|
|
1441
|
+
const patchPath = path.join(effectiveArtifactsDir, `${artifactId}.patch`);
|
|
1247
1442
|
await Bun.write(patchPath, delta.rootPatch);
|
|
1443
|
+
const producedChanges = Boolean(delta.rootPatch.trim() || delta.nestedPatches.length);
|
|
1248
1444
|
return {
|
|
1249
|
-
...
|
|
1445
|
+
...resultWithForkContext,
|
|
1250
1446
|
patchPath,
|
|
1251
1447
|
nestedPatches: delta.nestedPatches,
|
|
1448
|
+
producedChanges,
|
|
1252
1449
|
};
|
|
1253
1450
|
} catch (patchErr) {
|
|
1254
1451
|
const msg = patchErr instanceof Error ? patchErr.message : String(patchErr);
|
|
1255
|
-
return { ...
|
|
1452
|
+
return { ...resultWithForkContext, error: `Patch capture failed: ${msg}` };
|
|
1256
1453
|
}
|
|
1257
1454
|
}
|
|
1258
|
-
return
|
|
1455
|
+
return resultWithForkContext;
|
|
1259
1456
|
} catch (err) {
|
|
1260
1457
|
const message = err instanceof Error ? err.message : String(err);
|
|
1261
1458
|
const assignment = task.assignment.trim();
|
|
@@ -1274,6 +1471,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1274
1471
|
durationMs: Date.now() - taskStart,
|
|
1275
1472
|
tokens: 0,
|
|
1276
1473
|
modelOverride,
|
|
1474
|
+
forkContext,
|
|
1277
1475
|
error: message,
|
|
1278
1476
|
};
|
|
1279
1477
|
} finally {
|
|
@@ -1318,6 +1516,17 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1318
1516
|
abortReason: "Cancelled before start",
|
|
1319
1517
|
};
|
|
1320
1518
|
});
|
|
1519
|
+
if (!artifactsDir) {
|
|
1520
|
+
for (const result of results) {
|
|
1521
|
+
delete result.outputMeta;
|
|
1522
|
+
delete result.outputPath;
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
const forkContextClonedTokens = results.reduce(
|
|
1527
|
+
(total, result) => total + (result.forkContext?.clonedTokens ?? 0),
|
|
1528
|
+
0,
|
|
1529
|
+
);
|
|
1321
1530
|
|
|
1322
1531
|
// Aggregate usage from executor results (already accumulated incrementally)
|
|
1323
1532
|
const aggregatedUsage = createUsageTotals();
|
|
@@ -1329,13 +1538,8 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1329
1538
|
}
|
|
1330
1539
|
}
|
|
1331
1540
|
|
|
1332
|
-
// Collect output paths (artifacts already written by executor in real-time)
|
|
1333
|
-
const outputPaths: string[] = [];
|
|
1334
1541
|
const patchPaths: string[] = [];
|
|
1335
1542
|
for (const result of results) {
|
|
1336
|
-
if (result.outputPath) {
|
|
1337
|
-
outputPaths.push(result.outputPath);
|
|
1338
|
-
}
|
|
1339
1543
|
if (result.patchPath) {
|
|
1340
1544
|
patchPaths.push(result.patchPath);
|
|
1341
1545
|
}
|
|
@@ -1431,7 +1635,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1431
1635
|
"<system-notification>Patches were not applied and must be handled manually.</system-notification>";
|
|
1432
1636
|
const patchList =
|
|
1433
1637
|
patchPaths.length > 0
|
|
1434
|
-
? `\n\nPatch artifacts
|
|
1638
|
+
? `\n\nPatch artifacts: ${patchPaths.length} preserved for internal merge recovery.`
|
|
1435
1639
|
: "";
|
|
1436
1640
|
mergeSummary = `\n\n${notification}${patchList}`;
|
|
1437
1641
|
}
|
|
@@ -1487,41 +1691,25 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1487
1691
|
const successCount = results.filter(r => r.exitCode === 0 && !r.error && !r.aborted).length;
|
|
1488
1692
|
const totalDuration = Date.now() - startTime;
|
|
1489
1693
|
|
|
1490
|
-
const
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
? "merge failed"
|
|
1495
|
-
: r.exitCode === 0
|
|
1496
|
-
? "completed"
|
|
1497
|
-
: `failed (exit ${r.exitCode})`;
|
|
1498
|
-
const output = r.output.trim() || r.stderr.trim() || "(no output)";
|
|
1499
|
-
const outputCharCount = r.outputMeta?.charCount ?? output.length;
|
|
1500
|
-
const fullOutputThreshold = 5000;
|
|
1501
|
-
let preview = output;
|
|
1502
|
-
let truncated = false;
|
|
1503
|
-
if (outputCharCount > fullOutputThreshold) {
|
|
1504
|
-
const slice = output.slice(0, fullOutputThreshold);
|
|
1505
|
-
const lastNewline = slice.lastIndexOf("\n");
|
|
1506
|
-
preview = lastNewline >= 0 ? slice.slice(0, lastNewline) : slice;
|
|
1507
|
-
truncated = true;
|
|
1508
|
-
}
|
|
1694
|
+
const receipts = results.map(buildTaskReceipt);
|
|
1695
|
+
const roiSummary = buildTaskRoiSummary(receipts);
|
|
1696
|
+
const summaries = receipts.map(r => {
|
|
1697
|
+
const status = r.status === "merge_failed" ? "merge failed" : r.status;
|
|
1509
1698
|
return {
|
|
1510
1699
|
agent: r.agent,
|
|
1511
1700
|
status,
|
|
1512
1701
|
id: r.id,
|
|
1513
|
-
preview,
|
|
1514
|
-
|
|
1515
|
-
meta: r.
|
|
1702
|
+
synopsis: r.preview,
|
|
1703
|
+
outputUri: r.outputRef?.uri,
|
|
1704
|
+
meta: r.outputRef
|
|
1516
1705
|
? {
|
|
1517
|
-
lineCount: r.
|
|
1518
|
-
charSize: formatBytes(r.
|
|
1706
|
+
lineCount: r.outputRef.lineCount,
|
|
1707
|
+
charSize: formatBytes(r.outputRef.sizeBytes),
|
|
1519
1708
|
}
|
|
1520
1709
|
: undefined,
|
|
1521
1710
|
};
|
|
1522
1711
|
});
|
|
1523
1712
|
|
|
1524
|
-
const outputIds = results.filter(r => !r.aborted || r.output.trim()).map(r => `agent://${r.id}`);
|
|
1525
1713
|
const summary = prompt.render(taskSummaryTemplate, {
|
|
1526
1714
|
successCount,
|
|
1527
1715
|
totalCount: results.length,
|
|
@@ -1529,7 +1717,6 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1529
1717
|
hasCancelledNote: aborted && cancelledCount > 0,
|
|
1530
1718
|
duration: formatDuration(totalDuration),
|
|
1531
1719
|
summaries,
|
|
1532
|
-
outputIds,
|
|
1533
1720
|
agentName,
|
|
1534
1721
|
mergeSummary,
|
|
1535
1722
|
});
|
|
@@ -1541,15 +1728,18 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1541
1728
|
await fs.rm(tempArtifactsDir, { recursive: true, force: true });
|
|
1542
1729
|
}
|
|
1543
1730
|
|
|
1731
|
+
const details: TaskToolDetails = {
|
|
1732
|
+
projectAgentsDir,
|
|
1733
|
+
results: receipts,
|
|
1734
|
+
totalDurationMs: totalDuration,
|
|
1735
|
+
usage: hasAggregatedUsage ? aggregatedUsage : undefined,
|
|
1736
|
+
forkContextClonedTokens: forkContextClonedTokens > 0 ? forkContextClonedTokens : undefined,
|
|
1737
|
+
roiSummary,
|
|
1738
|
+
};
|
|
1739
|
+
assertNoRawTaskFields(details, "task.return.details");
|
|
1544
1740
|
return {
|
|
1545
1741
|
content: [{ type: "text", text: summary }],
|
|
1546
|
-
details
|
|
1547
|
-
projectAgentsDir,
|
|
1548
|
-
results: results,
|
|
1549
|
-
totalDurationMs: totalDuration,
|
|
1550
|
-
usage: hasAggregatedUsage ? aggregatedUsage : undefined,
|
|
1551
|
-
outputPaths,
|
|
1552
|
-
},
|
|
1742
|
+
details,
|
|
1553
1743
|
};
|
|
1554
1744
|
} catch (err) {
|
|
1555
1745
|
return {
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* This enables reliable agent:// URL resolution and prevents artifact collisions.
|
|
9
9
|
*/
|
|
10
10
|
import * as fs from "node:fs/promises";
|
|
11
|
+
import { validateAllocatedTaskId, validateTaskId } from "./id";
|
|
11
12
|
|
|
12
13
|
function escapeRegExp(value: string): string {
|
|
13
14
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -73,8 +74,8 @@ export class AgentOutputManager {
|
|
|
73
74
|
*/
|
|
74
75
|
async allocate(id: string): Promise<string> {
|
|
75
76
|
await this.#ensureInitialized();
|
|
76
|
-
const prefix = this.#parentPrefix ? `${this.#parentPrefix}.` : "";
|
|
77
|
-
return `${prefix}${this.#nextId++}-${id}`;
|
|
77
|
+
const prefix = this.#parentPrefix ? `${validateAllocatedTaskId(this.#parentPrefix)}.` : "";
|
|
78
|
+
return `${prefix}${this.#nextId++}-${validateTaskId(id)}`;
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
/**
|
|
@@ -85,8 +86,8 @@ export class AgentOutputManager {
|
|
|
85
86
|
*/
|
|
86
87
|
async allocateBatch(ids: string[]): Promise<string[]> {
|
|
87
88
|
await this.#ensureInitialized();
|
|
88
|
-
const prefix = this.#parentPrefix ? `${this.#parentPrefix}.` : "";
|
|
89
|
-
return ids.map(id => `${prefix}${this.#nextId++}-${id}`);
|
|
89
|
+
const prefix = this.#parentPrefix ? `${validateAllocatedTaskId(this.#parentPrefix)}.` : "";
|
|
90
|
+
return ids.map(id => `${prefix}${this.#nextId++}-${validateTaskId(id)}`);
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
/**
|