@gajae-code/coding-agent 0.16.4 → 0.16.6
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 +54 -0
- package/dist/types/capability/types.d.ts +4 -0
- package/dist/types/cli/customize-doctor.d.ts +22 -0
- package/dist/types/config/file-lock.d.ts +31 -3
- package/dist/types/coordinator-mcp/question-state.d.ts +7 -0
- package/dist/types/coordinator-mcp/server.d.ts +7 -0
- package/dist/types/discovery/helpers.d.ts +33 -0
- package/dist/types/exec/bash-executor.d.ts +17 -1
- package/dist/types/exec/bash-shell-guardian.d.ts +15 -0
- package/dist/types/exec/bash-shell-runtime-entry.d.ts +2 -0
- package/dist/types/exec/bash-shell-signals.d.ts +2 -0
- package/dist/types/exec/bash-shell-supervisor-entry.d.ts +1 -0
- package/dist/types/exec/bash-shell-supervisor.d.ts +10 -0
- package/dist/types/exec/bash-shell-worker-entry.d.ts +2 -0
- package/dist/types/exec/bash-shell-worker-protocol.d.ts +63 -0
- package/dist/types/exec/bash-shell-worker.d.ts +1 -0
- package/dist/types/exec/isolated-shell.d.ts +19 -0
- package/dist/types/extensibility/extensions/function-hooks-internal.d.ts +9 -0
- package/dist/types/extensibility/extensions/function-hooks.d.ts +169 -0
- package/dist/types/extensibility/extensions/index.d.ts +1 -0
- package/dist/types/extensibility/extensions/runner.d.ts +46 -6
- package/dist/types/extensibility/extensions/types.d.ts +16 -0
- package/dist/types/extensibility/extensions/wrapper.d.ts +3 -1
- package/dist/types/extensibility/gjc-plugins/constrained-hooks.d.ts +35 -2
- package/dist/types/extensibility/gjc-plugins/types.d.ts +25 -0
- package/dist/types/extensibility/hooks/types.d.ts +4 -0
- package/dist/types/extensibility/runtime-skill-discovery.d.ts +4 -1
- package/dist/types/extensibility/skill-management.d.ts +9 -4
- package/dist/types/extensibility/skills.d.ts +2 -0
- package/dist/types/gjc-runtime/empty-delete-gc.d.ts +4 -1
- package/dist/types/gjc-runtime/linux-proc.d.ts +2 -0
- package/dist/types/gjc-runtime/session-state-lock.d.ts +12 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +41 -3
- package/dist/types/gjc-runtime/ultragoal-succession.d.ts +251 -0
- package/dist/types/modes/components/bash-execution.d.ts +1 -0
- package/dist/types/modes/components/execution-shared.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +2 -0
- package/dist/types/modes/types.d.ts +6 -0
- package/dist/types/sdk/broker/ensure.d.ts +32 -0
- package/dist/types/sdk/broker/lifecycle-ledger.d.ts +0 -1
- package/dist/types/sdk/broker/lifecycle.d.ts +6 -0
- package/dist/types/sdk/broker/startup-failure.d.ts +4 -1
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +2 -0
- package/dist/types/sdk/bus/chat-effect-journal.d.ts +17 -2
- package/dist/types/sdk/bus/conversation-store.d.ts +11 -0
- package/dist/types/sdk/bus/lifecycle-commands.d.ts +8 -8
- package/dist/types/sdk/bus/slack-daemon.d.ts +1 -1
- package/dist/types/sdk/bus/topic-registry.d.ts +8 -0
- package/dist/types/sdk/client/client.d.ts +6 -0
- package/dist/types/sdk/host/host.d.ts +3 -1
- package/dist/types/sdk/host/session-runtime.d.ts +4 -2
- package/dist/types/sdk/lifecycle/service.d.ts +1 -0
- package/dist/types/sdk/router/session-router.d.ts +10 -2
- package/dist/types/sdk/session.d.ts +5 -1
- package/dist/types/session/agent-session.d.ts +2 -0
- package/dist/types/session/fallback-chain-controller.d.ts +15 -0
- package/dist/types/session/internal/managed-session-storage.d.ts +7 -0
- package/dist/types/session/messages.d.ts +1 -0
- package/dist/types/session/session-manager.d.ts +3 -1
- package/dist/types/setup/paseo/announce.d.ts +4 -3
- package/dist/types/skill-state/canonical-skills.d.ts +4 -0
- package/dist/types/system-prompt.d.ts +8 -0
- package/dist/types/task/executor.d.ts +3 -0
- package/dist/types/tools/bash.d.ts +1 -0
- package/dist/types/tools/github-cache.d.ts +2 -1
- package/dist/types/tools/index.d.ts +2 -0
- package/package.json +9 -7
- package/scripts/generate-sdk-operation-inventory.ts +2 -0
- package/src/capability/index.ts +14 -2
- package/src/capability/types.ts +4 -0
- package/src/cli/customize-doctor.ts +155 -12
- package/src/cli.ts +22 -0
- package/src/commands/sdk.ts +74 -31
- package/src/config/file-lock-gc.ts +40 -2
- package/src/config/file-lock.ts +198 -14
- package/src/config/model-preset-registry.ts +115 -16
- package/src/config/model-registry.ts +16 -12
- package/src/coordinator-mcp/question-state.ts +33 -2
- package/src/coordinator-mcp/server.ts +477 -101
- package/src/crash/sanitize.ts +1 -1
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +22 -0
- package/src/discovery/builtin.ts +50 -62
- package/src/discovery/helpers.ts +297 -32
- package/src/exec/bash-executor.ts +330 -50
- package/src/exec/bash-shell-guardian.ts +388 -0
- package/src/exec/bash-shell-runtime-entry.ts +5 -0
- package/src/exec/bash-shell-signals.ts +29 -0
- package/src/exec/bash-shell-supervisor-entry.ts +3 -0
- package/src/exec/bash-shell-supervisor.ts +359 -0
- package/src/exec/bash-shell-worker-entry.ts +5 -0
- package/src/exec/bash-shell-worker-protocol.ts +36 -0
- package/src/exec/bash-shell-worker.ts +116 -0
- package/src/exec/isolated-shell.ts +393 -0
- package/src/extensibility/extensions/function-hooks-internal.ts +73 -0
- package/src/extensibility/extensions/function-hooks.ts +959 -0
- package/src/extensibility/extensions/index.ts +22 -0
- package/src/extensibility/extensions/loader.ts +53 -2
- package/src/extensibility/extensions/runner.ts +895 -264
- package/src/extensibility/extensions/types.ts +42 -0
- package/src/extensibility/extensions/wrapper.ts +56 -15
- package/src/extensibility/gjc-plugins/compiler.ts +20 -2
- package/src/extensibility/gjc-plugins/constrained-hooks.ts +321 -23
- package/src/extensibility/gjc-plugins/registry.ts +113 -1
- package/src/extensibility/gjc-plugins/runtime-quarantine.ts +20 -2
- package/src/extensibility/gjc-plugins/schema.ts +121 -4
- package/src/extensibility/gjc-plugins/types.ts +25 -0
- package/src/extensibility/hooks/loader.ts +133 -16
- package/src/extensibility/hooks/types.ts +28 -0
- package/src/extensibility/runtime-skill-discovery.ts +80 -47
- package/src/extensibility/skill-management.ts +200 -52
- package/src/extensibility/skills.ts +29 -9
- package/src/gjc-runtime/empty-delete-gc.ts +94 -4
- package/src/gjc-runtime/gc-runtime.ts +29 -0
- package/src/gjc-runtime/linux-proc.ts +14 -0
- package/src/gjc-runtime/session-state-lock.ts +51 -8
- package/src/gjc-runtime/session-state-sidecar.ts +27 -11
- package/src/gjc-runtime/state-writer.ts +30 -29
- package/src/gjc-runtime/ultragoal-runtime.ts +189 -47
- package/src/gjc-runtime/ultragoal-succession.ts +1667 -0
- package/src/gjc-runtime/workflow-manifest.generated.json +52 -1
- package/src/gjc-runtime/workflow-manifest.ts +16 -0
- package/src/harness-control-plane/session-lease.ts +2 -2
- package/src/internal-urls/docs-index.generated.ts +6 -6
- package/src/lsp/config.ts +10 -3
- package/src/lsp/index.ts +1 -1
- package/src/lsp/path-trust.ts +69 -14
- package/src/main.ts +6 -1
- package/src/modes/acp/acp-agent.ts +16 -3
- package/src/modes/components/bash-execution.ts +4 -1
- package/src/modes/components/execution-shared.ts +4 -1
- package/src/modes/components/session-observer-overlay.ts +1 -1
- package/src/modes/components/tool-status-header.ts +3 -1
- package/src/modes/controllers/command-controller.ts +1 -0
- package/src/modes/controllers/event-controller.ts +3 -2
- package/src/modes/controllers/extension-ui-controller.ts +1 -0
- package/src/modes/controllers/input-controller.ts +6 -3
- package/src/modes/interactive-mode.ts +6 -5
- package/src/modes/print-mode.ts +5 -1
- package/src/modes/prompt-action-autocomplete.ts +54 -27
- package/src/modes/runtime-init.ts +2 -0
- package/src/modes/types.ts +16 -3
- package/src/modes/utils/ui-helpers.ts +1 -0
- package/src/prompts/tools/subagent.md +1 -0
- package/src/runtime-mcp/manager.ts +20 -2
- package/src/runtime-mcp/pool.test.ts +20 -11
- package/src/sdk/broker/broker.ts +119 -28
- package/src/sdk/broker/ensure.ts +248 -41
- package/src/sdk/broker/lifecycle-ledger.ts +7 -17
- package/src/sdk/broker/lifecycle.ts +56 -6
- package/src/sdk/broker/startup-failure.ts +15 -6
- package/src/sdk/bus/chat-daemon-control.ts +3 -1
- package/src/sdk/bus/chat-daemon-runtime.ts +35 -5
- package/src/sdk/bus/chat-effect-journal.ts +132 -7
- package/src/sdk/bus/conversation-store.ts +29 -0
- package/src/sdk/bus/lifecycle-commands.ts +17 -11
- package/src/sdk/bus/slack-conversation.ts +1 -0
- package/src/sdk/bus/slack-daemon.ts +387 -48
- package/src/sdk/bus/telegram-daemon.ts +16 -2
- package/src/sdk/bus/topic-registry.ts +19 -0
- package/src/sdk/cli/master-cli.ts +1 -1
- package/src/sdk/cli/session-cli.ts +2 -2
- package/src/sdk/client/client.ts +66 -17
- package/src/sdk/host/host.ts +29 -9
- package/src/sdk/host/query/revision-store.ts +19 -13
- package/src/sdk/host/reverse-leases.ts +7 -4
- package/src/sdk/host/session-runtime.test.ts +50 -8
- package/src/sdk/host/session-runtime.ts +158 -51
- package/src/sdk/lifecycle/service.ts +4 -0
- package/src/sdk/protocol/operation-inventory.generated.json +11 -0
- package/src/sdk/router/session-router.ts +89 -38
- package/src/sdk/session.ts +155 -26
- package/src/sdk/transport/relay.ts +35 -13
- package/src/session/agent-session.ts +117 -52
- package/src/session/fallback-chain-controller.ts +38 -0
- package/src/session/internal/managed-session-storage.ts +19 -5
- package/src/session/messages.ts +5 -0
- package/src/session/session-manager.ts +29 -5
- package/src/session-import/redact.ts +5 -1
- package/src/setup/paseo/announce.ts +49 -43
- package/src/setup/paseo/setup-deps.ts +1 -1
- package/src/skill-state/canonical-skills.ts +12 -0
- package/src/skills/skills.test.ts +41 -21
- package/src/system-prompt.ts +25 -3
- package/src/task/executor.ts +5 -0
- package/src/task/index.ts +4 -0
- package/src/tools/bash.ts +28 -11
- package/src/tools/gh.ts +26 -3
- package/src/tools/github-cache.ts +68 -16
- package/src/tools/index.ts +2 -0
- package/src/tools/job.ts +13 -2
- package/src/tools/read.ts +14 -2
- package/src/tools/render-utils.ts +1 -3
- package/src/tools/resource-gc.ts +28 -8
- package/src/tools/skill-discovery.ts +5 -0
- package/src/tools/skill.ts +15 -0
- package/src/tools/subagent.ts +3 -2
- package/src/tools/tool-catalog.generated.ts +2 -2
- package/src/tools/ultragoal-ask-guard.ts +2 -2
package/src/sdk/session.ts
CHANGED
|
@@ -32,8 +32,10 @@ import {
|
|
|
32
32
|
$flag,
|
|
33
33
|
getAgentDbPath,
|
|
34
34
|
getAgentDir,
|
|
35
|
+
getAgentProfileAuthority,
|
|
35
36
|
getProjectDir,
|
|
36
37
|
logger,
|
|
38
|
+
normalizePathForComparison,
|
|
37
39
|
postmortem,
|
|
38
40
|
prompt,
|
|
39
41
|
Snowflake,
|
|
@@ -91,10 +93,14 @@ import { CustomToolAdapter } from "../extensibility/custom-tools/wrapper";
|
|
|
91
93
|
import {
|
|
92
94
|
createCustomToolSettings,
|
|
93
95
|
type ExtensionContext,
|
|
96
|
+
type ExtensionEvent,
|
|
94
97
|
type ExtensionFactory,
|
|
95
98
|
ExtensionRunner,
|
|
96
99
|
ExtensionToolWrapper,
|
|
97
100
|
type ExtensionUIContext,
|
|
101
|
+
type FunctionHook,
|
|
102
|
+
type FunctionHookEventType,
|
|
103
|
+
type FunctionHookResult,
|
|
98
104
|
type LoadExtensionsResult,
|
|
99
105
|
loadExtensionFromFactory,
|
|
100
106
|
type ToolDefinition,
|
|
@@ -168,6 +174,7 @@ import {
|
|
|
168
174
|
unregisterOwnedRegistration,
|
|
169
175
|
} from "../session/terminal-abort";
|
|
170
176
|
import { formatNoModelsAvailableFallback } from "../setup/model-onboarding-guidance";
|
|
177
|
+
import { getSkillFilesystemIdentity } from "../skill-state/canonical-skills";
|
|
171
178
|
import {
|
|
172
179
|
type BuildSystemPromptResult,
|
|
173
180
|
buildSystemPrompt as buildSystemPromptInternal,
|
|
@@ -438,6 +445,8 @@ export interface CreateAgentSessionOptions {
|
|
|
438
445
|
cwd?: string;
|
|
439
446
|
/** Global config directory. Default: ~/.gjc/agent */
|
|
440
447
|
agentDir?: string;
|
|
448
|
+
/** Resolver-owned classification for `agentDir`; required when authority must survive HOME/config refreshes. */
|
|
449
|
+
profileAuthority?: "default" | "custom";
|
|
441
450
|
/** Spawns to allow. Default: "*" */
|
|
442
451
|
spawns?: string;
|
|
443
452
|
|
|
@@ -781,10 +790,11 @@ export async function discoverSkills(
|
|
|
781
790
|
*/
|
|
782
791
|
export async function discoverContextFiles(
|
|
783
792
|
cwd?: string,
|
|
784
|
-
|
|
793
|
+
agentDir?: string,
|
|
785
794
|
): Promise<Array<{ path: string; content: string; depth?: number }>> {
|
|
786
795
|
return await loadContextFilesInternal({
|
|
787
796
|
cwd: cwd ?? getProjectDir(),
|
|
797
|
+
agentDir,
|
|
788
798
|
});
|
|
789
799
|
}
|
|
790
800
|
|
|
@@ -821,6 +831,8 @@ export interface BuildSystemPromptOptions {
|
|
|
821
831
|
skills?: Skill[];
|
|
822
832
|
contextFiles?: Array<{ path: string; content: string }>;
|
|
823
833
|
cwd?: string;
|
|
834
|
+
agentDir?: string;
|
|
835
|
+
profileAuthority?: "default" | "custom";
|
|
824
836
|
appendPrompt?: string;
|
|
825
837
|
repeatToolDescriptions?: boolean;
|
|
826
838
|
}
|
|
@@ -834,6 +846,8 @@ export interface BuildSystemPromptOptions {
|
|
|
834
846
|
export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}): Promise<BuildSystemPromptResult> {
|
|
835
847
|
return await buildSystemPromptInternal({
|
|
836
848
|
cwd: options.cwd,
|
|
849
|
+
agentDir: options.agentDir,
|
|
850
|
+
profileAuthority: options.profileAuthority,
|
|
837
851
|
skills: options.skills,
|
|
838
852
|
contextFiles: options.contextFiles,
|
|
839
853
|
appendSystemPrompt: options.appendPrompt,
|
|
@@ -1015,14 +1029,89 @@ export function createPluginHooksExtension(hooks: ConstrainedPluginHook[]): Exte
|
|
|
1015
1029
|
if (!normalized) throw new Error("Hook normalization invariant violated");
|
|
1016
1030
|
const registrationEvent = normalized.runtimeEvent;
|
|
1017
1031
|
const target = normalized.toolName === "*" ? undefined : normalized.toolName;
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1032
|
+
if (!hook.functionHook) {
|
|
1033
|
+
const legacyHandler: (...args: unknown[]) => unknown = target
|
|
1034
|
+
? (event: unknown, ...rest: unknown[]) => {
|
|
1035
|
+
const record = event as { toolName?: string; tool?: { name?: string }; name?: string } | undefined;
|
|
1036
|
+
const toolName = record?.toolName ?? record?.tool?.name ?? record?.name;
|
|
1037
|
+
if (toolName !== target) return undefined;
|
|
1038
|
+
return (hook.handler as (...args: unknown[]) => unknown)(event, ...rest);
|
|
1039
|
+
}
|
|
1040
|
+
: (hook.handler as (...args: unknown[]) => unknown);
|
|
1041
|
+
(api.on as (event: string, handler: (...args: unknown[]) => void) => void)(
|
|
1042
|
+
registrationEvent,
|
|
1043
|
+
legacyHandler,
|
|
1044
|
+
);
|
|
1045
|
+
continue;
|
|
1046
|
+
}
|
|
1047
|
+
const handler: FunctionHook = async (invocation, _capabilities, next) => {
|
|
1048
|
+
const legacyResult = await (hook.handler as (...args: unknown[]) => unknown)(invocation.payload, undefined);
|
|
1049
|
+
if (legacyResult === undefined) return await next();
|
|
1050
|
+
if (invocation.eventType === "tool_call") {
|
|
1051
|
+
const result = legacyResult as { block?: unknown; reason?: unknown; input?: unknown };
|
|
1052
|
+
if (result.block === true) {
|
|
1053
|
+
return {
|
|
1054
|
+
action: "deny",
|
|
1055
|
+
reason:
|
|
1056
|
+
typeof result.reason === "string" ? result.reason : "Tool execution blocked by plugin hook",
|
|
1057
|
+
};
|
|
1058
|
+
}
|
|
1059
|
+
if (result.input !== undefined) {
|
|
1060
|
+
return {
|
|
1061
|
+
action: "continue",
|
|
1062
|
+
event: { ...invocation.payload, input: result.input as Record<string, unknown> } as ExtensionEvent,
|
|
1063
|
+
} as FunctionHookResult;
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
if (invocation.eventType === "tool_result") {
|
|
1067
|
+
const result = legacyResult as { content?: unknown; details?: unknown; isError?: unknown };
|
|
1068
|
+
if (result.content !== undefined || result.details !== undefined || result.isError !== undefined) {
|
|
1069
|
+
return {
|
|
1070
|
+
action: "continue",
|
|
1071
|
+
event: {
|
|
1072
|
+
...invocation.payload,
|
|
1073
|
+
...(result.content === undefined ? {} : { content: result.content }),
|
|
1074
|
+
...(result.details === undefined ? {} : { details: result.details }),
|
|
1075
|
+
...(result.isError === undefined ? {} : { isError: result.isError }),
|
|
1076
|
+
},
|
|
1077
|
+
} as FunctionHookResult;
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
if (invocation.eventType === "context" && (legacyResult as { messages?: unknown }).messages !== undefined) {
|
|
1081
|
+
return {
|
|
1082
|
+
action: "continue",
|
|
1083
|
+
event: {
|
|
1084
|
+
...invocation.payload,
|
|
1085
|
+
messages: (legacyResult as { messages: unknown }).messages,
|
|
1086
|
+
} as ExtensionEvent,
|
|
1087
|
+
} as FunctionHookResult;
|
|
1088
|
+
}
|
|
1089
|
+
if (
|
|
1090
|
+
invocation.eventType.startsWith("session_before_") &&
|
|
1091
|
+
(legacyResult as { cancel?: unknown }).cancel === true
|
|
1092
|
+
) {
|
|
1093
|
+
return { action: "deny", reason: "Session change blocked by plugin hook" };
|
|
1094
|
+
}
|
|
1095
|
+
if (invocation.eventType === "before_agent_start") {
|
|
1096
|
+
const result = legacyResult as { message?: unknown; systemPrompt?: unknown };
|
|
1097
|
+
if (result.message !== undefined || result.systemPrompt !== undefined) {
|
|
1098
|
+
return {
|
|
1099
|
+
action: "return",
|
|
1100
|
+
value: {
|
|
1101
|
+
...(result.message === undefined ? {} : { messages: [result.message] }),
|
|
1102
|
+
...(result.systemPrompt === undefined ? {} : { systemPrompt: result.systemPrompt }),
|
|
1103
|
+
},
|
|
1104
|
+
} as FunctionHookResult;
|
|
1023
1105
|
}
|
|
1024
|
-
|
|
1025
|
-
|
|
1106
|
+
}
|
|
1107
|
+
return await next();
|
|
1108
|
+
};
|
|
1109
|
+
const options = {
|
|
1110
|
+
...(target === undefined ? {} : { target }),
|
|
1111
|
+
registrationId: hook.extensionId,
|
|
1112
|
+
...(hook.grant ?? {}),
|
|
1113
|
+
};
|
|
1114
|
+
api.registerFunctionHook(registrationEvent as FunctionHookEventType, handler, options);
|
|
1026
1115
|
}
|
|
1027
1116
|
};
|
|
1028
1117
|
}
|
|
@@ -1112,14 +1201,14 @@ function buildMCPPromptCommands(manager: MCPManager): LoadedCustomCommand[] {
|
|
|
1112
1201
|
function withEmbeddedDefaultGjcSkills(skills: Skill[]): Skill[] {
|
|
1113
1202
|
const byName = new Map<string, Skill>();
|
|
1114
1203
|
for (const skill of skills) {
|
|
1115
|
-
const key = skill.name
|
|
1204
|
+
const key = getSkillFilesystemIdentity(skill.name);
|
|
1116
1205
|
if (!byName.has(key)) byName.set(key, skill);
|
|
1117
1206
|
}
|
|
1118
1207
|
// The four public GJC workflow skills are a product invariant: even if a
|
|
1119
1208
|
// caller-supplied or filesystem skill shares a name, the bundled definition
|
|
1120
1209
|
// wins so workflow routing can never be silently hijacked.
|
|
1121
1210
|
for (const defaultSkill of getEmbeddedDefaultGjcSkills()) {
|
|
1122
|
-
byName.set(defaultSkill.name
|
|
1211
|
+
byName.set(getSkillFilesystemIdentity(defaultSkill.name), defaultSkill);
|
|
1123
1212
|
}
|
|
1124
1213
|
return [...byName.values()];
|
|
1125
1214
|
}
|
|
@@ -1393,7 +1482,14 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1393
1482
|
}
|
|
1394
1483
|
const cwd = options.cwd ?? getProjectDir();
|
|
1395
1484
|
const explicitMcpConfigPath = !isCanonicalSubSession && !options.mcpManager ? options.mcpConfigPath : undefined;
|
|
1396
|
-
const agentDir = options.agentDir ?? getDefaultAgentDir();
|
|
1485
|
+
const agentDir = options.agentDir ?? options.settings?.getAgentDir() ?? getDefaultAgentDir();
|
|
1486
|
+
const profileAuthority =
|
|
1487
|
+
options.profileAuthority ??
|
|
1488
|
+
(options.agentDir !== undefined || options.settings !== undefined
|
|
1489
|
+
? normalizePathForComparison(agentDir) !== normalizePathForComparison(getAgentDir())
|
|
1490
|
+
? "custom"
|
|
1491
|
+
: getAgentProfileAuthority()
|
|
1492
|
+
: getAgentProfileAuthority());
|
|
1397
1493
|
const eventBus = options.eventBus ?? new EventBus();
|
|
1398
1494
|
const hasInjectedAuth = options.authStorage !== undefined || options.modelRegistry !== undefined;
|
|
1399
1495
|
|
|
@@ -1581,7 +1677,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1581
1677
|
// session-context build, tool creation, MCP discovery, and extension discovery.
|
|
1582
1678
|
const contextFilesResultPromise = options.contextFiles
|
|
1583
1679
|
? Promise.resolve({ contextFiles: options.contextFiles, warnings: [] })
|
|
1584
|
-
: logger.time("discoverContextFiles", loadContextFilesResultInternal, { cwd });
|
|
1680
|
+
: logger.time("discoverContextFiles", loadContextFilesResultInternal, { cwd, agentDir, profileAuthority });
|
|
1585
1681
|
contextFilesResultPromise.catch(() => {});
|
|
1586
1682
|
const promptTemplatesPromise = options.promptTemplates
|
|
1587
1683
|
? Promise.resolve(options.promptTemplates)
|
|
@@ -1982,9 +2078,10 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1982
2078
|
skills = withEmbeddedDefaultGjcSkills(options.skills);
|
|
1983
2079
|
skillWarnings = [];
|
|
1984
2080
|
} else if (settings.get("skills.enabled")) {
|
|
1985
|
-
const skillsResult = await logger.time("
|
|
2081
|
+
const skillsResult = await logger.time("discoverSkills", loadSkills, {
|
|
1986
2082
|
...settings.getGroup("skills"),
|
|
1987
2083
|
agentDir,
|
|
2084
|
+
profileAuthority,
|
|
1988
2085
|
cwd,
|
|
1989
2086
|
disabledExtensions: settings.get("disabledExtensions"),
|
|
1990
2087
|
});
|
|
@@ -2006,7 +2103,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2006
2103
|
const rulesResult =
|
|
2007
2104
|
options.rules !== undefined
|
|
2008
2105
|
? { items: options.rules, warnings: undefined }
|
|
2009
|
-
: await loadCapability<Rule>(ruleCapability.id, { cwd, agentDir, settings });
|
|
2106
|
+
: await loadCapability<Rule>(ruleCapability.id, { cwd, agentDir, profileAuthority, settings });
|
|
2010
2107
|
const rulebookRules: Rule[] = [];
|
|
2011
2108
|
const alwaysApplyRules: Rule[] = [];
|
|
2012
2109
|
for (const rule of rulesResult.items) {
|
|
@@ -2334,7 +2431,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2334
2431
|
*/
|
|
2335
2432
|
const applyRescopedReadState = async (to: string): Promise<void> => {
|
|
2336
2433
|
try {
|
|
2337
|
-
const rediscovered = await loadContextFilesResultInternal({ cwd: to });
|
|
2434
|
+
const rediscovered = await loadContextFilesResultInternal({ cwd: to, agentDir, profileAuthority });
|
|
2338
2435
|
contextFiles = rediscovered.contextFiles;
|
|
2339
2436
|
} catch (error) {
|
|
2340
2437
|
logger.warn("Failed to re-discover context files after session rescope", {
|
|
@@ -2375,6 +2472,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2375
2472
|
return sessionManager.getCwd();
|
|
2376
2473
|
},
|
|
2377
2474
|
hasUI: options.hasUI ?? false,
|
|
2475
|
+
profileAuthority,
|
|
2378
2476
|
workflowGateEligible: true,
|
|
2379
2477
|
enableLsp,
|
|
2380
2478
|
get hasEditTool() {
|
|
@@ -2693,6 +2791,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2693
2791
|
}
|
|
2694
2792
|
: {}),
|
|
2695
2793
|
getSessionFile: () => sessionManager.getSessionFile() ?? null,
|
|
2794
|
+
getSessionAgentDir: () => session?.getSessionAgentDir() ?? options.agentDir ?? settings.getAgentDir(),
|
|
2696
2795
|
getEvalKernelOwnerId: () => evalKernelOwnerId,
|
|
2697
2796
|
assertEvalExecutionAllowed: () => session?.assertEvalExecutionAllowed(),
|
|
2698
2797
|
trackEvalExecution: (execution, abortController) =>
|
|
@@ -2974,7 +3073,14 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2974
3073
|
cwdCapturingToolNames.push(...pluginToolResult.tools.map(tool => tool.name));
|
|
2975
3074
|
}
|
|
2976
3075
|
for (const q of pluginToolResult.quarantine) {
|
|
2977
|
-
gjcFindings.add({
|
|
3076
|
+
gjcFindings.add({
|
|
3077
|
+
identity: q.identity,
|
|
3078
|
+
surfaceId: q.surfaceId,
|
|
3079
|
+
code: q.code,
|
|
3080
|
+
message: q.message,
|
|
3081
|
+
decision: "quarantined",
|
|
3082
|
+
provenance: { source: "plugin-bundle", plugin: q.plugin },
|
|
3083
|
+
});
|
|
2978
3084
|
logger.warn("Quarantined GJC plugin surface", { plugin: q.plugin, surface: q.surfaceId, code: q.code });
|
|
2979
3085
|
}
|
|
2980
3086
|
} catch (error) {
|
|
@@ -3064,7 +3170,14 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
3064
3170
|
try {
|
|
3065
3171
|
const { configs, quarantine } = await buildPluginMcpConfigs({ cwd });
|
|
3066
3172
|
for (const q of quarantine) {
|
|
3067
|
-
gjcFindings.add({
|
|
3173
|
+
gjcFindings.add({
|
|
3174
|
+
identity: q.identity,
|
|
3175
|
+
surfaceId: q.surfaceId,
|
|
3176
|
+
code: q.code,
|
|
3177
|
+
message: q.message,
|
|
3178
|
+
decision: "quarantined",
|
|
3179
|
+
provenance: { source: "plugin-bundle", plugin: q.plugin },
|
|
3180
|
+
});
|
|
3068
3181
|
logger.warn("Quarantined GJC plugin MCP", { plugin: q.plugin, surface: q.surfaceId, code: q.code });
|
|
3069
3182
|
}
|
|
3070
3183
|
const pluginNames = new Set(Object.keys(configs));
|
|
@@ -3209,12 +3322,22 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
3209
3322
|
// Always-on constrained plugin hooks (validated registry surfaces). Additive
|
|
3210
3323
|
// and a no-op without installed plugins; the loader denies all dangerous APIs.
|
|
3211
3324
|
try {
|
|
3212
|
-
const pluginHookResult = await loadConstrainedPluginHooks({
|
|
3325
|
+
const pluginHookResult = await loadConstrainedPluginHooks({
|
|
3326
|
+
cwd,
|
|
3327
|
+
activationGeneration: gjcActivationGeneration,
|
|
3328
|
+
});
|
|
3213
3329
|
if (pluginHookResult.hooks.length > 0) {
|
|
3214
3330
|
inlineExtensions.push(createPluginHooksExtension(pluginHookResult.hooks));
|
|
3215
3331
|
}
|
|
3216
3332
|
for (const q of pluginHookResult.quarantine) {
|
|
3217
|
-
gjcFindings.add({
|
|
3333
|
+
gjcFindings.add({
|
|
3334
|
+
identity: q.identity,
|
|
3335
|
+
surfaceId: q.surfaceId,
|
|
3336
|
+
code: q.code,
|
|
3337
|
+
message: q.message,
|
|
3338
|
+
decision: "quarantined",
|
|
3339
|
+
provenance: { source: "plugin-bundle", plugin: q.plugin },
|
|
3340
|
+
});
|
|
3218
3341
|
logger.warn("Quarantined GJC plugin hook", { plugin: q.plugin, surface: q.surfaceId, code: q.code });
|
|
3219
3342
|
}
|
|
3220
3343
|
} catch (error) {
|
|
@@ -3774,7 +3897,10 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
3774
3897
|
} else if (!toolRegistry.has("resolve")) {
|
|
3775
3898
|
const resolveTool = await logger.time("createTools:resolve:session", HIDDEN_TOOLS.resolve, toolSession);
|
|
3776
3899
|
if (resolveTool) {
|
|
3777
|
-
const
|
|
3900
|
+
const resolveWithNotice = wrapToolWithMetaNotice(resolveTool);
|
|
3901
|
+
const wrappedResolveTool = extensionRunner
|
|
3902
|
+
? (new ExtensionToolWrapper(resolveWithNotice, extensionRunner) as AgentTool)
|
|
3903
|
+
: resolveWithNotice;
|
|
3778
3904
|
builtinCandidateTools.push(wrappedResolveTool);
|
|
3779
3905
|
toolRegistry.set(wrappedResolveTool.name, wrappedResolveTool);
|
|
3780
3906
|
builtinToolIdentities.add(wrappedResolveTool);
|
|
@@ -3912,6 +4038,8 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
3912
4038
|
// Live cwd: the prompt is rebuilt after a rescope, and describing the
|
|
3913
4039
|
// retired launcher root there is what makes the model pick wrong paths.
|
|
3914
4040
|
cwd: getLiveCwd(),
|
|
4041
|
+
agentDir,
|
|
4042
|
+
profileAuthority,
|
|
3915
4043
|
skills,
|
|
3916
4044
|
contextFiles,
|
|
3917
4045
|
tools: promptTools,
|
|
@@ -4184,21 +4312,21 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
4184
4312
|
if (!obfuscator?.hasSecrets() || !obfuscateMessagesFn) return converted;
|
|
4185
4313
|
return obfuscateMessagesFn(obfuscator, converted);
|
|
4186
4314
|
};
|
|
4187
|
-
const transformContext = async (messages: AgentMessage[],
|
|
4315
|
+
const transformContext = async (messages: AgentMessage[], signal?: AbortSignal, scope?: AttemptScopeRef) => {
|
|
4188
4316
|
// External Agent events dispatch listeners without awaiting them. The
|
|
4189
4317
|
// session-owned barrier makes any pre-admission artifact transformation
|
|
4190
4318
|
// visible before this provider context is normalized.
|
|
4191
4319
|
await session?.awaitPendingContextTransformations();
|
|
4192
|
-
return extensionRunner ? await extensionRunner.emitContext(messages, scope) : messages;
|
|
4320
|
+
return extensionRunner ? await extensionRunner.emitContext(messages, scope, signal) : messages;
|
|
4193
4321
|
};
|
|
4194
4322
|
const onPayload = extensionRunner
|
|
4195
|
-
? async (payload: unknown, _model?: Model, scope?: AttemptScopeRef) => {
|
|
4196
|
-
return await extensionRunner.emitBeforeProviderRequest(payload, scope);
|
|
4323
|
+
? async (payload: unknown, _model?: Model, scope?: AttemptScopeRef, signal?: AbortSignal) => {
|
|
4324
|
+
return await extensionRunner.emitBeforeProviderRequest(payload, scope, signal);
|
|
4197
4325
|
}
|
|
4198
4326
|
: undefined;
|
|
4199
4327
|
const onResponse: SimpleStreamOptions["onResponse"] | undefined = extensionRunner
|
|
4200
|
-
? async (response, model, scope) => {
|
|
4201
|
-
await extensionRunner.emitAfterProviderResponse(response, model, scope);
|
|
4328
|
+
? async (response, model, scope, signal) => {
|
|
4329
|
+
await extensionRunner.emitAfterProviderResponse(response, model, scope, signal);
|
|
4202
4330
|
}
|
|
4203
4331
|
: undefined;
|
|
4204
4332
|
|
|
@@ -4491,6 +4619,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
4491
4619
|
const reloaded = await loadSkills({
|
|
4492
4620
|
...settings.getGroup("skills"),
|
|
4493
4621
|
agentDir,
|
|
4622
|
+
profileAuthority,
|
|
4494
4623
|
cwd: reloadCwd,
|
|
4495
4624
|
disabledExtensions: settings.get("disabledExtensions"),
|
|
4496
4625
|
});
|
|
@@ -56,18 +56,25 @@ function upstreamUrl(url: string, token: string): string {
|
|
|
56
56
|
return endpoint.toString();
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
function waitForDrain(stream: Writable): Promise<void
|
|
59
|
+
function waitForDrain(stream: Writable): { promise: Promise<void>; cancel: () => void } {
|
|
60
60
|
const { promise, reject, resolve } = Promise.withResolvers<void>();
|
|
61
|
+
let settled = false;
|
|
61
62
|
const onDrain = (): void => done(resolve);
|
|
62
63
|
const onError = (error: Error): void => done(() => reject(error));
|
|
64
|
+
const onClose = (): void => done(() => reject(new Error("downstream_closed")));
|
|
63
65
|
const done = (callback: () => void): void => {
|
|
66
|
+
if (settled) return;
|
|
67
|
+
settled = true;
|
|
64
68
|
stream.removeListener("drain", onDrain);
|
|
65
69
|
stream.removeListener("error", onError);
|
|
70
|
+
stream.removeListener("close", onClose);
|
|
66
71
|
callback();
|
|
67
72
|
};
|
|
68
73
|
stream.once("drain", onDrain);
|
|
69
74
|
stream.once("error", onError);
|
|
70
|
-
|
|
75
|
+
stream.once("close", onClose);
|
|
76
|
+
if (stream.destroyed) onClose();
|
|
77
|
+
return { promise, cancel: onDrain };
|
|
71
78
|
}
|
|
72
79
|
|
|
73
80
|
const WEBSOCKET_CONNECTING = 0;
|
|
@@ -96,7 +103,9 @@ export async function startRelayPair(options: RelayOptions): Promise<RelayPair>
|
|
|
96
103
|
const finished = Promise.withResolvers<void>();
|
|
97
104
|
let closed = false;
|
|
98
105
|
let completed = false;
|
|
99
|
-
let
|
|
106
|
+
let downstreamChunks: Buffer[] = [];
|
|
107
|
+
let downstreamBytes = 0;
|
|
108
|
+
let downstreamDrain: { promise: Promise<void>; cancel: () => void } | undefined;
|
|
100
109
|
const toWs: QueuedFrame[] = [];
|
|
101
110
|
const toDownstream: QueuedFrame[] = [];
|
|
102
111
|
let pendingToWs = 0;
|
|
@@ -123,6 +132,7 @@ export async function startRelayPair(options: RelayOptions): Promise<RelayPair>
|
|
|
123
132
|
const close = async (error?: Error): Promise<void> => {
|
|
124
133
|
if (closed) return finished.promise.catch(() => undefined);
|
|
125
134
|
closed = true;
|
|
135
|
+
downstreamDrain?.cancel();
|
|
126
136
|
detach();
|
|
127
137
|
options.downstream.pause();
|
|
128
138
|
if (ws.readyState === WEBSOCKET_OPEN || ws.readyState === WEBSOCKET_CONNECTING) ws.close();
|
|
@@ -175,33 +185,45 @@ export async function startRelayPair(options: RelayOptions): Promise<RelayPair>
|
|
|
175
185
|
writingDownstream = true;
|
|
176
186
|
if (frame.accounted) pendingToDownstream -= frame.bytes.length;
|
|
177
187
|
try {
|
|
178
|
-
if (!options.downstreamSink.write(frame.bytes)
|
|
188
|
+
if (!options.downstreamSink.write(frame.bytes) && !closed) {
|
|
189
|
+
downstreamDrain = waitForDrain(options.downstreamSink);
|
|
190
|
+
await downstreamDrain.promise;
|
|
191
|
+
}
|
|
179
192
|
} catch (error) {
|
|
180
193
|
await close(error instanceof Error ? error : new Error(String(error)));
|
|
181
194
|
return;
|
|
182
195
|
} finally {
|
|
196
|
+
downstreamDrain = undefined;
|
|
183
197
|
writingDownstream = false;
|
|
184
198
|
}
|
|
185
199
|
void pumpDownstream();
|
|
186
200
|
};
|
|
187
201
|
const consumeLines = (chunk: Buffer): void => {
|
|
188
|
-
|
|
189
|
-
let newline =
|
|
202
|
+
let start = 0;
|
|
203
|
+
let newline = chunk.indexOf(0x0a);
|
|
190
204
|
while (newline >= 0) {
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
if (line.length === 0)
|
|
205
|
+
const length = downstreamBytes + newline - start;
|
|
206
|
+
if (length === 0)
|
|
194
207
|
return fail({ type: "transport_error", code: "protocol_error", direction: "downstream->ws" });
|
|
195
|
-
if (
|
|
208
|
+
if (length > REQUEST_FRAME_BYTES)
|
|
196
209
|
return fail({ type: "transport_error", code: "frame_oversize", direction: "downstream->ws" });
|
|
210
|
+
downstreamChunks.push(chunk.subarray(start, newline));
|
|
211
|
+
const line = Buffer.concat(downstreamChunks, length);
|
|
212
|
+
downstreamChunks = [];
|
|
213
|
+
downstreamBytes = 0;
|
|
197
214
|
if (options.validateDownstreamFrame && !options.validateDownstreamFrame(line.toString("utf8")))
|
|
198
215
|
return fail({ type: "transport_error", code: "protocol_error", direction: "downstream->ws" });
|
|
199
216
|
enqueue(toWs, "downstream->ws", line);
|
|
200
217
|
if (closed) return;
|
|
201
|
-
|
|
218
|
+
start = newline + 1;
|
|
219
|
+
newline = chunk.indexOf(0x0a, start);
|
|
220
|
+
}
|
|
221
|
+
if (start < chunk.length) {
|
|
222
|
+
downstreamBytes += chunk.length - start;
|
|
223
|
+
if (downstreamBytes > REQUEST_FRAME_BYTES)
|
|
224
|
+
return fail({ type: "transport_error", code: "frame_oversize", direction: "downstream->ws" });
|
|
225
|
+
downstreamChunks.push(chunk.subarray(start));
|
|
202
226
|
}
|
|
203
|
-
if (downstreamBuffer.length > REQUEST_FRAME_BYTES)
|
|
204
|
-
fail({ type: "transport_error", code: "frame_oversize", direction: "downstream->ws" });
|
|
205
227
|
};
|
|
206
228
|
const onData = (chunk: Buffer | string): void => consumeLines(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
207
229
|
const onEnd = (): void => void close();
|