@gajae-code/coding-agent 0.11.6 → 0.11.8
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 +92 -0
- package/dist/types/capability/index.d.ts +10 -20
- package/dist/types/capability/types.d.ts +3 -0
- package/dist/types/cli/args.d.ts +0 -2
- package/dist/types/commands/daemon.d.ts +2 -2
- package/dist/types/commands/sdk.d.ts +20 -2
- package/dist/types/config/keybindings.d.ts +34 -4
- package/dist/types/config/model-profile-activation.d.ts +4 -3
- package/dist/types/config/model-profile-contract.d.ts +38 -0
- package/dist/types/config/settings-schema.d.ts +70 -7
- package/dist/types/edit/modes/patch.d.ts +13 -0
- package/dist/types/edit/path-mutation-lock.d.ts +15 -0
- package/dist/types/eval/py/executor.d.ts +1 -1
- package/dist/types/eval/py/runner-artifact.d.ts +8 -0
- package/dist/types/eval/py/tool-bridge.d.ts +1 -2
- package/dist/types/gjc-runtime/repository-binding.d.ts +63 -0
- package/dist/types/gjc-runtime/ultragoal-guard.d.ts +6 -5
- package/dist/types/gjc-runtime/ultragoal-receipt-freshness.d.ts +20 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +43 -5
- package/dist/types/main.d.ts +32 -1
- package/dist/types/modes/components/btw-panel.d.ts +1 -0
- package/dist/types/modes/components/model-selector.d.ts +2 -0
- package/dist/types/modes/components/runtime-mcp-add-wizard.d.ts +2 -1
- package/dist/types/modes/components/tool-status-header.d.ts +4 -2
- package/dist/types/modes/components/welcome.d.ts +2 -0
- package/dist/types/modes/controllers/btw-controller.d.ts +5 -0
- package/dist/types/modes/controllers/command-controller.d.ts +2 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +2 -1
- package/dist/types/modes/interactive-mode.d.ts +7 -2
- package/dist/types/modes/prompt-action-autocomplete.d.ts +6 -1
- package/dist/types/modes/prompt-suggestion-controller.d.ts +35 -0
- package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +2 -2
- package/dist/types/modes/types.d.ts +4 -0
- package/dist/types/modes/utils/hotkeys-markdown.d.ts +2 -1
- package/dist/types/runtime-mcp/content-limits.d.ts +7 -0
- package/dist/types/runtime-mcp/manager.d.ts +1 -1
- package/dist/types/runtime-mcp/oauth-flow.d.ts +0 -5
- package/dist/types/runtime-mcp/plugin-network-boundary.d.ts +14 -0
- package/dist/types/sdk/broker/broker.d.ts +2 -0
- package/dist/types/sdk/broker/lifecycle.d.ts +6 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +6 -1
- package/dist/types/sdk/bus/config-commands.d.ts +2 -2
- package/dist/types/sdk/bus/config.d.ts +2 -0
- package/dist/types/sdk/bus/conversation-store.d.ts +1 -0
- package/dist/types/sdk/bus/index.d.ts +26 -1
- package/dist/types/sdk/bus/lifecycle-commands.d.ts +5 -4
- package/dist/types/sdk/bus/notification-orchestration.d.ts +1 -0
- package/dist/types/sdk/bus/notification-service.d.ts +34 -0
- package/dist/types/sdk/bus/prompt-reconciliation.d.ts +105 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +18 -3
- package/dist/types/sdk/bus/telegram-daemon-control.d.ts +5 -1
- package/dist/types/sdk/bus/telegram-daemon.d.ts +189 -4
- package/dist/types/sdk/bus/telegram-reference.d.ts +2 -0
- package/dist/types/sdk/bus/topic-registry.d.ts +88 -2
- package/dist/types/sdk/client/discovery.d.ts +2 -0
- package/dist/types/sdk/client/liveness.d.ts +7 -0
- package/dist/types/sdk/host/control/operations.d.ts +1 -1
- package/dist/types/sdk/host/host.d.ts +1 -1
- package/dist/types/sdk/host/query/handlers.d.ts +9 -0
- package/dist/types/sdk/index.d.ts +2 -0
- package/dist/types/sdk/prompt-status.d.ts +88 -0
- package/dist/types/sdk/session-directory.d.ts +1 -1
- package/dist/types/sdk/startup-capability.d.ts +3 -0
- package/dist/types/sdk/transport/auth-preface.d.ts +9 -0
- package/dist/types/sdk/transport/index.d.ts +12 -0
- package/dist/types/sdk/transport/relay.d.ts +43 -0
- package/dist/types/sdk/transport/serve-cli.d.ts +4 -0
- package/dist/types/sdk/transport/socket.d.ts +7 -0
- package/dist/types/sdk/transport/stdio.d.ts +3 -0
- package/dist/types/session/agent-session.d.ts +30 -5
- package/dist/types/session/btw-contract.d.ts +16 -0
- package/dist/types/session/internal/managed-session-scope.d.ts +32 -9
- package/dist/types/session/internal/managed-session-storage.d.ts +27 -10
- package/dist/types/session/internal/native-publish-outcome.d.ts +48 -0
- package/dist/types/session/session-manager.d.ts +25 -4
- package/dist/types/session/session-storage.d.ts +18 -0
- package/dist/types/setup/credential-import.d.ts +5 -1
- package/dist/types/setup/provider-onboarding.d.ts +2 -0
- package/dist/types/ssh/utils.d.ts +1 -0
- package/dist/types/task/discovery.d.ts +3 -1
- package/dist/types/task/index.d.ts +3 -1
- package/dist/types/task/receipt.d.ts +2 -0
- package/dist/types/task/types.d.ts +94 -0
- package/dist/types/tools/ask.d.ts +454 -174
- package/dist/types/tools/fetch.d.ts +5 -8
- package/dist/types/tools/image-gen.d.ts +63 -1
- package/dist/types/tools/index.d.ts +4 -0
- package/dist/types/tools/skill-discovery.d.ts +7 -0
- package/dist/types/tools/sqlite-reader.d.ts +7 -0
- package/dist/types/utils/prompt-suggestion.d.ts +33 -0
- package/dist/types/utils/shell-snapshot.d.ts +12 -0
- package/dist/types/web/insane/bridge.d.ts +1 -0
- package/dist/types/web/insane/url-guard.d.ts +17 -0
- package/package.json +8 -8
- package/scripts/capture-platform-shortcut-labels-showcase.ts +342 -0
- package/scripts/dogfood-repository-binding.ts +209 -0
- package/scripts/generate-sdk-operation-inventory.ts +4 -0
- package/scripts/run-test-manifest.ts +4 -4
- package/src/capability/index.ts +50 -42
- package/src/capability/types.ts +3 -0
- package/src/cli/args.ts +2 -92
- package/src/cli/notify-cli.ts +5 -38
- package/src/cli/setup-cli.ts +10 -4
- package/src/cli.ts +52 -9
- package/src/commands/daemon.ts +22 -5
- package/src/commands/sdk.ts +44 -11
- package/src/config/keybindings.ts +158 -25
- package/src/config/model-profile-activation.ts +7 -18
- package/src/config/model-profile-contract.ts +161 -0
- package/src/config/model-profiles.ts +18 -0
- package/src/config/model-registry.ts +11 -1
- package/src/config/settings-schema.ts +73 -7
- package/src/coordinator-mcp/model-preset.ts +21 -74
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +2 -2
- package/src/defaults/gjc/skills/ralplan/SKILL.md +3 -1
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +42 -1
- package/src/discovery/ssh.ts +12 -1
- package/src/edit/index.ts +3 -6
- package/src/edit/modes/patch.ts +38 -1
- package/src/edit/modes/replace.ts +42 -0
- package/src/edit/path-mutation-lock.ts +112 -0
- package/src/eval/py/executor.ts +30 -11
- package/src/eval/py/kernel.ts +1 -21
- package/src/eval/py/prelude.py +2 -2
- package/src/eval/py/runner-artifact.ts +84 -0
- package/src/eval/py/tool-bridge.ts +34 -18
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +2 -1
- package/src/extensibility/plugins/marketplace/fetcher.ts +191 -7
- package/src/gjc-runtime/launch-tmux.ts +1 -1
- package/src/gjc-runtime/managed-owner-supervisor.ts +83 -4
- package/src/gjc-runtime/ralplan-runtime.ts +75 -3
- package/src/gjc-runtime/repository-binding.ts +267 -0
- package/src/gjc-runtime/session-state-sidecar.ts +25 -9
- package/src/gjc-runtime/tmux-owner-isolation.ts +2 -1
- package/src/gjc-runtime/tmux-sessions.ts +45 -6
- package/src/gjc-runtime/ultragoal-guard.ts +93 -15
- package/src/gjc-runtime/ultragoal-receipt-freshness.ts +103 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +456 -31
- package/src/gjc-runtime/workflow-manifest.generated.json +58 -0
- package/src/gjc-runtime/workflow-manifest.ts +23 -0
- package/src/internal-urls/docs-index.generated.ts +12 -10
- package/src/internal-urls/local-protocol.ts +64 -21
- package/src/internal-urls/mcp-protocol.ts +73 -11
- package/src/main.ts +111 -37
- package/src/modes/DESIGN.md +5 -0
- package/src/modes/acp/acp-agent.ts +50 -16
- package/src/modes/action-registry.ts +1 -1
- package/src/modes/components/btw-panel.ts +82 -16
- package/src/modes/components/model-selector.ts +73 -11
- package/src/modes/components/plan-preview-overlay.ts +1 -1
- package/src/modes/components/runtime-mcp-add-wizard.ts +5 -0
- package/src/modes/components/tool-status-header.ts +25 -4
- package/src/modes/components/welcome.ts +22 -18
- package/src/modes/controllers/btw-controller.ts +119 -36
- package/src/modes/controllers/command-controller.ts +97 -54
- package/src/modes/controllers/event-controller.ts +10 -0
- package/src/modes/controllers/input-controller.ts +38 -2
- package/src/modes/controllers/runtime-mcp-command-controller.ts +29 -6
- package/src/modes/controllers/selector-controller.ts +149 -63
- package/src/modes/interactive-mode.ts +57 -34
- package/src/modes/prompt-action-autocomplete.ts +32 -13
- package/src/modes/prompt-suggestion-controller.ts +96 -0
- package/src/modes/shared/agent-wire/workflow-gate-broker.ts +2 -2
- package/src/modes/types.ts +4 -0
- package/src/modes/utils/hotkeys-markdown.ts +64 -36
- package/src/modes/utils/ui-helpers.ts +5 -3
- package/src/prompts/agents/architect.md +0 -1
- package/src/prompts/agents/critic.md +0 -1
- package/src/prompts/system/btw-user.md +3 -8
- package/src/prompts/system/prompt-suggestion-system.md +32 -0
- package/src/prompts/system/system-prompt.md +6 -4
- package/src/prompts/tools/cron.md +3 -1
- package/src/prompts/tools/skill-discovery.md +1 -0
- package/src/runtime-mcp/client.ts +41 -55
- package/src/runtime-mcp/content-limits.ts +71 -0
- package/src/runtime-mcp/json-rpc.ts +23 -9
- package/src/runtime-mcp/manager.ts +51 -53
- package/src/runtime-mcp/oauth-flow.ts +0 -72
- package/src/runtime-mcp/plugin-network-boundary.ts +101 -0
- package/src/runtime-mcp/transports/http.ts +63 -22
- package/src/sdk/broker/broker.ts +34 -20
- package/src/sdk/broker/lifecycle.ts +185 -36
- package/src/sdk/bus/chat-daemon-control.ts +19 -5
- package/src/sdk/bus/config-commands.ts +2 -2
- package/src/sdk/bus/config.ts +9 -1
- package/src/sdk/bus/conversation-store.ts +40 -6
- package/src/sdk/bus/index.ts +244 -70
- package/src/sdk/bus/lifecycle-commands.ts +63 -10
- package/src/sdk/bus/lifecycle-control-runtime.ts +11 -2
- package/src/sdk/bus/lifecycle-orchestrator.ts +32 -1
- package/src/sdk/bus/notification-orchestration.ts +12 -0
- package/src/sdk/bus/notification-service.ts +68 -20
- package/src/sdk/bus/prompt-reconciliation.ts +239 -0
- package/src/sdk/bus/recent-activity.ts +90 -26
- package/src/sdk/bus/telegram-daemon-contract.ts +18 -3
- package/src/sdk/bus/telegram-daemon-control.ts +147 -35
- package/src/sdk/bus/telegram-daemon.ts +2463 -450
- package/src/sdk/bus/telegram-reference.ts +20 -2
- package/src/sdk/bus/topic-registry.ts +451 -12
- package/src/sdk/cli/session-cli.ts +15 -2
- package/src/sdk/client/discovery.ts +19 -3
- package/src/sdk/client/liveness.ts +49 -0
- package/src/sdk/host/control/dispatch.ts +1 -1
- package/src/sdk/host/control/operations.ts +1 -1
- package/src/sdk/host/host.ts +2 -6
- package/src/sdk/host/query/handlers.ts +70 -5
- package/src/sdk/index.ts +12 -0
- package/src/sdk/prompt-status.ts +97 -0
- package/src/sdk/protocol/operation-inventory.generated.json +58 -0
- package/src/sdk/protocol/operation-registry.ts +18 -4
- package/src/sdk/session-directory.ts +5 -1
- package/src/sdk/session.ts +31 -5
- package/src/sdk/startup-capability.ts +9 -1
- package/src/sdk/transport/auth-preface.ts +82 -0
- package/src/sdk/transport/index.ts +18 -0
- package/src/sdk/transport/relay.ts +252 -0
- package/src/sdk/transport/serve-cli.ts +105 -0
- package/src/sdk/transport/socket.ts +197 -0
- package/src/sdk/transport/stdio.ts +17 -0
- package/src/session/agent-session.ts +292 -154
- package/src/session/blob-store.ts +25 -7
- package/src/session/btw-contract.ts +59 -0
- package/src/session/internal/managed-session-scope.ts +1163 -137
- package/src/session/internal/managed-session-storage.ts +397 -234
- package/src/session/internal/native-publish-outcome.ts +266 -0
- package/src/session/session-manager.ts +620 -403
- package/src/session/session-storage.ts +128 -11
- package/src/setup/credential-import.ts +28 -3
- package/src/setup/provider-onboarding.ts +30 -1
- package/src/setup/provider-presets.json +2 -1
- package/src/slash-commands/builtin-registry.ts +1 -1
- package/src/ssh/utils.ts +14 -0
- package/src/task/discovery.ts +8 -2
- package/src/task/gjc-command.ts +2 -2
- package/src/task/index.ts +121 -15
- package/src/task/receipt.ts +3 -0
- package/src/task/types.ts +34 -3
- package/src/tools/ask.ts +199 -89
- package/src/tools/ast-edit.ts +2 -2
- package/src/tools/bash-pty-selection.ts +2 -2
- package/src/tools/browser/screenshot-format.ts +6 -1
- package/src/tools/cron.ts +1 -1
- package/src/tools/fetch.ts +13 -131
- package/src/tools/image-gen.ts +476 -23
- package/src/tools/index.ts +4 -0
- package/src/tools/read.ts +2 -0
- package/src/tools/render-utils.ts +7 -1
- package/src/tools/skill-discovery.ts +39 -3
- package/src/tools/sqlite-reader.ts +63 -5
- package/src/utils/edit-mode.ts +2 -2
- package/src/utils/pasted-image-path.ts +15 -6
- package/src/utils/prompt-suggestion.ts +265 -0
- package/src/utils/shell-snapshot.ts +173 -63
- package/src/utils/sixel.ts +3 -3
- package/src/web/insane/bridge.ts +5 -1
- package/src/web/insane/url-guard.ts +140 -27
- package/src/web/scrapers/docs-rs.ts +30 -5
- package/src/web/scrapers/types.ts +19 -49
- package/src/web/scrapers/utils.ts +12 -26
package/src/task/index.ts
CHANGED
|
@@ -17,7 +17,7 @@ import * as os from "node:os";
|
|
|
17
17
|
import path from "node:path";
|
|
18
18
|
import type { AgentTool, AgentToolResult, AgentToolUpdateCallback } from "@gajae-code/agent-core";
|
|
19
19
|
import type { Model, Usage } from "@gajae-code/ai";
|
|
20
|
-
import { $
|
|
20
|
+
import { $pickenv, prompt, Snowflake } from "@gajae-code/utils";
|
|
21
21
|
import type { ToolSession } from "..";
|
|
22
22
|
import { AsyncJobManager, OwnerSubagentShutdownError, type ResumeRunner } from "../async";
|
|
23
23
|
import { resolveAgentModelPatterns } from "../config/model-resolver";
|
|
@@ -43,6 +43,15 @@ import {
|
|
|
43
43
|
|
|
44
44
|
// Import review tools for side effects (registers subagent tool handlers)
|
|
45
45
|
import "../tools/review";
|
|
46
|
+
import {
|
|
47
|
+
assertExecutionRootMatchesRepositoryBinding,
|
|
48
|
+
assertPathUnderRepositoryBinding,
|
|
49
|
+
captureRepositoryBinding,
|
|
50
|
+
publicRepositoryBinding,
|
|
51
|
+
type RepositoryBinding,
|
|
52
|
+
RepositoryBindingError,
|
|
53
|
+
resolveTaskRepositoryBinding,
|
|
54
|
+
} from "../gjc-runtime/repository-binding";
|
|
46
55
|
import { initializeLocalRoot, type LocalProtocolOptions, resolveLocalUrlToPath } from "../internal-urls";
|
|
47
56
|
import { generateCommitMessage } from "../utils/commit-message-generator";
|
|
48
57
|
import * as git from "../utils/git";
|
|
@@ -128,6 +137,43 @@ function addUsageTotals(target: Usage, usage: Partial<Usage>): void {
|
|
|
128
137
|
target.cost.total += cost.total;
|
|
129
138
|
}
|
|
130
139
|
|
|
140
|
+
/**
|
|
141
|
+
* Stamp/resolve repository authority for every task before agent discovery or spawn.
|
|
142
|
+
* Omitted bindings inherit the session worktree; declared ones must match it.
|
|
143
|
+
*/
|
|
144
|
+
async function resolveTaskItemsWithRepositoryBindings(
|
|
145
|
+
cwd: string,
|
|
146
|
+
tasks: readonly TaskItem[],
|
|
147
|
+
): Promise<{ tasks: TaskItem[]; error?: string }> {
|
|
148
|
+
const resolved: TaskItem[] = [];
|
|
149
|
+
for (const task of tasks) {
|
|
150
|
+
try {
|
|
151
|
+
const binding = await resolveTaskRepositoryBinding(cwd, task.repositoryBinding);
|
|
152
|
+
if (binding.relativeSubdir) {
|
|
153
|
+
assertPathUnderRepositoryBinding(binding, ".");
|
|
154
|
+
}
|
|
155
|
+
resolved.push({
|
|
156
|
+
...task,
|
|
157
|
+
repositoryBinding: binding,
|
|
158
|
+
});
|
|
159
|
+
} catch (error) {
|
|
160
|
+
const id = task.id?.trim() ? task.id : "(missing-id)";
|
|
161
|
+
if (error instanceof RepositoryBindingError) {
|
|
162
|
+
return { tasks: [], error: `Task "${id}" repository binding rejected: ${error.message}` };
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
tasks: [],
|
|
166
|
+
error: `Task "${id}" repository binding rejected: ${error instanceof Error ? error.message : String(error)}`,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return { tasks: resolved };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function repositoryBindingFromTask(task: TaskItem): RepositoryBinding | undefined {
|
|
174
|
+
return task.repositoryBinding ? publicRepositoryBinding(task.repositoryBinding as RepositoryBinding) : undefined;
|
|
175
|
+
}
|
|
176
|
+
|
|
131
177
|
function validateTaskIdsForScheduling(tasks: readonly TaskItem[]): string | undefined {
|
|
132
178
|
const invalid: string[] = [];
|
|
133
179
|
for (let i = 0; i < tasks.length; i++) {
|
|
@@ -399,12 +445,16 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
399
445
|
this.session.getSessionSpawns() ?? "*",
|
|
400
446
|
);
|
|
401
447
|
}
|
|
448
|
+
readonly #sessionRepositoryBinding: RepositoryBinding;
|
|
449
|
+
|
|
402
450
|
private constructor(
|
|
403
451
|
private readonly session: ToolSession,
|
|
404
452
|
discoveredAgents: AgentDefinition[],
|
|
453
|
+
sessionRepositoryBinding: RepositoryBinding,
|
|
405
454
|
) {
|
|
406
|
-
this.#blockedAgent = $
|
|
455
|
+
this.#blockedAgent = $pickenv("GJC_BLOCKED_AGENT", "PI_BLOCKED_AGENT");
|
|
407
456
|
this.#discoveredAgents = discoveredAgents;
|
|
457
|
+
this.#sessionRepositoryBinding = sessionRepositoryBinding;
|
|
408
458
|
}
|
|
409
459
|
|
|
410
460
|
#getTaskSimpleMode(): TaskSimpleMode {
|
|
@@ -412,11 +462,16 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
412
462
|
}
|
|
413
463
|
|
|
414
464
|
/**
|
|
415
|
-
* Create a TaskTool instance
|
|
465
|
+
* Create a TaskTool instance.
|
|
466
|
+
* Repository authority is captured from session cwd *before* agent discovery so
|
|
467
|
+
* multi-repo workspaces fail closed prior to context/discovery (#2901).
|
|
416
468
|
*/
|
|
417
469
|
static async create(session: ToolSession): Promise<TaskTool> {
|
|
470
|
+
const sessionRepositoryBinding = await captureRepositoryBinding(session.cwd, { displayPath: session.cwd });
|
|
471
|
+
// Authority check before discovery: session cwd must resolve to a stable binding.
|
|
472
|
+
await assertExecutionRootMatchesRepositoryBinding(session.cwd, sessionRepositoryBinding);
|
|
418
473
|
const { agents } = await discoverAgents(session.cwd);
|
|
419
|
-
return new TaskTool(session, agents);
|
|
474
|
+
return new TaskTool(session, agents, publicRepositoryBinding(sessionRepositoryBinding));
|
|
420
475
|
}
|
|
421
476
|
|
|
422
477
|
async execute(
|
|
@@ -432,13 +487,32 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
432
487
|
return createTaskModeError(validationError);
|
|
433
488
|
}
|
|
434
489
|
|
|
435
|
-
|
|
436
|
-
|
|
490
|
+
// Re-verify session authority before using any discovered agents or scheduling work.
|
|
491
|
+
try {
|
|
492
|
+
await assertExecutionRootMatchesRepositoryBinding(this.session.cwd, this.#sessionRepositoryBinding);
|
|
493
|
+
} catch (error) {
|
|
494
|
+
const message =
|
|
495
|
+
error instanceof RepositoryBindingError
|
|
496
|
+
? error.message
|
|
497
|
+
: error instanceof Error
|
|
498
|
+
? error.message
|
|
499
|
+
: String(error);
|
|
500
|
+
return createTaskModeError(`Session repository binding rejected before task discovery: ${message}`);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
const rawTaskItems = params.tasks ?? [];
|
|
504
|
+
const taskIdValidationError = validateTaskIdsForScheduling(rawTaskItems);
|
|
437
505
|
if (taskIdValidationError) {
|
|
438
506
|
return createTaskModeError(taskIdValidationError);
|
|
439
507
|
}
|
|
508
|
+
const bindingResolution = await resolveTaskItemsWithRepositoryBindings(this.session.cwd, rawTaskItems);
|
|
509
|
+
if (bindingResolution.error) {
|
|
510
|
+
return createTaskModeError(bindingResolution.error);
|
|
511
|
+
}
|
|
512
|
+
const taskItems = bindingResolution.tasks;
|
|
513
|
+
const paramsWithBindings: TaskParams = { ...params, tasks: taskItems };
|
|
440
514
|
if (taskItems.length === 0) {
|
|
441
|
-
return this.#executeSync(_toolCallId,
|
|
515
|
+
return this.#executeSync(_toolCallId, paramsWithBindings, signal, onUpdate);
|
|
442
516
|
}
|
|
443
517
|
const agent = getAgent(this.#discoveredAgents, params.agent);
|
|
444
518
|
if (!agent) {
|
|
@@ -926,13 +1000,31 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
926
1000
|
},
|
|
927
1001
|
): Promise<AgentToolResult<TaskToolDetails>> {
|
|
928
1002
|
const startTime = Date.now();
|
|
1003
|
+
// Pre-discovery authority: session cwd must still match the capture from create().
|
|
1004
|
+
try {
|
|
1005
|
+
await assertExecutionRootMatchesRepositoryBinding(this.session.cwd, this.#sessionRepositoryBinding);
|
|
1006
|
+
} catch (error) {
|
|
1007
|
+
const message =
|
|
1008
|
+
error instanceof RepositoryBindingError
|
|
1009
|
+
? error.message
|
|
1010
|
+
: error instanceof Error
|
|
1011
|
+
? error.message
|
|
1012
|
+
: String(error);
|
|
1013
|
+
return createTaskModeError(`Session repository binding rejected before task discovery: ${message}`);
|
|
1014
|
+
}
|
|
1015
|
+
const bindingResolution = await resolveTaskItemsWithRepositoryBindings(this.session.cwd, params.tasks ?? []);
|
|
1016
|
+
if (bindingResolution.error) {
|
|
1017
|
+
return createTaskModeError(bindingResolution.error);
|
|
1018
|
+
}
|
|
1019
|
+
const boundParams: TaskParams = { ...params, tasks: bindingResolution.tasks };
|
|
1020
|
+
|
|
929
1021
|
const { agents, projectAgentsDir } = await discoverAgents(this.session.cwd);
|
|
930
|
-
const { agent: agentName, context, schema: outputSchema } =
|
|
1022
|
+
const { agent: agentName, context, schema: outputSchema } = boundParams;
|
|
931
1023
|
const simpleMode = this.#getTaskSimpleMode();
|
|
932
1024
|
const { contextEnabled, customSchemaEnabled } = getTaskSimpleModeCapabilities(simpleMode);
|
|
933
1025
|
const sharedContext = contextEnabled ? context?.trim() : undefined;
|
|
934
1026
|
const isolationMode = this.session.settings.get("task.isolation.mode");
|
|
935
|
-
const isolationRequested = "isolated" in
|
|
1027
|
+
const isolationRequested = "isolated" in boundParams ? boundParams.isolated === true : false;
|
|
936
1028
|
const isIsolated = isolationMode !== "none" && isolationRequested;
|
|
937
1029
|
const mergeMode = this.session.settings.get("task.isolation.merge");
|
|
938
1030
|
const commitStyle = this.session.settings.get("task.isolation.commits");
|
|
@@ -940,7 +1032,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
940
1032
|
const taskDepth = this.session.taskDepth ?? 0;
|
|
941
1033
|
const subagentLspEnabled = (this.session.enableLsp ?? true) && this.session.settings.get("task.enableLsp");
|
|
942
1034
|
|
|
943
|
-
if (isolationMode === "none" && "isolated" in
|
|
1035
|
+
if (isolationMode === "none" && "isolated" in boundParams) {
|
|
944
1036
|
return {
|
|
945
1037
|
content: [
|
|
946
1038
|
{
|
|
@@ -1000,7 +1092,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1000
1092
|
}
|
|
1001
1093
|
|
|
1002
1094
|
const forkContextValidationError = validateForkContextRequests(
|
|
1003
|
-
|
|
1095
|
+
boundParams.tasks ?? [],
|
|
1004
1096
|
agent,
|
|
1005
1097
|
this.session.settings.get("task.forkContext.enabled"),
|
|
1006
1098
|
);
|
|
@@ -1039,7 +1131,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1039
1131
|
: (effectiveAgent.output ?? this.session.outputSchema);
|
|
1040
1132
|
|
|
1041
1133
|
// Handle empty or missing tasks
|
|
1042
|
-
if (!
|
|
1134
|
+
if (!boundParams.tasks || boundParams.tasks.length === 0) {
|
|
1043
1135
|
return {
|
|
1044
1136
|
content: [
|
|
1045
1137
|
{
|
|
@@ -1057,7 +1149,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1057
1149
|
};
|
|
1058
1150
|
}
|
|
1059
1151
|
|
|
1060
|
-
const tasks =
|
|
1152
|
+
const tasks = boundParams.tasks;
|
|
1061
1153
|
const missingTaskIndexes: number[] = [];
|
|
1062
1154
|
const idIndexes = new Map<string, number[]>();
|
|
1063
1155
|
|
|
@@ -1173,7 +1265,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1173
1265
|
const emitProgress = () => {
|
|
1174
1266
|
const progress = Array.from(progressMap.values()).sort((a, b) => a.index - b.index);
|
|
1175
1267
|
onUpdate?.({
|
|
1176
|
-
content: [{ type: "text", text: `Running ${
|
|
1268
|
+
content: [{ type: "text", text: `Running ${tasks.length} agents...` }],
|
|
1177
1269
|
details: {
|
|
1178
1270
|
projectAgentsDir,
|
|
1179
1271
|
results: [],
|
|
@@ -1342,7 +1434,13 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1342
1434
|
const taskSessionFile = managedPersistence
|
|
1343
1435
|
? null
|
|
1344
1436
|
: (overrides?.sessionFile ?? executionOverrides?.sessionFiles?.get(task.id) ?? null);
|
|
1437
|
+
const taskRepositoryBinding = repositoryBindingFromTask(task) ?? this.#sessionRepositoryBinding;
|
|
1438
|
+
// Declared paths (relativeSubdir) must stay under the bound root before spawn.
|
|
1439
|
+
if (taskRepositoryBinding.relativeSubdir) {
|
|
1440
|
+
assertPathUnderRepositoryBinding(taskRepositoryBinding, ".");
|
|
1441
|
+
}
|
|
1345
1442
|
if (!isIsolated) {
|
|
1443
|
+
await assertExecutionRootMatchesRepositoryBinding(this.session.cwd, taskRepositoryBinding);
|
|
1346
1444
|
const result = await runSubprocess({
|
|
1347
1445
|
cwd: this.session.cwd,
|
|
1348
1446
|
agent: effectiveAgent,
|
|
@@ -1393,7 +1491,12 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1393
1491
|
parentTelemetry: this.session.getTelemetry?.(),
|
|
1394
1492
|
forkContextSeed,
|
|
1395
1493
|
});
|
|
1396
|
-
return {
|
|
1494
|
+
return {
|
|
1495
|
+
...result,
|
|
1496
|
+
...(forkContext ? { forkContext } : {}),
|
|
1497
|
+
forkContextAdvisory,
|
|
1498
|
+
repositoryBinding: publicRepositoryBinding(taskRepositoryBinding),
|
|
1499
|
+
};
|
|
1397
1500
|
}
|
|
1398
1501
|
|
|
1399
1502
|
const taskStart = Date.now();
|
|
@@ -1406,6 +1509,8 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1406
1509
|
|
|
1407
1510
|
isolationHandle = await ensureIsolation(repoRoot, task.id, preferredIsolationBackend);
|
|
1408
1511
|
const isolationDir = isolationHandle.mergedDir;
|
|
1512
|
+
// Isolated worktrees must preserve the source repository identity (#2901).
|
|
1513
|
+
await assertExecutionRootMatchesRepositoryBinding(isolationDir, taskRepositoryBinding);
|
|
1409
1514
|
|
|
1410
1515
|
const result = await runSubprocess({
|
|
1411
1516
|
cwd: this.session.cwd,
|
|
@@ -1462,6 +1567,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
|
|
|
1462
1567
|
...result,
|
|
1463
1568
|
...(forkContext ? { forkContext } : {}),
|
|
1464
1569
|
forkContextAdvisory,
|
|
1570
|
+
repositoryBinding: publicRepositoryBinding(taskRepositoryBinding),
|
|
1465
1571
|
};
|
|
1466
1572
|
if (mergeMode === "branch" && resultWithForkContext.exitCode === 0) {
|
|
1467
1573
|
try {
|
package/src/task/receipt.ts
CHANGED
|
@@ -48,6 +48,8 @@ export interface TaskResultReceipt {
|
|
|
48
48
|
extractedToolCounts?: Record<string, number>;
|
|
49
49
|
forkContext?: SingleResult["forkContext"];
|
|
50
50
|
forkContextAdvisory?: SingleResult["forkContextAdvisory"];
|
|
51
|
+
/** Resolved repository identity for this delegated lane (#2901). */
|
|
52
|
+
repositoryBinding?: SingleResult["repositoryBinding"];
|
|
51
53
|
roi?: TaskRoi;
|
|
52
54
|
}
|
|
53
55
|
|
|
@@ -262,6 +264,7 @@ export function buildTaskReceipt(raw: SingleResult): TaskResultReceipt {
|
|
|
262
264
|
extractedToolCounts,
|
|
263
265
|
forkContext: raw.forkContext,
|
|
264
266
|
forkContextAdvisory: raw.forkContextAdvisory,
|
|
267
|
+
repositoryBinding: raw.repositoryBinding,
|
|
265
268
|
roi: buildTaskRoi(raw),
|
|
266
269
|
};
|
|
267
270
|
}
|
package/src/task/types.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ThinkingLevel } from "@gajae-code/agent-core";
|
|
2
2
|
import type { Usage } from "@gajae-code/ai";
|
|
3
|
-
import { $
|
|
3
|
+
import { $pickenv } from "@gajae-code/utils";
|
|
4
4
|
import * as z from "zod/v4";
|
|
5
5
|
import { isValidTaskId, TASK_ID_DESCRIPTION } from "./id";
|
|
6
6
|
import type { TaskResultReceipt } from "./receipt";
|
|
@@ -27,10 +27,10 @@ const parseNumber = (value: string | undefined, defaultValue: number): number =>
|
|
|
27
27
|
};
|
|
28
28
|
|
|
29
29
|
/** Maximum output bytes per agent */
|
|
30
|
-
export const MAX_OUTPUT_BYTES = parseNumber($
|
|
30
|
+
export const MAX_OUTPUT_BYTES = parseNumber($pickenv("GJC_TASK_MAX_OUTPUT_BYTES", "PI_TASK_MAX_OUTPUT_BYTES"), 500_000);
|
|
31
31
|
|
|
32
32
|
/** Maximum output lines per agent */
|
|
33
|
-
export const MAX_OUTPUT_LINES = parseNumber($
|
|
33
|
+
export const MAX_OUTPUT_LINES = parseNumber($pickenv("GJC_TASK_MAX_OUTPUT_LINES", "PI_TASK_MAX_OUTPUT_LINES"), 5000);
|
|
34
34
|
|
|
35
35
|
/** EventBus channel for raw subagent events */
|
|
36
36
|
export const TASK_SUBAGENT_EVENT_CHANNEL = "task:subagent:event";
|
|
@@ -74,6 +74,19 @@ const spawnPlanSchema = z
|
|
|
74
74
|
})
|
|
75
75
|
.describe("justification required before spawning more than four tasks");
|
|
76
76
|
|
|
77
|
+
const repositoryBindingSchema = z
|
|
78
|
+
.object({
|
|
79
|
+
schema: z.literal("gjc.repository_binding.v1"),
|
|
80
|
+
worktreeRoot: z.string().min(1).describe("canonical git worktree root"),
|
|
81
|
+
commonDir: z.string().min(1).nullable().describe("git common dir, or null outside a git checkout"),
|
|
82
|
+
relativeSubdir: z.string().min(1).optional().describe("optional repo-relative subdirectory; not an absolute cwd"),
|
|
83
|
+
displayPath: z.string().min(1).optional().describe("human-facing path; never used for authority"),
|
|
84
|
+
head: z.string().min(1).optional(),
|
|
85
|
+
branch: z.string().min(1).optional(),
|
|
86
|
+
})
|
|
87
|
+
.strict()
|
|
88
|
+
.describe("authoritative repository identity for multi-repo fail-closed spawn");
|
|
89
|
+
|
|
77
90
|
const createTaskItemSchema = (_contextEnabled: boolean) =>
|
|
78
91
|
z.object({
|
|
79
92
|
id: z.string().max(48).refine(isValidTaskId, TASK_ID_DESCRIPTION).describe("filesystem-safe task identifier"),
|
|
@@ -85,6 +98,11 @@ const createTaskItemSchema = (_contextEnabled: boolean) =>
|
|
|
85
98
|
.describe(
|
|
86
99
|
"fork-context mode: none/omitted copies no parent context; receipt copies a minimal receipt-sized snapshot; last-turn copies only the latest exchange; bounded copies the bounded default snapshot; full copies a larger sanitized snapshot up to the configured/model token cap",
|
|
87
100
|
),
|
|
101
|
+
repositoryBinding: repositoryBindingSchema
|
|
102
|
+
.optional()
|
|
103
|
+
.describe(
|
|
104
|
+
"authoritative repository identity; omitted items are stamped from session cwd before discovery/spawn and still fail closed on sibling drift",
|
|
105
|
+
),
|
|
88
106
|
});
|
|
89
107
|
|
|
90
108
|
/** Single task item for parallel execution (default shape with context enabled). */
|
|
@@ -353,6 +371,19 @@ export interface SingleResult {
|
|
|
353
371
|
* never changes the actual mode selection).
|
|
354
372
|
*/
|
|
355
373
|
forkContextAdvisory?: { recommendedMode: ForkContextMode; reasons: string[] };
|
|
374
|
+
/**
|
|
375
|
+
* Resolved repository identity used for this task after pre-discovery stamping
|
|
376
|
+
* and fail-closed validation (#2901).
|
|
377
|
+
*/
|
|
378
|
+
repositoryBinding?: {
|
|
379
|
+
schema: "gjc.repository_binding.v1";
|
|
380
|
+
worktreeRoot: string;
|
|
381
|
+
commonDir: string | null;
|
|
382
|
+
relativeSubdir?: string;
|
|
383
|
+
displayPath?: string;
|
|
384
|
+
head?: string;
|
|
385
|
+
branch?: string;
|
|
386
|
+
};
|
|
356
387
|
}
|
|
357
388
|
|
|
358
389
|
/** True only for complete, factual five-bucket cost accounting. */
|