@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
|
@@ -62,6 +62,8 @@ export interface CreateAgentSessionOptions {
|
|
|
62
62
|
cwd?: string;
|
|
63
63
|
/** Global config directory. Default: ~/.gjc/agent */
|
|
64
64
|
agentDir?: string;
|
|
65
|
+
/** Resolver-owned classification for `agentDir`; required when authority must survive HOME/config refreshes. */
|
|
66
|
+
profileAuthority?: "default" | "custom";
|
|
65
67
|
/** Spawns to allow. Default: "*" */
|
|
66
68
|
spawns?: string;
|
|
67
69
|
/** Auth storage for credentials. Default: discoverAuthStorage(agentDir) */
|
|
@@ -336,7 +338,7 @@ export declare function discoverSkills(_cwd?: string, _agentDir?: string, _setti
|
|
|
336
338
|
* Discover context files (AGENTS.md) walking up from cwd.
|
|
337
339
|
* Returns files sorted by depth (farther from cwd first, so closer files appear last/more prominent).
|
|
338
340
|
*/
|
|
339
|
-
export declare function discoverContextFiles(cwd?: string,
|
|
341
|
+
export declare function discoverContextFiles(cwd?: string, agentDir?: string): Promise<Array<{
|
|
340
342
|
path: string;
|
|
341
343
|
content: string;
|
|
342
344
|
depth?: number;
|
|
@@ -361,6 +363,8 @@ export interface BuildSystemPromptOptions {
|
|
|
361
363
|
content: string;
|
|
362
364
|
}>;
|
|
363
365
|
cwd?: string;
|
|
366
|
+
agentDir?: string;
|
|
367
|
+
profileAuthority?: "default" | "custom";
|
|
364
368
|
appendPrompt?: string;
|
|
365
369
|
repeatToolDescriptions?: boolean;
|
|
366
370
|
}
|
|
@@ -826,6 +826,8 @@ export declare class AgentSession {
|
|
|
826
826
|
awaitSessionSettlement(): Promise<void>;
|
|
827
827
|
/** Test seam: hold prompt admission while bypassing a pending selection fence. */
|
|
828
828
|
runWithPromptAdmissionForTests(body: () => Promise<void>): Promise<void>;
|
|
829
|
+
/** Test seam: await all currently admitted coordinator sidecar writes. */
|
|
830
|
+
awaitCoordinatorRuntimeStatePersistenceForTests(): Promise<void>;
|
|
829
831
|
queueCoordinatorRuntimeStatePersistForTests(event: AgentSessionEvent, gate: Promise<void>): Promise<void>;
|
|
830
832
|
parkAgentEndForCoordinatorPersistForTests(event: Extract<AgentSessionEvent, {
|
|
831
833
|
type: "agent_end";
|
|
@@ -95,5 +95,20 @@ export declare function cappedExponentialWithFullJitter(baseDelayMs: number, max
|
|
|
95
95
|
* A missing, NaN, or infinite hint collapses to "no usable hint".
|
|
96
96
|
*/
|
|
97
97
|
export declare function compactionRetryDelay(baseDelayMs: number, maxDelayMs: number, attempt: number, retryAfterMs: number | undefined): number;
|
|
98
|
+
export interface CompactionCandidateFailure {
|
|
99
|
+
readonly model: string;
|
|
100
|
+
readonly message: string;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Error for an auto-compaction run whose every candidate failed.
|
|
104
|
+
*
|
|
105
|
+
* The candidate chain starts at the session model and ends on a same-provider
|
|
106
|
+
* largest-context fallback, so surfacing only the final error named a model
|
|
107
|
+
* the user never chose and hid that their own model had already failed the
|
|
108
|
+
* same way. The message leads with the first failure (the one the user can act
|
|
109
|
+
* on), then lists every candidate that was tried with its own error. `cause`
|
|
110
|
+
* is the final error so callers that classify by type keep the same object.
|
|
111
|
+
*/
|
|
112
|
+
export declare function describeCompactionCandidateFailures(failures: readonly CompactionCandidateFailure[], lastError: unknown): Error;
|
|
98
113
|
/** Retry-After is intentionally uncapped. */
|
|
99
114
|
export declare function effectiveFallbackDelay(baseDelayMs: number, maxDelayMs: number, attemptK: number, retryAfterMs: number | undefined, random?: () => number): number;
|
|
@@ -6,6 +6,13 @@ export declare const MANAGED_ARTIFACT_MAX_FILES = 50000;
|
|
|
6
6
|
export declare const MANAGED_ARTIFACT_MAX_FILE_BYTES: number;
|
|
7
7
|
export declare const MANAGED_ARTIFACT_MAX_TOTAL_BYTES: number;
|
|
8
8
|
export declare const MANAGED_ARTIFACT_COPY_BATCH_SIZE = 256;
|
|
9
|
+
/** A pre-mutation append fence rejection: no bytes from this append were written. */
|
|
10
|
+
export declare class ManagedAppendIdentityMismatchError extends Error {
|
|
11
|
+
readonly code = "managed_append_identity_mismatch";
|
|
12
|
+
readonly relativePath: string;
|
|
13
|
+
readonly operatorMessage = "Session was resumed by another process; this resume did not run. Retry, or resume a different session.";
|
|
14
|
+
constructor(relativePath: string);
|
|
15
|
+
}
|
|
9
16
|
export declare class ManagedPublishError extends Error {
|
|
10
17
|
readonly classification: "destination_conflict" | "atomic_unavailable" | "invalid_request" | "durability_not_provable" | "identity_mismatch" | "io_error" | "durability_failed";
|
|
11
18
|
readonly diagnostic: string;
|
|
@@ -9,7 +9,7 @@ import type { ManagedLegacyLocalMigrationSource } from "../internal-urls/local-p
|
|
|
9
9
|
import { ArtifactManager } from "./artifacts";
|
|
10
10
|
import { type BlobPutResult, BlobStore } from "./blob-store";
|
|
11
11
|
import { type ManagedMigrationPolicy } from "./internal/managed-session-scope";
|
|
12
|
-
import { type ManagedBoundedAppendExpectation, type ManagedDirectoryRoot, type ManagedFileIdentity, ManagedSessionDescendantStore } from "./internal/managed-session-storage";
|
|
12
|
+
import { ManagedAppendIdentityMismatchError, type ManagedBoundedAppendExpectation, type ManagedDirectoryRoot, type ManagedFileIdentity, ManagedSessionDescendantStore } from "./internal/managed-session-storage";
|
|
13
13
|
import { type BaseAnchor, BoundedLabelsPinsStore, type CommittedTail, type DescriptorSnapshot, type DictionaryPartitionCommit, FixedCacheAccount, type MetadataDeltaValue, type ParentBucketCommit, type ReducerState, type ReopenClassification, SessionMemoryAccountant } from "./internal/session-memory-sidecar";
|
|
14
14
|
import { type MemoryGuardCreateCheckpointInput, type MemoryGuardParticipantIngressLease, type MemoryGuardRestoreInput, type MemoryGuardRestoreResult, type MemoryGuardSessionManagerCheckpointV1 } from "./memory-guard-checkpoint-participant";
|
|
15
15
|
import { type BashExecutionMessage, type CustomMessage, type FileMentionMessage, type HookMessage, type PythonExecutionMessage } from "./messages";
|
|
@@ -1291,6 +1291,8 @@ export declare class SessionManager {
|
|
|
1291
1291
|
}) => Promise<fs.BigIntStats>;
|
|
1292
1292
|
};
|
|
1293
1293
|
}): Promise<void>;
|
|
1294
|
+
/** Ownership loss remains observable even when an agent event listener aborts the turn. */
|
|
1295
|
+
getAppendIdentityMismatch(): ManagedAppendIdentityMismatchError | undefined;
|
|
1294
1296
|
isPersisted(): boolean;
|
|
1295
1297
|
stageDefaultModelSelection(model: string, thinkingLevel: string | undefined, options?: {
|
|
1296
1298
|
readonly appendThinkingLevel: boolean;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export { resolvePaseoHome } from "./setup-deps";
|
|
2
1
|
export type PaseoDaemonTarget = {
|
|
3
2
|
readonly kind: "ipc";
|
|
4
3
|
readonly socketPath: string;
|
|
@@ -40,6 +39,8 @@ export interface PaseoAnnounceDependencies {
|
|
|
40
39
|
readonly providerKey: string;
|
|
41
40
|
readonly cwd: string;
|
|
42
41
|
readonly sessionId: string;
|
|
42
|
+
readonly daemonTarget: PaseoDaemonTarget;
|
|
43
|
+
readonly daemonHost: string;
|
|
43
44
|
readonly signal?: AbortSignal;
|
|
44
45
|
}): Promise<PaseoAnnounceOutcome>;
|
|
45
46
|
}
|
|
@@ -64,7 +65,7 @@ export declare function parseDaemonListen(raw: string): PaseoDaemonTarget | unde
|
|
|
64
65
|
* environment override, then the running daemon's own pid file, then the
|
|
65
66
|
* configured listener, then Paseo's default.
|
|
66
67
|
*/
|
|
67
|
-
export declare function resolveDaemonTarget(config: unknown, deps: Pick<PaseoAnnounceDependencies, "env" | "paseoHome" | "readJson">): Promise<PaseoDaemonTarget>;
|
|
68
|
+
export declare function resolveDaemonTarget(config: unknown, deps: Pick<PaseoAnnounceDependencies, "env" | "paseoHome" | "readJson">): Promise<PaseoDaemonTarget | undefined>;
|
|
68
69
|
/**
|
|
69
70
|
* Turn a non-zero `paseo import` into an outcome.
|
|
70
71
|
*
|
|
@@ -107,5 +108,5 @@ export declare function startPaseoAnnouncement(input: {
|
|
|
107
108
|
isEnabled?: () => boolean;
|
|
108
109
|
onOutcome?: (outcome: PaseoAnnounceOutcome) => void;
|
|
109
110
|
}, deps: PaseoAnnounceDependencies): PaseoAnnouncementHandle;
|
|
110
|
-
export declare function
|
|
111
|
+
export declare function sessionListContainsLiveSession(sessions: readonly unknown[], sessionId: string, cwd: string): boolean;
|
|
111
112
|
export declare function createDefaultPaseoAnnounceDependencies(agentDir: string, env?: NodeJS.ProcessEnv): PaseoAnnounceDependencies;
|
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
/** Native-free canonical GJC workflow skill identifiers. */
|
|
2
2
|
export declare const CANONICAL_GJC_WORKFLOW_SKILLS: readonly ["deep-interview", "ralplan", "ultragoal", "autoresearch"];
|
|
3
3
|
export type CanonicalGjcWorkflowSkill = (typeof CANONICAL_GJC_WORKFLOW_SKILLS)[number];
|
|
4
|
+
/** Case-insensitive, Win32-path-equivalent key used for skill collision checks. */
|
|
5
|
+
export declare function getSkillFilesystemIdentity(name: string): string;
|
|
6
|
+
/** Whether a name resolves to a bundled workflow under portable filesystem semantics. */
|
|
7
|
+
export declare function isCanonicalGjcWorkflowSkillFilesystemAlias(name: string): boolean;
|
|
@@ -15,6 +15,10 @@ export declare function resolvePromptInput(input: string | undefined, descriptio
|
|
|
15
15
|
export interface LoadContextFilesOptions {
|
|
16
16
|
/** Working directory to start walking up from. Default: getProjectDir() */
|
|
17
17
|
cwd?: string;
|
|
18
|
+
/** Agent directory backing native user-scope context and system prompt files. */
|
|
19
|
+
agentDir?: string;
|
|
20
|
+
/** Resolver-owned classification for `agentDir`; preserve it across HOME/config refreshes. */
|
|
21
|
+
profileAuthority?: "default" | "custom";
|
|
18
22
|
}
|
|
19
23
|
export interface ProjectContextFilesResult {
|
|
20
24
|
contextFiles: Array<{
|
|
@@ -70,6 +74,10 @@ export interface BuildSystemPromptOptions {
|
|
|
70
74
|
skillsSettings?: SkillsSettings;
|
|
71
75
|
/** Working directory. Default: getProjectDir() */
|
|
72
76
|
cwd?: string;
|
|
77
|
+
/** Agent directory backing native user-scope prompt discovery. */
|
|
78
|
+
agentDir?: string;
|
|
79
|
+
/** Resolver-owned classification for `agentDir`; preserve it across HOME/config refreshes. */
|
|
80
|
+
profileAuthority?: "default" | "custom";
|
|
73
81
|
/** Pre-loaded context files (skips discovery if provided). */
|
|
74
82
|
contextFiles?: Array<{
|
|
75
83
|
path: string;
|
|
@@ -95,6 +95,9 @@ export interface ExecutorOptions {
|
|
|
95
95
|
authStorage?: AuthStorage;
|
|
96
96
|
modelRegistry?: ModelRegistry;
|
|
97
97
|
settings?: Settings;
|
|
98
|
+
/** Parent session's selected agent directory and immutable resolver-owned authority. */
|
|
99
|
+
agentDir?: string;
|
|
100
|
+
profileAuthority?: "default" | "custom";
|
|
98
101
|
/** Parent session's registry; shared by child sessions for IRC routing and roster visibility. */
|
|
99
102
|
agentRegistry?: AgentRegistry;
|
|
100
103
|
/**
|
|
@@ -19,6 +19,7 @@ export declare const STEER_FOLD_GRACE_MS = 2000;
|
|
|
19
19
|
/** Model-facing line appended to a steer-folded background-start result. */
|
|
20
20
|
export declare function steerFoldReasonLine(jobId: string): string;
|
|
21
21
|
export type BashOriginalArtifactSaveResult = BashArtifactSaveResult;
|
|
22
|
+
export declare function suffixPrefixOverlap(source: string, target: string): number;
|
|
22
23
|
export declare function saveBashOriginalArtifactForTests(session: ToolSession, originalText: string, onResult?: (result: BashOriginalArtifactSaveResult) => void): Promise<string | undefined>;
|
|
23
24
|
declare const bashSchemaBase: z.ZodObject<{
|
|
24
25
|
command: z.ZodString;
|
|
@@ -78,9 +78,10 @@ export interface CacheLookupOptions<T> {
|
|
|
78
78
|
* must bypass persistent cache reads/writes.
|
|
79
79
|
*/
|
|
80
80
|
authKey?: string | null;
|
|
81
|
-
fetchFresh: () => Promise<FreshResult<T>>;
|
|
81
|
+
fetchFresh: (signal?: AbortSignal) => Promise<FreshResult<T>>;
|
|
82
82
|
settings?: Settings | undefined;
|
|
83
83
|
now?: number;
|
|
84
|
+
signal?: AbortSignal;
|
|
84
85
|
}
|
|
85
86
|
export type CacheStatus = "miss" | "fresh" | "stale" | "disabled";
|
|
86
87
|
export interface CacheLookupResult<T> {
|
|
@@ -152,6 +152,8 @@ export interface ToolSession {
|
|
|
152
152
|
* Runtime discovery only; never threaded into capability loading.
|
|
153
153
|
*/
|
|
154
154
|
home?: string;
|
|
155
|
+
/** Resolver-owned classification for the session's selected agent directory. */
|
|
156
|
+
profileAuthority?: "default" | "custom";
|
|
155
157
|
skills?: Skill[];
|
|
156
158
|
/** Currently executing skill prompt, when this tool session is inside one. */
|
|
157
159
|
getActiveSkillState?: () => Pick<SkillActiveEntry, "skill" | "session_id"> | undefined;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@gajae-code/coding-agent",
|
|
4
|
-
"version": "0.16.
|
|
4
|
+
"version": "0.16.6",
|
|
5
5
|
"description": "Gajae Code CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://gajae-code.com",
|
|
7
7
|
"author": "Yeachan-Heo and Gajae Code Contributors",
|
|
@@ -56,12 +56,12 @@
|
|
|
56
56
|
"@agentclientprotocol/sdk": "1.3.0",
|
|
57
57
|
"@babel/parser": "^7.29.3",
|
|
58
58
|
"@mozilla/readability": "^0.6.0",
|
|
59
|
-
"@gajae-code/stats": "0.16.
|
|
60
|
-
"@gajae-code/agent-core": "0.16.
|
|
61
|
-
"@gajae-code/ai": "0.16.
|
|
62
|
-
"@gajae-code/natives": "0.16.
|
|
63
|
-
"@gajae-code/tui": "0.16.
|
|
64
|
-
"@gajae-code/utils": "0.16.
|
|
59
|
+
"@gajae-code/stats": "0.16.6",
|
|
60
|
+
"@gajae-code/agent-core": "0.16.6",
|
|
61
|
+
"@gajae-code/ai": "0.16.6",
|
|
62
|
+
"@gajae-code/natives": "0.16.6",
|
|
63
|
+
"@gajae-code/tui": "0.16.6",
|
|
64
|
+
"@gajae-code/utils": "0.16.6",
|
|
65
65
|
"@puppeteer/browsers": "^2.13.0",
|
|
66
66
|
"@types/turndown": "5.0.6",
|
|
67
67
|
"@xterm/headless": "^6.0.0",
|
|
@@ -130,6 +130,8 @@
|
|
|
130
130
|
"./session/session-manager-internal.js": null,
|
|
131
131
|
"./session/sdk-run-capability": null,
|
|
132
132
|
"./session/sdk-run-capability.js": null,
|
|
133
|
+
"./extensibility/extensions/function-hooks-internal": null,
|
|
134
|
+
"./extensibility/extensions/function-hooks-internal.js": null,
|
|
133
135
|
"./sdk": {
|
|
134
136
|
"types": "./dist/types/sdk/index.d.ts",
|
|
135
137
|
"import": "./src/sdk/index.ts"
|
|
@@ -115,6 +115,8 @@ const LOCKED_EXCLUSIONS: Readonly<Record<string, string>> = {
|
|
|
115
115
|
"agent_session:getPendingNextTurnMessagesForTests": "read-only test seam, not a user-facing SDK control seam",
|
|
116
116
|
"agent_session:queueCoordinatorRuntimeStatePersistForTests":
|
|
117
117
|
"test-only coordinator persistence ordering seam, not a user-facing SDK control seam",
|
|
118
|
+
"agent_session:awaitCoordinatorRuntimeStatePersistenceForTests":
|
|
119
|
+
"test-only coordinator persistence drain barrier, not a user-facing SDK control seam",
|
|
118
120
|
"agent_session:parkAgentEndForCoordinatorPersistForTests":
|
|
119
121
|
"test-only parked terminal persistence seam, not a user-facing SDK control seam",
|
|
120
122
|
"agent_session:flushParkedAgentEndForCoordinatorPersistForTests":
|
package/src/capability/index.ts
CHANGED
|
@@ -7,7 +7,14 @@
|
|
|
7
7
|
* - Loading items for a capability across all providers
|
|
8
8
|
*/
|
|
9
9
|
import * as path from "node:path";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
getAgentDir,
|
|
12
|
+
getAgentProfileAuthority,
|
|
13
|
+
getProjectDir,
|
|
14
|
+
getTrustedHomeDir,
|
|
15
|
+
logger,
|
|
16
|
+
normalizePathForComparison,
|
|
17
|
+
} from "@gajae-code/utils";
|
|
11
18
|
|
|
12
19
|
import type { Settings } from "../config/settings";
|
|
13
20
|
import { clearCache as clearFsCache, findRepoRoot, cacheStats as fsCacheStats, invalidate as invalidateFs } from "./fs";
|
|
@@ -243,8 +250,13 @@ export async function loadCapability<T>(capabilityId: string, options: LoadOptio
|
|
|
243
250
|
const cwd = options.cwd ?? getProjectDir();
|
|
244
251
|
const home = getTrustedHomeDir();
|
|
245
252
|
const userAgentDir = options.agentDir ? path.resolve(options.agentDir) : getAgentDir();
|
|
253
|
+
const profileAuthority =
|
|
254
|
+
options.profileAuthority ??
|
|
255
|
+
(options.agentDir && normalizePathForComparison(userAgentDir) !== normalizePathForComparison(getAgentDir())
|
|
256
|
+
? "custom"
|
|
257
|
+
: getAgentProfileAuthority());
|
|
246
258
|
const repoRoot = await findRepoRoot(cwd);
|
|
247
|
-
const ctx: LoadContext = { cwd, home, userAgentDir, repoRoot, settings: options.settings };
|
|
259
|
+
const ctx: LoadContext = { cwd, home, userAgentDir, profileAuthority, repoRoot, settings: options.settings };
|
|
248
260
|
const providers = filterProviders(capability, options);
|
|
249
261
|
|
|
250
262
|
return await loadImpl(capability, providers, ctx, options);
|
package/src/capability/types.ts
CHANGED
|
@@ -29,6 +29,8 @@ export interface LoadContext {
|
|
|
29
29
|
* produced. This includes MCP registrations and user-installed skills.
|
|
30
30
|
*/
|
|
31
31
|
userAgentDir?: string;
|
|
32
|
+
/** Resolver-owned classification for the selected user agent directory. */
|
|
33
|
+
profileAuthority?: "default" | "custom";
|
|
32
34
|
/** Git repository root (directory containing .git), or null if not in a repo */
|
|
33
35
|
repoRoot: string | null;
|
|
34
36
|
/** Owning session settings for provider policy decisions. */
|
|
@@ -89,6 +91,8 @@ export interface LoadOptions {
|
|
|
89
91
|
* process-wide one (`createAgentSession({ agentDir })`).
|
|
90
92
|
*/
|
|
91
93
|
agentDir?: string;
|
|
94
|
+
/** Resolver-owned classification for `agentDir`; preserve it across HOME/config refreshes. */
|
|
95
|
+
profileAuthority?: "default" | "custom";
|
|
92
96
|
/** Include items even if they fail validation. Default: false */
|
|
93
97
|
includeInvalid?: boolean;
|
|
94
98
|
/** Include items disabled via settings. Default: false */
|
|
@@ -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.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
|