@gajae-code/coding-agent 0.16.3 → 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 +113 -0
- package/dist/types/capability/types.d.ts +4 -0
- package/dist/types/cli/args.d.ts +2 -2
- package/dist/types/cli/customize-doctor.d.ts +22 -0
- package/dist/types/cli/root-flags.d.ts +4 -2
- package/dist/types/cli.d.ts +1 -1
- package/dist/types/commands/launch.d.ts +1 -1
- package/dist/types/config/autorouting-tier-map.d.ts +3 -0
- package/dist/types/config/file-lock.d.ts +31 -3
- package/dist/types/config/model-registry.d.ts +4 -0
- package/dist/types/config/model-resolver.d.ts +9 -0
- package/dist/types/config/settings-schema.d.ts +29 -1
- 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/claude-plugins.d.ts +3 -1
- package/dist/types/discovery/helpers.d.ts +35 -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/mcp-policy.d.ts +16 -0
- package/dist/types/extensibility/gjc-plugins/paths.d.ts +2 -0
- 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 +5 -2
- package/dist/types/extensibility/shared-events.d.ts +1 -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 +14 -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/assistant-message.d.ts +1 -2
- 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/components/settings-selector.d.ts +6 -1
- package/dist/types/modes/components/status-line/command.d.ts +35 -0
- package/dist/types/modes/components/status-line/index.d.ts +1 -0
- package/dist/types/modes/components/status-line/types.d.ts +5 -0
- package/dist/types/modes/components/tool-status-header.d.ts +14 -0
- package/dist/types/modes/controllers/event-controller.d.ts +6 -0
- package/dist/types/modes/interactive-mode.d.ts +3 -0
- package/dist/types/modes/types.d.ts +7 -0
- package/dist/types/runtime-mcp/client.d.ts +9 -1
- package/dist/types/runtime-mcp/manager.d.ts +7 -1
- package/dist/types/runtime-mcp/pool.d.ts +22 -3
- package/dist/types/runtime-mcp/transports/stdio.d.ts +0 -4
- package/dist/types/runtime-mcp/types.d.ts +22 -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-daemon-runtime.d.ts +12 -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/slack-live-provider.d.ts +6 -0
- package/dist/types/sdk/bus/slack-provider.d.ts +12 -0
- 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 +26 -1
- 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-api-key.d.ts +26 -0
- package/dist/types/sdk/session.d.ts +5 -1
- package/dist/types/sdk/transport/serve-cli.d.ts +1 -1
- package/dist/types/session/agent-session.d.ts +11 -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 +112 -0
- package/dist/types/setup/paseo/setup-deps.d.ts +2 -1
- package/dist/types/skill-state/canonical-skills.d.ts +4 -0
- package/dist/types/system-prompt.d.ts +10 -0
- package/dist/types/task/executor.d.ts +5 -1
- package/dist/types/tools/bash.d.ts +1 -0
- package/dist/types/tools/fetch.d.ts +7 -0
- package/dist/types/tools/github-cache.d.ts +2 -1
- package/dist/types/tools/index.d.ts +10 -0
- package/dist/types/tools/path-utils.d.ts +2 -0
- package/dist/types/tools/search.d.ts +6 -0
- package/package.json +9 -7
- package/scripts/capture-status-line-custom-editor-showcase.ts +151 -0
- package/scripts/generate-sdk-operation-inventory.ts +11 -0
- package/scripts/verify-status-line-custom-editor-showcase.ts +309 -0
- package/src/capability/index.ts +14 -2
- package/src/capability/types.ts +4 -0
- package/src/cli/args.ts +20 -9
- package/src/cli/customize-doctor.ts +155 -12
- package/src/cli/root-flags.ts +5 -3
- package/src/cli.ts +22 -0
- package/src/commands/sdk.ts +74 -31
- package/src/config/autorouting-tier-map.ts +1 -0
- package/src/config/file-lock-gc.ts +40 -2
- package/src/config/file-lock.ts +379 -31
- package/src/config/model-preset-registry.ts +120 -19
- package/src/config/model-profiles.ts +40 -0
- package/src/config/model-registry.ts +73 -23
- package/src/config/model-resolver.ts +48 -0
- package/src/config/settings-schema.ts +33 -1
- package/src/config/settings.ts +1 -0
- 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/extensions/grok-cli-vendor/src/models/catalog.ts +11 -11
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/register.ts +13 -2
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +22 -0
- package/src/discovery/builtin.ts +52 -55
- package/src/discovery/claude-plugins.ts +12 -4
- package/src/discovery/helpers.ts +307 -34
- 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 +228 -60
- package/src/extensibility/gjc-plugins/constrained-hooks.ts +321 -23
- package/src/extensibility/gjc-plugins/installer.ts +13 -12
- package/src/extensibility/gjc-plugins/mcp-policy.ts +81 -52
- package/src/extensibility/gjc-plugins/paths.ts +13 -0
- package/src/extensibility/gjc-plugins/registry.ts +113 -1
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +758 -16
- 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 +149 -190
- package/src/extensibility/shared-events.ts +1 -1
- package/src/extensibility/skill-management.ts +200 -52
- package/src/extensibility/skills.ts +73 -25
- 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/repository-binding.ts +1 -1
- package/src/gjc-runtime/session-state-lock.ts +143 -10
- 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 +12 -12
- 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 +78 -35
- package/src/modes/DESIGN.md +54 -0
- package/src/modes/acp/acp-agent.ts +16 -3
- package/src/modes/components/assistant-message.ts +22 -9
- package/src/modes/components/bash-execution.ts +4 -1
- package/src/modes/components/execution-shared.ts +4 -1
- package/src/modes/components/model-selector.ts +166 -33
- package/src/modes/components/session-observer-overlay.ts +1 -1
- package/src/modes/components/settings-selector.ts +1075 -235
- package/src/modes/components/status-line/command.ts +190 -0
- package/src/modes/components/status-line/index.ts +1 -0
- package/src/modes/components/status-line/segments.ts +32 -5
- package/src/modes/components/status-line/types.ts +5 -0
- package/src/modes/components/tool-status-header.ts +396 -22
- package/src/modes/controllers/command-controller.ts +3 -0
- package/src/modes/controllers/event-controller.ts +151 -7
- package/src/modes/controllers/extension-ui-controller.ts +1 -0
- package/src/modes/controllers/input-controller.ts +6 -3
- package/src/modes/controllers/selector-controller.ts +21 -0
- package/src/modes/interactive-mode.ts +53 -6
- 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 +17 -3
- package/src/modes/utils/ui-helpers.ts +2 -0
- package/src/prompts/system/system-prompt.md +8 -0
- package/src/prompts/tools/search.md +2 -0
- package/src/prompts/tools/subagent.md +1 -0
- package/src/runtime-mcp/client.ts +60 -17
- package/src/runtime-mcp/manager.ts +189 -14
- package/src/runtime-mcp/pool.test.ts +218 -0
- package/src/runtime-mcp/pool.ts +224 -23
- package/src/runtime-mcp/transports/stdio.ts +158 -24
- package/src/runtime-mcp/types.ts +24 -0
- package/src/sdk/broker/broker.ts +124 -32
- 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 +72 -6
- 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 +478 -49
- package/src/sdk/bus/slack-live-provider.ts +12 -0
- package/src/sdk/bus/slack-provider.ts +5 -0
- 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 +11 -8
- 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 +52 -10
- package/src/sdk/host/session-runtime.ts +383 -44
- package/src/sdk/lifecycle/service.ts +4 -0
- package/src/sdk/protocol/operation-inventory.generated.json +77 -0
- package/src/sdk/router/session-router.ts +89 -38
- package/src/sdk/session-api-key.ts +94 -0
- package/src/sdk/session.ts +228 -55
- package/src/sdk/transport/relay.ts +35 -13
- package/src/sdk/transport/serve-cli.ts +3 -3
- package/src/session/agent-session.ts +240 -90
- package/src/session/contribution-prep.ts +214 -21
- 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 +456 -0
- package/src/setup/paseo/setup-deps.ts +15 -3
- package/src/skill-state/canonical-skills.ts +12 -0
- package/src/skills/skills.test.ts +41 -21
- package/src/slash-commands/builtin-registry.ts +1 -0
- package/src/system-prompt.ts +29 -3
- package/src/task/executor.ts +7 -1
- package/src/task/index.ts +21 -4
- package/src/tools/bash.ts +63 -19
- package/src/tools/cron.ts +1 -1
- package/src/tools/fetch.ts +29 -1
- package/src/tools/gh.ts +26 -3
- package/src/tools/github-cache.ts +68 -16
- package/src/tools/index.ts +10 -0
- package/src/tools/job.ts +21 -4
- package/src/tools/monitor.ts +8 -2
- package/src/tools/path-utils.ts +7 -0
- 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/search.ts +116 -58
- package/src/tools/skill-discovery.ts +5 -0
- package/src/tools/skill.ts +37 -2
- package/src/tools/subagent.ts +6 -3
- package/src/tools/tool-catalog.generated.ts +10 -3
- package/src/tools/ultragoal-ask-guard.ts +2 -2
- package/src/web/insane/bridge.ts +113 -23
- package/src/web/search/providers/perplexity.ts +102 -41
|
@@ -38,6 +38,8 @@ import { initializeWithSettings, loadCapability } from "../discovery";
|
|
|
38
38
|
import { inspectClaudeConvention } from "../discovery/claude";
|
|
39
39
|
import { inspectCodexConvention } from "../discovery/codex";
|
|
40
40
|
import { scanSkillsFromDir } from "../discovery/helpers";
|
|
41
|
+
import { functionHookGrantHash, normalizeFunctionHookGrant } from "../extensibility/extensions/function-hooks";
|
|
42
|
+
import { compileGjcPluginBundle } from "../extensibility/gjc-plugins/compiler";
|
|
41
43
|
import { summarizeGjcPluginObservability } from "../extensibility/gjc-plugins/observability";
|
|
42
44
|
import { loadEffectiveGjcPluginRegistry } from "../extensibility/gjc-plugins/registry";
|
|
43
45
|
import { getEnabledPlugins } from "../extensibility/plugins/loader";
|
|
@@ -47,7 +49,10 @@ import { loadAllMCPConfigs } from "../runtime-mcp/config";
|
|
|
47
49
|
import { readDisabledServers } from "../runtime-mcp/config-writer";
|
|
48
50
|
import { canonicalizeMCPEndpoint } from "../runtime-mcp/pool-key";
|
|
49
51
|
import { redactMCPEndpoint } from "../runtime-mcp/redaction";
|
|
50
|
-
import {
|
|
52
|
+
import {
|
|
53
|
+
getSkillFilesystemIdentity,
|
|
54
|
+
isCanonicalGjcWorkflowSkillFilesystemAlias,
|
|
55
|
+
} from "../skill-state/canonical-skills";
|
|
51
56
|
import { expandTilde } from "../tools/path-utils";
|
|
52
57
|
|
|
53
58
|
// =============================================================================
|
|
@@ -153,6 +158,29 @@ export interface CustomizeDoctorItem {
|
|
|
153
158
|
mcp?: McpSafeSummary;
|
|
154
159
|
/** Present only for quarantined plugin-bundle surfaces. */
|
|
155
160
|
quarantineCode?: string;
|
|
161
|
+
/** Metadata-only Function Hook policy projection; hook code is never executed. */
|
|
162
|
+
functionHooks?: CustomizeFunctionHookSummary[];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export interface CustomizeFunctionHookSummary {
|
|
166
|
+
extensionId: string;
|
|
167
|
+
order: number;
|
|
168
|
+
event: string;
|
|
169
|
+
target?: string;
|
|
170
|
+
phase?: "before" | "after";
|
|
171
|
+
scope: "user" | "project";
|
|
172
|
+
plugin: string;
|
|
173
|
+
relativePath: string;
|
|
174
|
+
status: "disabled" | "quarantined" | "blocked-isolate" | "legacy-active";
|
|
175
|
+
requestedCapabilities: string[];
|
|
176
|
+
effectiveCapabilities: string[];
|
|
177
|
+
attenuateDownstream: string[];
|
|
178
|
+
networkDestinations: string[];
|
|
179
|
+
filesystemRoots: string[];
|
|
180
|
+
capabilityHash?: string;
|
|
181
|
+
implementationHash?: string;
|
|
182
|
+
quarantineCode?: string;
|
|
183
|
+
remediation: string;
|
|
156
184
|
}
|
|
157
185
|
|
|
158
186
|
export interface CustomizeDoctorSurface {
|
|
@@ -200,8 +228,6 @@ export interface CustomizeDoctorCommandOptions {
|
|
|
200
228
|
|
|
201
229
|
const REDACTED = "<redacted>";
|
|
202
230
|
|
|
203
|
-
const BUILT_IN_SKILL_NAMES = new Set<string>(CANONICAL_GJC_WORKFLOW_SKILLS);
|
|
204
|
-
|
|
205
231
|
const SENSITIVE_KEY_PATTERN =
|
|
206
232
|
/(?:token|secret|key|credential|password|passwd|pwd|authorization|auth|bearer|cookie|session|apikey)/i;
|
|
207
233
|
|
|
@@ -655,7 +681,7 @@ async function collectSkills(cwd: string, activeSettings: SettingsInstance): Pro
|
|
|
655
681
|
cwd,
|
|
656
682
|
disabledExtensions: activeSettings.get("disabledExtensions"),
|
|
657
683
|
});
|
|
658
|
-
for (const skill of result.skills) loadedNames.add(skill.name);
|
|
684
|
+
for (const skill of result.skills) loadedNames.add(getSkillFilesystemIdentity(skill.name));
|
|
659
685
|
}
|
|
660
686
|
|
|
661
687
|
const skillScopeNotes: string[] = [];
|
|
@@ -730,7 +756,7 @@ async function collectSkills(cwd: string, activeSettings: SettingsInstance): Pro
|
|
|
730
756
|
[`Move the skill under .gjc/skills/<name>/SKILL.md to make it loadable`],
|
|
731
757
|
);
|
|
732
758
|
}
|
|
733
|
-
if (
|
|
759
|
+
if (isCanonicalGjcWorkflowSkillFilesystemAlias(entry.name)) {
|
|
734
760
|
return finalizeItem(
|
|
735
761
|
base,
|
|
736
762
|
"shadowed",
|
|
@@ -740,7 +766,7 @@ async function collectSkills(cwd: string, activeSettings: SettingsInstance): Pro
|
|
|
740
766
|
{ precedence: { priority: entry.priority, shadowedBy: { provider: "bundled", scope: "native" } } },
|
|
741
767
|
);
|
|
742
768
|
}
|
|
743
|
-
if (loadedNames.has(entry.name)) {
|
|
769
|
+
if (loadedNames.has(getSkillFilesystemIdentity(entry.name))) {
|
|
744
770
|
return finalizeItem(base, "loaded", "loaded", "Loaded by session startup.", []);
|
|
745
771
|
}
|
|
746
772
|
if (ignoredPatterns.length > 0 || includePatterns.length > 0) {
|
|
@@ -809,7 +835,7 @@ async function collectSkills(cwd: string, activeSettings: SettingsInstance): Pro
|
|
|
809
835
|
);
|
|
810
836
|
continue;
|
|
811
837
|
}
|
|
812
|
-
if (
|
|
838
|
+
if (isCanonicalGjcWorkflowSkillFilesystemAlias(skill.name)) {
|
|
813
839
|
items.push(
|
|
814
840
|
finalizeItem(
|
|
815
841
|
base,
|
|
@@ -828,7 +854,10 @@ async function collectSkills(cwd: string, activeSettings: SettingsInstance): Pro
|
|
|
828
854
|
// in loadedNames even though it loses the name collision to an
|
|
829
855
|
// earlier-priority source. The collision must report shadowed-by-
|
|
830
856
|
// precedence, not a second "loaded" item.
|
|
831
|
-
const
|
|
857
|
+
const skillIdentity = getSkillFilesystemIdentity(skill.name);
|
|
858
|
+
const collisionWinner = items.find(
|
|
859
|
+
i => getSkillFilesystemIdentity(i.name) === skillIdentity && i.status === "loaded",
|
|
860
|
+
);
|
|
832
861
|
if (collisionWinner) {
|
|
833
862
|
items.push(
|
|
834
863
|
finalizeItem(
|
|
@@ -847,7 +876,7 @@ async function collectSkills(cwd: string, activeSettings: SettingsInstance): Pro
|
|
|
847
876
|
);
|
|
848
877
|
continue;
|
|
849
878
|
}
|
|
850
|
-
if (loadedNames.has(
|
|
879
|
+
if (loadedNames.has(skillIdentity)) {
|
|
851
880
|
items.push(
|
|
852
881
|
finalizeItem(base, "loaded", "loaded", "Loaded by session startup from skills.customDirectories.", []),
|
|
853
882
|
);
|
|
@@ -910,8 +939,11 @@ async function collectHooks(cwd: string, activeSettings: SettingsInstance): Prom
|
|
|
910
939
|
nameOf: hook => hook.name,
|
|
911
940
|
pathOf: hook => hook.path,
|
|
912
941
|
notExecutedDetail:
|
|
913
|
-
"
|
|
914
|
-
notExecutedRemediation: [
|
|
942
|
+
"Trusted filesystem hook module discovered for session-start activation. Doctor does not execute the module, so dynamic Function Hook registrations and effective runtime order remain opaque until a session loads it.",
|
|
943
|
+
notExecutedRemediation: [
|
|
944
|
+
"Review the trusted hook source before session startup",
|
|
945
|
+
"Use plugin-bundle Function Hooks for declarative grants, hashes, quarantine, and metadata-only policy inspection",
|
|
946
|
+
],
|
|
915
947
|
});
|
|
916
948
|
}
|
|
917
949
|
|
|
@@ -1140,7 +1172,101 @@ async function collectPluginBundles(cwd: string): Promise<CustomizeDoctorSurface
|
|
|
1140
1172
|
const bundleEntries = await loadEffectiveGjcPluginRegistry(cwd, { migrate: false });
|
|
1141
1173
|
const observability = await summarizeGjcPluginObservability(cwd, { migrate: false });
|
|
1142
1174
|
const items: CustomizeDoctorItem[] = [...npmItems];
|
|
1175
|
+
let globalFunctionHookOrder = 0;
|
|
1143
1176
|
for (const entry of bundleEntries) {
|
|
1177
|
+
const surfaces = observability.surfaces.filter(s => s.plugin === entry.name && s.scope === entry.scope);
|
|
1178
|
+
let compiledHooks = new Map<
|
|
1179
|
+
string,
|
|
1180
|
+
Awaited<ReturnType<typeof compileGjcPluginBundle>>["surfaces"]["hooks"][number]
|
|
1181
|
+
>();
|
|
1182
|
+
try {
|
|
1183
|
+
const compiled = await compileGjcPluginBundle(entry.pluginRoot);
|
|
1184
|
+
compiledHooks = new Map(compiled.surfaces.hooks.map(hook => [hook.extensionId, hook]));
|
|
1185
|
+
} catch {
|
|
1186
|
+
// Existing observability reports unreadable/hash-drift bundles. Keep
|
|
1187
|
+
// declarative rows visible and mark unmatched metadata quarantined.
|
|
1188
|
+
}
|
|
1189
|
+
const functionHooks: CustomizeFunctionHookSummary[] = entry.surfaces.hooks.map(hook => {
|
|
1190
|
+
const observed = surfaces.find(surface => surface.extensionId === hook.extensionId);
|
|
1191
|
+
const compiled = compiledHooks.get(hook.extensionId);
|
|
1192
|
+
const hasGrantMetadata =
|
|
1193
|
+
hook.capabilities !== undefined ||
|
|
1194
|
+
hook.networkDestinations !== undefined ||
|
|
1195
|
+
hook.filesystemRoots !== undefined ||
|
|
1196
|
+
hook.capabilityHash !== undefined;
|
|
1197
|
+
let metadataValid =
|
|
1198
|
+
compiled !== undefined &&
|
|
1199
|
+
((hook.functionHook === true && hasGrantMetadata) ||
|
|
1200
|
+
(hook.functionHook !== true && !hasGrantMetadata && compiled.functionHook !== true));
|
|
1201
|
+
try {
|
|
1202
|
+
const grant = normalizeFunctionHookGrant({
|
|
1203
|
+
capabilities: hook.capabilities,
|
|
1204
|
+
networkDestinations: hook.networkDestinations,
|
|
1205
|
+
filesystemRoots: hook.filesystemRoots,
|
|
1206
|
+
});
|
|
1207
|
+
metadataValid =
|
|
1208
|
+
metadataValid &&
|
|
1209
|
+
hook.functionHook === compiled?.functionHook &&
|
|
1210
|
+
hook.event === compiled?.event &&
|
|
1211
|
+
hook.target === compiled?.target &&
|
|
1212
|
+
hook.phase === compiled?.phase &&
|
|
1213
|
+
hook.relativePath === compiled?.relativePath &&
|
|
1214
|
+
hook.implementationHash === compiled?.implementationHash &&
|
|
1215
|
+
(hook.functionHook !== true ||
|
|
1216
|
+
(hook.capabilityHash?.toLowerCase() === functionHookGrantHash(grant).toLowerCase() &&
|
|
1217
|
+
hook.capabilityHash?.toLowerCase() === compiled?.capabilityHash?.toLowerCase() &&
|
|
1218
|
+
JSON.stringify(grant.capabilities) === JSON.stringify(compiled?.capabilities ?? []) &&
|
|
1219
|
+
JSON.stringify(grant.networkDestinations) ===
|
|
1220
|
+
JSON.stringify(compiled?.networkDestinations ?? []) &&
|
|
1221
|
+
JSON.stringify(grant.filesystemRoots) === JSON.stringify(compiled?.filesystemRoots ?? [])));
|
|
1222
|
+
} catch {
|
|
1223
|
+
metadataValid = false;
|
|
1224
|
+
}
|
|
1225
|
+
const status: CustomizeFunctionHookSummary["status"] =
|
|
1226
|
+
!metadataValid || observed?.status === "quarantined"
|
|
1227
|
+
? "quarantined"
|
|
1228
|
+
: !entry.enabled || entry.disabledSurfaceIds.includes(hook.extensionId)
|
|
1229
|
+
? "disabled"
|
|
1230
|
+
: hook.functionHook === true
|
|
1231
|
+
? "blocked-isolate"
|
|
1232
|
+
: "legacy-active";
|
|
1233
|
+
return {
|
|
1234
|
+
extensionId: hook.extensionId,
|
|
1235
|
+
order: globalFunctionHookOrder++,
|
|
1236
|
+
event: hook.event,
|
|
1237
|
+
...(hook.target === undefined ? {} : { target: hook.target }),
|
|
1238
|
+
...(hook.phase === undefined ? {} : { phase: hook.phase }),
|
|
1239
|
+
scope: entry.scope,
|
|
1240
|
+
plugin: entry.name,
|
|
1241
|
+
relativePath: hook.relativePath,
|
|
1242
|
+
status,
|
|
1243
|
+
requestedCapabilities: [...(hook.capabilities ?? [])],
|
|
1244
|
+
effectiveCapabilities: status === "legacy-active" ? [...(hook.capabilities ?? [])] : [],
|
|
1245
|
+
attenuateDownstream: [],
|
|
1246
|
+
networkDestinations: (hook.networkDestinations ?? []).map(destination => {
|
|
1247
|
+
try {
|
|
1248
|
+
const url = new URL(destination);
|
|
1249
|
+
return url.protocol === "https:" && !url.username && !url.password ? url.origin : "[redacted]";
|
|
1250
|
+
} catch {
|
|
1251
|
+
return "[redacted]";
|
|
1252
|
+
}
|
|
1253
|
+
}),
|
|
1254
|
+
filesystemRoots: [...(hook.filesystemRoots ?? [])],
|
|
1255
|
+
...(hook.capabilityHash === undefined ? {} : { capabilityHash: hook.capabilityHash }),
|
|
1256
|
+
...(hook.implementationHash === undefined ? {} : { implementationHash: hook.implementationHash }),
|
|
1257
|
+
...(observed?.quarantineCode === undefined && metadataValid
|
|
1258
|
+
? {}
|
|
1259
|
+
: { quarantineCode: observed?.quarantineCode ?? "security_policy" }),
|
|
1260
|
+
remediation:
|
|
1261
|
+
status === "blocked-isolate"
|
|
1262
|
+
? "Function Hook remains disabled until a capability-enforcing plugin isolate is available."
|
|
1263
|
+
: status === "quarantined"
|
|
1264
|
+
? "Reinstall the bundle and verify installed metadata and file hashes."
|
|
1265
|
+
: status === "disabled"
|
|
1266
|
+
? `Enable surface ${hook.extensionId} only after reviewing its declared policy.`
|
|
1267
|
+
: "Legacy constrained hook executes under the existing trusted compatibility policy.",
|
|
1268
|
+
};
|
|
1269
|
+
});
|
|
1144
1270
|
const base: Omit<CustomizeDoctorItem, "status" | "reason" | "detail" | "remediation"> = {
|
|
1145
1271
|
name: entry.name,
|
|
1146
1272
|
kind: "plugin-bundle",
|
|
@@ -1153,6 +1279,7 @@ async function collectPluginBundles(cwd: string): Promise<CustomizeDoctorSurface
|
|
|
1153
1279
|
trust: TRUST_BY_KIND["plugin-bundle"],
|
|
1154
1280
|
restartRequired: true,
|
|
1155
1281
|
precedence: { priority: 0 },
|
|
1282
|
+
functionHooks,
|
|
1156
1283
|
};
|
|
1157
1284
|
if (!entry.enabled) {
|
|
1158
1285
|
items.push(
|
|
@@ -1166,7 +1293,6 @@ async function collectPluginBundles(cwd: string): Promise<CustomizeDoctorSurface
|
|
|
1166
1293
|
);
|
|
1167
1294
|
continue;
|
|
1168
1295
|
}
|
|
1169
|
-
const surfaces = observability.surfaces.filter(s => s.plugin === entry.name && s.scope === entry.scope);
|
|
1170
1296
|
const quarantined = surfaces.filter(s => s.status === "quarantined");
|
|
1171
1297
|
if (quarantined.length > 0) {
|
|
1172
1298
|
const codes = Array.from(new Set(quarantined.map(s => s.quarantineCode ?? "unknown"))).join(", ");
|
|
@@ -1574,6 +1700,23 @@ export function renderCustomizeDoctorText(report: CustomizeDoctorReport): string
|
|
|
1574
1700
|
lines.push(` reason: ${item.reason} — ${item.detail}`);
|
|
1575
1701
|
lines.push(` source: ${item.path}`);
|
|
1576
1702
|
if (item.quarantineCode) lines.push(` quarantine code: ${item.quarantineCode}`);
|
|
1703
|
+
for (const hook of item.functionHooks ?? []) {
|
|
1704
|
+
lines.push(
|
|
1705
|
+
` function hook[${hook.order}]: ${hook.extensionId} event=${hook.event}${hook.target ? ` target=${hook.target}` : ""} status=${hook.status}`,
|
|
1706
|
+
);
|
|
1707
|
+
lines.push(` provenance: scope=${hook.scope} plugin=${hook.plugin} path=${hook.relativePath}`);
|
|
1708
|
+
lines.push(
|
|
1709
|
+
` grants: requested=${hook.requestedCapabilities.join(",") || "none"} effective=${hook.effectiveCapabilities.join(",") || "none"} attenuate=${hook.attenuateDownstream.join(",") || "none"}`,
|
|
1710
|
+
);
|
|
1711
|
+
if (hook.networkDestinations.length > 0)
|
|
1712
|
+
lines.push(` network destinations: ${hook.networkDestinations.join(",")}`);
|
|
1713
|
+
if (hook.filesystemRoots.length > 0)
|
|
1714
|
+
lines.push(` filesystem roots: ${hook.filesystemRoots.join(",")}`);
|
|
1715
|
+
if (hook.capabilityHash) lines.push(` capability hash: ${hook.capabilityHash}`);
|
|
1716
|
+
if (hook.implementationHash) lines.push(` implementation hash: ${hook.implementationHash}`);
|
|
1717
|
+
if (hook.quarantineCode) lines.push(` quarantine code: ${hook.quarantineCode}`);
|
|
1718
|
+
lines.push(` remediation: ${hook.remediation}`);
|
|
1719
|
+
}
|
|
1577
1720
|
for (const fix of item.remediation) lines.push(` fix: ${fix}`);
|
|
1578
1721
|
lines.push(` trust: ${item.trust}`);
|
|
1579
1722
|
lines.push(` restart required: ${item.restartRequired ? "yes (new session)" : "no"}`);
|
package/src/cli/root-flags.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { THINKING_EFFORTS } from "@gajae-code/ai/core";
|
|
1
2
|
import { type FlagDescriptor, Flags } from "@gajae-code/utils/cli";
|
|
2
3
|
|
|
3
|
-
const
|
|
4
|
+
export const ROOT_THINKING_LEVELS = ["off", ...THINKING_EFFORTS] as const;
|
|
5
|
+
export type RootThinkingLevel = (typeof ROOT_THINKING_LEVELS)[number];
|
|
4
6
|
|
|
5
7
|
/** Public launch flags shared by root help, completion, and the launch command. */
|
|
6
8
|
export const ROOT_LAUNCH_FLAGS = {
|
|
@@ -63,8 +65,8 @@ export const ROOT_LAUNCH_FLAGS = {
|
|
|
63
65
|
tmux: Flags.boolean({ description: "Launch interactive startup inside tmux" }),
|
|
64
66
|
tools: Flags.string({ description: "Comma-separated list of tools to enable (default: all)" }),
|
|
65
67
|
thinking: Flags.string({
|
|
66
|
-
description: `Set thinking level: ${
|
|
67
|
-
options:
|
|
68
|
+
description: `Set thinking level: ${ROOT_THINKING_LEVELS.join(", ")}`,
|
|
69
|
+
options: ROOT_THINKING_LEVELS,
|
|
68
70
|
}),
|
|
69
71
|
"no-rules": Flags.boolean({ description: "Disable rules discovery and loading" }),
|
|
70
72
|
export: Flags.string({ description: "Export session file to HTML and exit" }),
|
package/src/cli.ts
CHANGED
|
@@ -10,6 +10,15 @@ import { APP_NAME, formatBunRuntimeError, MIN_BUN_VERSION, VERSION } from "@gaja
|
|
|
10
10
|
import { runFixtureReport } from "./cli/fixture-report";
|
|
11
11
|
import { ROOT_LAUNCH_FLAGS } from "./cli/root-flags";
|
|
12
12
|
import QuickLane from "./commands/quick-lane";
|
|
13
|
+
import { runBashShellGuardian } from "./exec/bash-shell-guardian";
|
|
14
|
+
import { runBashShellSupervisor } from "./exec/bash-shell-supervisor";
|
|
15
|
+
import { runBashShellWorker } from "./exec/bash-shell-worker";
|
|
16
|
+
import {
|
|
17
|
+
BASH_SHELL_RUNTIME_ARG,
|
|
18
|
+
BASH_SHELL_SUPERVISOR_ARG,
|
|
19
|
+
BASH_SHELL_WORKER_ARG,
|
|
20
|
+
} from "./exec/bash-shell-worker-protocol";
|
|
21
|
+
import { smokeTestIsolatedShell } from "./exec/isolated-shell";
|
|
13
22
|
import { smokeTestTabWorker } from "./tools/browser/tab-worker-smoke";
|
|
14
23
|
|
|
15
24
|
if (Bun.semver.order(Bun.version, MIN_BUN_VERSION) < 0) {
|
|
@@ -340,6 +349,7 @@ async function runSmokeTest(): Promise<void> {
|
|
|
340
349
|
const { runNativeSmokeTest } = await import("./cli/native-smoke");
|
|
341
350
|
await runNativeSmokeTest();
|
|
342
351
|
await smokeTestTabWorker();
|
|
352
|
+
await smokeTestIsolatedShell();
|
|
343
353
|
process.stdout.write("smoke-test: ok\n");
|
|
344
354
|
}
|
|
345
355
|
|
|
@@ -392,6 +402,18 @@ export function routeRootArgv(argv: readonly string[]): string[] {
|
|
|
392
402
|
|
|
393
403
|
/** Run the CLI with the given argv (no `process.argv` prefix). */
|
|
394
404
|
export async function runCli(argv: string[]): Promise<void> {
|
|
405
|
+
if (argv.length === 1 && argv[0] === BASH_SHELL_WORKER_ARG) {
|
|
406
|
+
await runBashShellGuardian();
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
if (argv.length === 1 && argv[0] === BASH_SHELL_SUPERVISOR_ARG) {
|
|
410
|
+
await runBashShellSupervisor();
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
if (argv.length === 1 && argv[0] === BASH_SHELL_RUNTIME_ARG) {
|
|
414
|
+
await runBashShellWorker();
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
395
417
|
// macOS malloc-env launch boundary. Re-exec once with a scrubbed environment
|
|
396
418
|
// BEFORE any fast path or subprocess spawn, so the startup env snapshot Bun hands
|
|
397
419
|
// to every child lane (Bun.spawn defaults, node:child_process, native PTY, tmux
|
package/src/commands/sdk.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { initTheme } from "../modes/theme/theme";
|
|
|
13
13
|
import { ACP_MCP_REQUEST_TIMEOUT_MS, ACP_MCP_STARTUP_HEADROOM_MS } from "../sdk/acp/mcp";
|
|
14
14
|
import { Broker } from "../sdk/broker/broker";
|
|
15
15
|
import { readBrokerDiscovery } from "../sdk/broker/discovery";
|
|
16
|
+
import { reconcileBrokerGenerationForStartup, withBrokerStartupLock } from "../sdk/broker/ensure";
|
|
16
17
|
import { completeBrokerProcess } from "../sdk/broker/internal";
|
|
17
18
|
import {
|
|
18
19
|
type LifecycleTranscriptEvidence,
|
|
@@ -1086,59 +1087,101 @@ export default class Sdk extends Command {
|
|
|
1086
1087
|
await runSessionHost();
|
|
1087
1088
|
return;
|
|
1088
1089
|
}
|
|
1089
|
-
const agentDir = internal.agentDir;
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1090
|
+
const agentDir = path.resolve(internal.agentDir);
|
|
1091
|
+
let broker: Broker | undefined;
|
|
1092
|
+
try {
|
|
1093
|
+
broker = await withBrokerStartupLock(agentDir, async deadline => {
|
|
1094
|
+
const remainingMs = Math.max(1, deadline - Date.now());
|
|
1095
|
+
const testWatchdogMs = Number(process.env.GJC_SDK_TEST_BROKER_STARTUP_WATCHDOG_MS ?? 0);
|
|
1096
|
+
const watchdogMs =
|
|
1097
|
+
Number.isSafeInteger(testWatchdogMs) && testWatchdogMs > 0 && testWatchdogMs <= remainingMs
|
|
1098
|
+
? testWatchdogMs
|
|
1099
|
+
: remainingMs;
|
|
1100
|
+
const startupWatchdog = setTimeout(() => {
|
|
1101
|
+
process.stderr.write(`SDK broker startup exceeded its ${watchdogMs}ms fence deadline.\n`);
|
|
1102
|
+
process.exit(1);
|
|
1103
|
+
}, watchdogMs);
|
|
1097
1104
|
try {
|
|
1098
|
-
|
|
1099
|
-
|
|
1105
|
+
if (await reconcileBrokerGenerationForStartup({ agentDir }, deadline)) return undefined;
|
|
1106
|
+
if (process.env.GJC_SDK_TEST_BROKER_STARTUP_STALL === "1") {
|
|
1107
|
+
const stalled = Promise.withResolvers<void>();
|
|
1108
|
+
await stalled.promise;
|
|
1109
|
+
}
|
|
1110
|
+
const startupDelayMs = Number(process.env.GJC_SDK_TEST_BROKER_STARTUP_DELAY_MS ?? 0);
|
|
1111
|
+
if (Number.isSafeInteger(startupDelayMs) && startupDelayMs > 0 && startupDelayMs <= 10_000)
|
|
1112
|
+
await Bun.sleep(startupDelayMs);
|
|
1113
|
+
const candidate = new Broker({
|
|
1114
|
+
agentDir,
|
|
1115
|
+
masterOrphanGraceMs: (await Settings.loadForScope({ cwd: process.cwd(), agentDir })).get(
|
|
1116
|
+
"sdk.masterOrphanGraceMs",
|
|
1117
|
+
),
|
|
1118
|
+
resolveDirectoryMigration: async cwd => {
|
|
1119
|
+
const settings = await Settings.loadForScope({ cwd, agentDir });
|
|
1120
|
+
try {
|
|
1121
|
+
const policy = settings.get("session.directoryMigration");
|
|
1122
|
+
return policy === "disabled" ? "disabled" : "copy-retain";
|
|
1123
|
+
} finally {
|
|
1124
|
+
await settings.close();
|
|
1125
|
+
}
|
|
1126
|
+
},
|
|
1127
|
+
});
|
|
1128
|
+
broker = candidate;
|
|
1129
|
+
await candidate.start();
|
|
1130
|
+
return candidate;
|
|
1100
1131
|
} finally {
|
|
1101
|
-
|
|
1132
|
+
clearTimeout(startupWatchdog);
|
|
1102
1133
|
}
|
|
1103
|
-
}
|
|
1104
|
-
});
|
|
1105
|
-
try {
|
|
1106
|
-
await broker.start();
|
|
1134
|
+
});
|
|
1107
1135
|
} catch (error) {
|
|
1136
|
+
if (broker) {
|
|
1137
|
+
try {
|
|
1138
|
+
await broker.stop();
|
|
1139
|
+
} catch {
|
|
1140
|
+
// Preserve the startup/fence failure that made this bootstrap unusable.
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1108
1143
|
// This process spawns detached with stdio ignored (see ensure.ts), so the
|
|
1109
1144
|
// durable marker is the only channel the caller has to see why start()
|
|
1110
1145
|
// failed instead of a bare exit code (#3963).
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1146
|
+
const incarnation = processIncarnation(process.pid);
|
|
1147
|
+
if (incarnation)
|
|
1148
|
+
await writeBrokerStartupFailureMarker(agentDir, {
|
|
1149
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
1150
|
+
exitCode: 1,
|
|
1151
|
+
signal: null,
|
|
1152
|
+
pid: process.pid,
|
|
1153
|
+
incarnation,
|
|
1154
|
+
});
|
|
1117
1155
|
throw error;
|
|
1118
1156
|
}
|
|
1119
|
-
if (!broker
|
|
1157
|
+
if (!broker) return;
|
|
1158
|
+
const runningBroker = broker;
|
|
1159
|
+
if (!runningBroker.ownsDiscovery) {
|
|
1120
1160
|
// Another broker owns discovery; this process exits cleanly (code 0) as
|
|
1121
1161
|
// the race loser. Record why so a caller polling for a winner that never
|
|
1122
1162
|
// appears can diagnose the loss instead of seeing only a bare exit 0.
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1163
|
+
const incarnation = processIncarnation(process.pid);
|
|
1164
|
+
if (incarnation)
|
|
1165
|
+
await writeBrokerStartupFailureMarker(agentDir, {
|
|
1166
|
+
reason: "Another broker owns the lock/discovery; this broker exited as the race loser.",
|
|
1167
|
+
exitCode: 0,
|
|
1168
|
+
signal: null,
|
|
1169
|
+
pid: process.pid,
|
|
1170
|
+
incarnation,
|
|
1171
|
+
});
|
|
1129
1172
|
return;
|
|
1130
1173
|
}
|
|
1131
1174
|
// A live broker must not keep advertising sessions whose host process is
|
|
1132
1175
|
// gone; the sweep is the broker-side half of the host reaping bound.
|
|
1133
|
-
const stopSweep = startBrokerDeadRegistrationSweep(
|
|
1176
|
+
const stopSweep = startBrokerDeadRegistrationSweep(runningBroker);
|
|
1134
1177
|
const stop = () => {
|
|
1135
1178
|
stopSweep();
|
|
1136
|
-
void
|
|
1179
|
+
void runningBroker.stop();
|
|
1137
1180
|
};
|
|
1138
1181
|
process.once("SIGTERM", stop);
|
|
1139
1182
|
process.once("SIGINT", stop);
|
|
1140
1183
|
try {
|
|
1141
|
-
await completeBrokerProcess(
|
|
1184
|
+
await completeBrokerProcess(runningBroker);
|
|
1142
1185
|
} finally {
|
|
1143
1186
|
stopSweep();
|
|
1144
1187
|
}
|
|
@@ -359,6 +359,7 @@ export const TIER_MAP_SKIP_LIST = {
|
|
|
359
359
|
"nvidia/poolside/laguna-xs-2.1": { rationale: "post-rebase catalog addition from dev; not yet curated" },
|
|
360
360
|
"nvidia/thinkingmachines/inkling": { rationale: "post-rebase catalog addition from dev; not yet curated" },
|
|
361
361
|
"nvidia/upstage/solar-10.7b-instruct": { rationale: "post-rebase catalog addition from dev; not yet curated" },
|
|
362
|
+
"openai-codex/gpt-6-astra": { rationale: "GPT-6 Astra catalog addition (2026-09-03 release); not yet curated" },
|
|
362
363
|
"openai-codex/gpt-daybreak-blue-latest": { rationale: "post-rebase catalog addition from dev; not yet curated" },
|
|
363
364
|
"opencode-go/deepseek-v4-flash-vision-exp": {
|
|
364
365
|
rationale: "post-rebase catalog addition from dev; not yet curated",
|
|
@@ -17,7 +17,12 @@ import type {
|
|
|
17
17
|
} from "../gjc-runtime/gc-runtime";
|
|
18
18
|
import { gcPidStatusLabel } from "../gjc-runtime/gc-runtime";
|
|
19
19
|
import { resolveReceiptSpoolDir } from "../harness-control-plane/receipt-spool";
|
|
20
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
fileLockStagingOwnerPid,
|
|
22
|
+
inspectFileLockStagingDir,
|
|
23
|
+
readFileLockObservationForGc,
|
|
24
|
+
removeFileLockDirForGc,
|
|
25
|
+
} from "./file-lock";
|
|
21
26
|
|
|
22
27
|
const MAX_WALK_DEPTH = 6;
|
|
23
28
|
/** Default per-root walk budget. Truncation is a warning, not a hard error. */
|
|
@@ -67,7 +72,27 @@ function keptMalformedRecord(lockDir: string): GcRecord {
|
|
|
67
72
|
};
|
|
68
73
|
}
|
|
69
74
|
|
|
75
|
+
function stagingOwnerStatus(ctx: GcContext, pid: number): "alive" | "dead" | "unknown" {
|
|
76
|
+
const status = gcPidStatusLabel(ctx.probe(pid));
|
|
77
|
+
return status === "eperm" ? "unknown" : status;
|
|
78
|
+
}
|
|
79
|
+
|
|
70
80
|
async function collectLockRecord(lockDir: string, ctx: GcContext): Promise<GcRecord> {
|
|
81
|
+
if (fileLockStagingOwnerPid(path.basename(lockDir)) !== null) {
|
|
82
|
+
const staging = await inspectFileLockStagingDir(lockDir, pid => stagingOwnerStatus(ctx, pid));
|
|
83
|
+
return {
|
|
84
|
+
store: "file_locks",
|
|
85
|
+
id: lockDir,
|
|
86
|
+
path: lockDir,
|
|
87
|
+
pid: staging.pid,
|
|
88
|
+
pid_status: staging.status,
|
|
89
|
+
status: "file_lock_staging_orphan",
|
|
90
|
+
stale: staging.status === "dead",
|
|
91
|
+
removable: staging.status === "dead",
|
|
92
|
+
action: "none",
|
|
93
|
+
reason: staging.reason,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
71
96
|
const observation = await readFileLockObservationForGc(lockDir);
|
|
72
97
|
const info = observation?.info;
|
|
73
98
|
if (!info) return keptMalformedRecord(lockDir);
|
|
@@ -131,7 +156,7 @@ async function walkForLockDirs(
|
|
|
131
156
|
state.entries++;
|
|
132
157
|
if (!stat.isDirectory() || stat.isSymbolicLink()) return;
|
|
133
158
|
|
|
134
|
-
if (path.basename(dir).endsWith(".lock")) {
|
|
159
|
+
if (path.basename(dir).endsWith(".lock") || fileLockStagingOwnerPid(path.basename(dir)) !== null) {
|
|
135
160
|
lockDirs.add(dir);
|
|
136
161
|
return;
|
|
137
162
|
}
|
|
@@ -152,6 +177,11 @@ async function walkForLockDirs(
|
|
|
152
177
|
state.truncated = true;
|
|
153
178
|
return;
|
|
154
179
|
}
|
|
180
|
+
// Session index locks live directly in sessions/, but session payload trees remain pruned.
|
|
181
|
+
if (entry === "sessions") {
|
|
182
|
+
await walkForLockDirs(path.join(dir, entry), MAX_WALK_DEPTH - 1, state, lockDirs, errors, maxWalkEntries);
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
155
185
|
if (PRUNED_DIR_NAMES.has(entry)) continue;
|
|
156
186
|
await walkForLockDirs(path.join(dir, entry), depth + 1, state, lockDirs, errors, maxWalkEntries);
|
|
157
187
|
}
|
|
@@ -204,6 +234,14 @@ export const fileLocksGcAdapter: GcStoreAdapter = {
|
|
|
204
234
|
},
|
|
205
235
|
async prune(record: GcRecord, ctx: GcContext): Promise<GcPruneOutcome> {
|
|
206
236
|
const lockDir = record.path ?? record.id;
|
|
237
|
+
if (fileLockStagingOwnerPid(path.basename(lockDir)) !== null) {
|
|
238
|
+
try {
|
|
239
|
+
const staging = await inspectFileLockStagingDir(lockDir, pid => stagingOwnerStatus(ctx, pid), true);
|
|
240
|
+
return staging.removed ? { removed: true } : { removed: false, skipped: staging.reason };
|
|
241
|
+
} catch (error) {
|
|
242
|
+
return { removed: false, error: errorMessage(error) };
|
|
243
|
+
}
|
|
244
|
+
}
|
|
207
245
|
const observation = await readFileLockObservationForGc(lockDir);
|
|
208
246
|
const info = observation?.info;
|
|
209
247
|
if (!info) return { removed: false, skipped: "lock_no_longer_dead_or_missing" };
|