@gajae-code/coding-agent 0.5.0 → 0.5.2
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 +36 -0
- package/README.md +1 -1
- package/dist/types/async/job-manager.d.ts +26 -0
- package/dist/types/cli/args.d.ts +1 -0
- package/dist/types/cli/list-models.d.ts +6 -0
- package/dist/types/cli/setup-cli.d.ts +8 -1
- package/dist/types/commands/gc.d.ts +26 -0
- package/dist/types/commands/setup.d.ts +7 -0
- package/dist/types/config/file-lock-gc.d.ts +5 -0
- package/dist/types/config/file-lock.d.ts +29 -0
- package/dist/types/config/model-registry.d.ts +4 -0
- package/dist/types/config/models-config-schema.d.ts +5 -0
- package/dist/types/config/settings-schema.d.ts +62 -0
- package/dist/types/coordinator/contract.d.ts +1 -1
- package/dist/types/defaults/gjc/extensions/grok-build/index.d.ts +1 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/index.d.ts +1 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/models/catalog.d.ts +25 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/payload/sanitize.d.ts +27 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/billing.d.ts +8 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/register.d.ts +5 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/stream.d.ts +10 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/usage.d.ts +2 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/shared/base-url.d.ts +2 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/shared/errors.d.ts +38 -0
- package/dist/types/defaults/gjc-grok-cli.d.ts +5 -0
- package/dist/types/extensibility/extensions/index.d.ts +1 -0
- package/dist/types/extensibility/extensions/prefix-command-bridge.d.ts +35 -0
- package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +103 -0
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +2 -0
- package/dist/types/gjc-runtime/deep-interview-state.d.ts +112 -0
- package/dist/types/gjc-runtime/gc-render.d.ts +6 -0
- package/dist/types/gjc-runtime/gc-runtime.d.ts +134 -0
- package/dist/types/gjc-runtime/ledger-event-renderer.d.ts +68 -0
- package/dist/types/gjc-runtime/state-writer.d.ts +64 -2
- package/dist/types/gjc-runtime/team-gc.d.ts +7 -0
- package/dist/types/gjc-runtime/team-runtime.d.ts +5 -0
- package/dist/types/gjc-runtime/tmux-common.d.ts +11 -0
- package/dist/types/gjc-runtime/tmux-gc.d.ts +7 -0
- package/dist/types/gjc-runtime/tmux-sessions.d.ts +13 -0
- package/dist/types/gjc-runtime/ultragoal-guard.d.ts +10 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +29 -0
- package/dist/types/harness-control-plane/gc-adapter.d.ts +3 -0
- package/dist/types/harness-control-plane/owner.d.ts +7 -0
- package/dist/types/harness-control-plane/storage.d.ts +20 -0
- package/dist/types/modes/components/hook-selector.d.ts +7 -1
- package/dist/types/modes/components/provider-onboarding-selector.d.ts +1 -1
- package/dist/types/modes/controllers/command-controller.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -1
- package/dist/types/modes/rpc/rpc-mode.d.ts +72 -2
- package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +13 -0
- package/dist/types/modes/shared/agent-wire/session-registry.d.ts +25 -0
- package/dist/types/modes/shared/agent-wire/unattended-action-policy.d.ts +2 -0
- package/dist/types/modes/shared/agent-wire/unattended-session.d.ts +10 -0
- package/dist/types/modes/theme/defaults/index.d.ts +302 -0
- package/dist/types/modes/theme/theme.d.ts +1 -0
- package/dist/types/modes/types.d.ts +1 -1
- package/dist/types/session/agent-session.d.ts +1 -1
- package/dist/types/session/blob-store.d.ts +39 -3
- package/dist/types/session/history-storage.d.ts +2 -2
- package/dist/types/session/session-manager.d.ts +10 -1
- package/dist/types/setup/credential-import.d.ts +79 -0
- package/dist/types/skill-state/workflow-hud.d.ts +14 -0
- package/dist/types/task/executor.d.ts +1 -0
- package/dist/types/task/render.d.ts +1 -1
- package/dist/types/tools/ask.d.ts +15 -1
- package/dist/types/tools/subagent-render.d.ts +7 -1
- package/dist/types/tools/subagent.d.ts +27 -0
- package/dist/types/tools/ultragoal-ask-guard.d.ts +5 -0
- package/dist/types/web/search/index.d.ts +4 -4
- package/dist/types/web/search/provider.d.ts +16 -20
- package/dist/types/web/search/providers/base.d.ts +2 -1
- package/dist/types/web/search/providers/openai-compatible.d.ts +9 -0
- package/dist/types/web/search/types.d.ts +14 -2
- package/package.json +7 -7
- package/scripts/build-binary.ts +7 -0
- package/src/async/job-manager.ts +52 -0
- package/src/cli/args.ts +5 -0
- package/src/cli/auth-broker-cli.ts +1 -0
- package/src/cli/fast-help.ts +2 -0
- package/src/cli/list-models.ts +13 -1
- package/src/cli/setup-cli.ts +138 -3
- package/src/cli.ts +1 -0
- package/src/commands/gc.ts +22 -0
- package/src/commands/harness.ts +7 -3
- package/src/commands/setup.ts +5 -1
- package/src/commands/ultragoal.ts +3 -1
- package/src/config/file-lock-gc.ts +193 -0
- package/src/config/file-lock.ts +66 -10
- package/src/config/model-profile-activation.ts +15 -3
- package/src/config/model-profiles.ts +39 -30
- package/src/config/model-registry.ts +21 -1
- package/src/config/models-config-schema.ts +1 -0
- package/src/config/settings-schema.ts +62 -0
- package/src/coordinator/contract.ts +1 -0
- package/src/coordinator-mcp/server.ts +459 -3
- package/src/defaults/gjc/agent.models.grok-cli.yml +36 -0
- package/src/defaults/gjc/extensions/grok-build/index.ts +1 -0
- package/src/defaults/gjc/extensions/grok-build/package.json +7 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/biome.json +39 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/package.json +8 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/index.ts +1 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/models/catalog.ts +155 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/payload/sanitize.ts +361 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/billing.ts +57 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/register.ts +99 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/stream.ts +50 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/usage.ts +56 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/shared/base-url.ts +36 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/shared/errors.ts +44 -0
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +131 -113
- package/src/defaults/gjc/skills/deep-interview/lateral-review-panel.md +49 -0
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +30 -8
- package/src/defaults/gjc-defaults.ts +7 -0
- package/src/defaults/gjc-grok-cli.ts +22 -0
- package/src/extensibility/extensions/index.ts +1 -0
- package/src/extensibility/extensions/prefix-command-bridge.ts +128 -0
- package/src/gjc-runtime/deep-interview-recorder.ts +457 -0
- package/src/gjc-runtime/deep-interview-runtime.ts +18 -26
- package/src/gjc-runtime/deep-interview-state.ts +324 -0
- package/src/gjc-runtime/gc-render.ts +70 -0
- package/src/gjc-runtime/gc-runtime.ts +403 -0
- package/src/gjc-runtime/launch-tmux.ts +3 -4
- package/src/gjc-runtime/ledger-event-renderer.ts +164 -0
- package/src/gjc-runtime/ralplan-runtime.ts +232 -19
- package/src/gjc-runtime/state-renderer.ts +12 -3
- package/src/gjc-runtime/state-runtime.ts +48 -30
- package/src/gjc-runtime/state-writer.ts +254 -7
- package/src/gjc-runtime/team-gc.ts +49 -0
- package/src/gjc-runtime/team-runtime.ts +179 -2
- package/src/gjc-runtime/tmux-common.ts +14 -0
- package/src/gjc-runtime/tmux-gc.ts +177 -0
- package/src/gjc-runtime/tmux-sessions.ts +49 -1
- package/src/gjc-runtime/ultragoal-guard.ts +155 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +1239 -31
- package/src/gjc-runtime/workflow-manifest.generated.json +44 -0
- package/src/gjc-runtime/workflow-manifest.ts +12 -0
- package/src/harness-control-plane/gc-adapter.ts +184 -0
- package/src/harness-control-plane/owner.ts +14 -2
- package/src/harness-control-plane/rpc-adapter.ts +1 -1
- package/src/harness-control-plane/storage.ts +70 -0
- package/src/hooks/skill-state.ts +121 -2
- package/src/internal-urls/docs-index.generated.ts +22 -12
- package/src/lsp/defaults.json +1 -0
- package/src/main.ts +18 -3
- package/src/modes/acp/acp-agent.ts +4 -2
- package/src/modes/bridge/bridge-mode.ts +2 -1
- package/src/modes/components/history-search.ts +5 -2
- package/src/modes/components/hook-selector.ts +19 -0
- package/src/modes/components/model-selector.ts +51 -8
- package/src/modes/components/provider-onboarding-selector.ts +6 -1
- package/src/modes/components/status-line/segments.ts +1 -1
- package/src/modes/controllers/command-controller.ts +25 -6
- package/src/modes/controllers/extension-ui-controller.ts +3 -0
- package/src/modes/controllers/selector-controller.ts +81 -1
- package/src/modes/interactive-mode.ts +11 -1
- package/src/modes/rpc/rpc-mode.ts +266 -34
- package/src/modes/shared/agent-wire/command-dispatch.ts +281 -261
- package/src/modes/shared/agent-wire/deep-interview-gate.ts +30 -1
- package/src/modes/shared/agent-wire/host-tool-bridge.ts +3 -0
- package/src/modes/shared/agent-wire/session-registry.ts +109 -0
- package/src/modes/shared/agent-wire/unattended-action-policy.ts +24 -0
- package/src/modes/shared/agent-wire/unattended-run-controller.ts +23 -3
- package/src/modes/shared/agent-wire/unattended-session.ts +32 -2
- package/src/modes/theme/defaults/claude-code.json +100 -0
- package/src/modes/theme/defaults/codex.json +100 -0
- package/src/modes/theme/defaults/index.ts +6 -0
- package/src/modes/theme/defaults/opencode.json +102 -0
- package/src/modes/theme/theme.ts +2 -2
- package/src/modes/types.ts +1 -1
- package/src/prompts/agents/executor.md +5 -2
- package/src/sdk.ts +29 -4
- package/src/session/agent-session.ts +99 -19
- package/src/session/blob-store.ts +59 -3
- package/src/session/history-storage.ts +32 -11
- package/src/session/session-manager.ts +72 -20
- package/src/setup/credential-import.ts +429 -0
- package/src/setup/hermes/templates/operator-instructions.v1.md +7 -1
- package/src/skill-state/deep-interview-mutation-guard.ts +2 -1
- package/src/skill-state/workflow-hud.ts +106 -10
- package/src/slash-commands/builtin-registry.ts +3 -2
- package/src/task/executor.ts +16 -1
- package/src/task/render.ts +18 -7
- package/src/tools/ask.ts +59 -2
- package/src/tools/cron.ts +1 -1
- package/src/tools/job.ts +3 -2
- package/src/tools/monitor.ts +36 -1
- package/src/tools/subagent-render.ts +128 -29
- package/src/tools/subagent.ts +173 -9
- package/src/tools/ultragoal-ask-guard.ts +39 -0
- package/src/web/search/index.ts +25 -25
- package/src/web/search/provider.ts +178 -87
- package/src/web/search/providers/base.ts +2 -1
- package/src/web/search/providers/openai-compatible.ts +151 -0
- package/src/web/search/types.ts +47 -22
|
@@ -143,7 +143,7 @@ export type AgentSessionEvent = AgentEvent | {
|
|
|
143
143
|
};
|
|
144
144
|
/** Listener function for agent session events */
|
|
145
145
|
export type AgentSessionEventListener = (event: AgentSessionEvent) => void;
|
|
146
|
-
export type AsyncJobSnapshotItem = Pick<AsyncJob, "id" | "type" | "status" | "label" | "startTime" | "metadata">;
|
|
146
|
+
export type AsyncJobSnapshotItem = Pick<AsyncJob, "id" | "type" | "status" | "label" | "startTime" | "endTime" | "metadata">;
|
|
147
147
|
export interface AsyncJobSnapshot {
|
|
148
148
|
running: AsyncJobSnapshotItem[];
|
|
149
149
|
recent: AsyncJobSnapshotItem[];
|
|
@@ -78,22 +78,58 @@ export declare function externalizeImageDataSync(blobStore: BlobStore, base64Dat
|
|
|
78
78
|
/**
|
|
79
79
|
* Resolve an externalized provider image data URL back to its original string.
|
|
80
80
|
* If the data is not a blob reference, returns it unchanged.
|
|
81
|
-
*
|
|
81
|
+
*
|
|
82
|
+
* LEGACY PERSISTED-IMAGE COMPATIBILITY BOUNDARY: when the persisted blob is missing
|
|
83
|
+
* (e.g. resuming an old session whose image blob was pruned), this warns and returns
|
|
84
|
+
* the reference as-is rather than throwing, so legacy resume degrades gracefully.
|
|
85
|
+
* New resident byte-sensitive TEXT uses the fail-closed path instead
|
|
86
|
+
* (`resolveTextBlobSync` -> `ResidentBlobMissingError`). Do NOT route new byte-sensitive
|
|
87
|
+
* resident data through this warn-and-return path.
|
|
82
88
|
*/
|
|
83
89
|
export declare function resolveImageDataUrl(blobStore: BlobStore, data: string): Promise<string>;
|
|
84
90
|
/**
|
|
85
91
|
* Resolve a blob reference back to base64 data.
|
|
86
92
|
* If the data is not a blob reference, returns it unchanged.
|
|
87
|
-
*
|
|
93
|
+
*
|
|
94
|
+
* LEGACY PERSISTED-IMAGE COMPATIBILITY BOUNDARY: when the blob is missing this warns
|
|
95
|
+
* and returns the reference as-is (downstream sees an invalid base64 ref but does not
|
|
96
|
+
* crash), preserving legacy-session resume. Byte-sensitive resident TEXT is fail-closed
|
|
97
|
+
* via `resolveTextBlobSync`; do NOT route new byte-sensitive resident data here.
|
|
88
98
|
*/
|
|
89
99
|
export declare function resolveImageData(blobStore: BlobStore, data: string): Promise<string>;
|
|
90
100
|
/** Synchronously resolve an externalized provider image data URL back to its original string. */
|
|
91
101
|
export declare function resolveImageDataUrlSync(blobStore: BlobStore, data: string): string;
|
|
92
102
|
/** Synchronously resolve a blob reference back to base64 data. */
|
|
93
103
|
export declare function resolveImageDataSync(blobStore: BlobStore, data: string): string;
|
|
94
|
-
/**
|
|
104
|
+
/**
|
|
105
|
+
* Synchronously resolve a blob reference back to utf8 text.
|
|
106
|
+
*
|
|
107
|
+
* FAIL-CLOSED byte-sensitive path: a missing resident blob throws
|
|
108
|
+
* `ResidentBlobMissingError` rather than degrading, so a missing resident text blob can
|
|
109
|
+
* never silently leak a `blob:sha256:` ref into provider payloads, UI, or exports.
|
|
110
|
+
* (Contrast the legacy persisted-image warn-and-return resolvers above.)
|
|
111
|
+
*/
|
|
95
112
|
export declare function resolveTextBlobSync(blobStore: BlobStore, data: string, context?: {
|
|
96
113
|
kind?: "text";
|
|
97
114
|
sessionId?: string;
|
|
98
115
|
sessionFile?: string;
|
|
99
116
|
}): string;
|
|
117
|
+
/**
|
|
118
|
+
* FAIL-CLOSED resident variant of {@link resolveImageDataUrlSync}: a missing resident
|
|
119
|
+
* image-data-url blob throws `ResidentBlobMissingError` ("imageUrl") instead of warn-returning,
|
|
120
|
+
* so resident byte-sensitive provider image data can never leak a `blob:sha256:` ref into
|
|
121
|
+
* materialized entries, context, or provider payloads. The warn-and-return `resolveImageDataUrl*`
|
|
122
|
+
* resolvers remain ONLY for legacy persisted-image resume.
|
|
123
|
+
*/
|
|
124
|
+
export declare function resolveResidentImageDataUrlSync(blobStore: BlobStore, data: string, context?: {
|
|
125
|
+
sessionId?: string;
|
|
126
|
+
sessionFile?: string;
|
|
127
|
+
}): string;
|
|
128
|
+
/**
|
|
129
|
+
* FAIL-CLOSED resident variant of {@link resolveImageDataSync}: a missing resident image blob
|
|
130
|
+
* throws `ResidentBlobMissingError` ("imageData") instead of warn-returning a placeholder.
|
|
131
|
+
*/
|
|
132
|
+
export declare function resolveResidentImageDataSync(blobStore: BlobStore, data: string, context?: {
|
|
133
|
+
sessionId?: string;
|
|
134
|
+
sessionFile?: string;
|
|
135
|
+
}): string;
|
|
@@ -11,6 +11,6 @@ export declare class HistoryStorage {
|
|
|
11
11
|
/** @internal Reset the singleton — test-only. */
|
|
12
12
|
static resetInstance(): void;
|
|
13
13
|
add(prompt: string, cwd?: string): Promise<void>;
|
|
14
|
-
getRecent(limit: number): HistoryEntry[];
|
|
15
|
-
search(query: string, limit: number): HistoryEntry[];
|
|
14
|
+
getRecent(limit: number, cwd?: string): HistoryEntry[];
|
|
15
|
+
search(query: string, limit: number, cwd?: string): HistoryEntry[];
|
|
16
16
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AgentMessage } from "@gajae-code/agent-core";
|
|
2
2
|
import type { ImageContent, Message, MessageAttribution, ServiceTier, TextContent } from "@gajae-code/ai";
|
|
3
3
|
import { ArtifactManager } from "./artifacts";
|
|
4
|
-
import { type BlobPutResult } from "./blob-store";
|
|
4
|
+
import { type BlobPutResult, BlobStore } from "./blob-store";
|
|
5
5
|
import { type BashExecutionMessage, type CustomMessage, type FileMentionMessage, type HookMessage, type PythonExecutionMessage } from "./messages";
|
|
6
6
|
import type { SessionStorage } from "./session-storage";
|
|
7
7
|
export declare const CURRENT_SESSION_VERSION = 3;
|
|
@@ -234,6 +234,15 @@ declare class RecentSessionInfo {
|
|
|
234
234
|
export declare function recoverOrphanedBackups(sessionDir: string, storage: SessionStorage): Promise<void>;
|
|
235
235
|
/** Exported for testing */
|
|
236
236
|
export declare function findMostRecentSession(sessionDir: string, storage?: SessionStorage): Promise<string | null>;
|
|
237
|
+
declare const RESIDENT_BLOB_SENTINEL_KEY = "__gjcResidentBlob";
|
|
238
|
+
type ResidentBlobKind = "text" | "imageUrl" | "imageData";
|
|
239
|
+
interface ResidentBlobSentinel {
|
|
240
|
+
[RESIDENT_BLOB_SENTINEL_KEY]: true;
|
|
241
|
+
kind: ResidentBlobKind;
|
|
242
|
+
ref: string;
|
|
243
|
+
}
|
|
244
|
+
export declare function residentBlobSentinelForTests(kind: ResidentBlobKind, ref: string): ResidentBlobSentinel;
|
|
245
|
+
export declare function materializeResidentEntriesForPersistenceForTests<T>(entries: T[], textStore: BlobStore, imageStore?: BlobStore): T[];
|
|
237
246
|
/** Get recent sessions for display in welcome screen */
|
|
238
247
|
export declare function getRecentSessions(sessionDir: string, limit?: number, storage?: SessionStorage): Promise<RecentSessionInfo[]>;
|
|
239
248
|
/**
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { AuthCredential } from "@gajae-code/ai";
|
|
2
|
+
/** gjc provider ids that external credentials map onto. */
|
|
3
|
+
export type ExternalProvider = "anthropic" | "openai-codex";
|
|
4
|
+
/** Where a discovered credential came from. */
|
|
5
|
+
export type CredentialOrigin = "claude-code-file" | "claude-code-keychain" | "codex-file";
|
|
6
|
+
/** Human labels for providers, used in redacted summaries. */
|
|
7
|
+
export declare const EXTERNAL_PROVIDER_LABELS: Record<ExternalProvider, string>;
|
|
8
|
+
/** A credential that can be safely imported into gjc's store. */
|
|
9
|
+
export interface ImportableCredential {
|
|
10
|
+
provider: ExternalProvider;
|
|
11
|
+
origin: CredentialOrigin;
|
|
12
|
+
/** Redacted, human-readable description of where this came from. */
|
|
13
|
+
source: string;
|
|
14
|
+
kind: AuthCredential["type"];
|
|
15
|
+
identity?: {
|
|
16
|
+
email?: string;
|
|
17
|
+
accountId?: string;
|
|
18
|
+
};
|
|
19
|
+
/** Epoch-ms expiry for OAuth credentials, when known. */
|
|
20
|
+
expiresAt?: number;
|
|
21
|
+
/** Redacted access token / API key — safe to display. */
|
|
22
|
+
redactedToken: string;
|
|
23
|
+
/** Opaque credential payload. Never include this in any summary output. */
|
|
24
|
+
credential: AuthCredential;
|
|
25
|
+
}
|
|
26
|
+
/** A source that was found but could not be imported. */
|
|
27
|
+
export interface SkippedCredential {
|
|
28
|
+
origin: CredentialOrigin;
|
|
29
|
+
source: string;
|
|
30
|
+
reason: string;
|
|
31
|
+
}
|
|
32
|
+
/** Ambient environment-backed auth that is already usable without import. */
|
|
33
|
+
export interface EnvironmentCredentialHint {
|
|
34
|
+
provider: ExternalProvider;
|
|
35
|
+
variable: string;
|
|
36
|
+
redactedValue: string;
|
|
37
|
+
}
|
|
38
|
+
export interface CredentialDiscoveryResult {
|
|
39
|
+
importable: ImportableCredential[];
|
|
40
|
+
skipped: SkippedCredential[];
|
|
41
|
+
environment: EnvironmentCredentialHint[];
|
|
42
|
+
}
|
|
43
|
+
export interface DiscoveryOptions {
|
|
44
|
+
/** Override the home directory (defaults to `os.homedir()`). */
|
|
45
|
+
homeDir?: string;
|
|
46
|
+
/** Override the environment (defaults to `process.env`). */
|
|
47
|
+
env?: Record<string, string | undefined>;
|
|
48
|
+
/** Override the platform (defaults to `process.platform`). */
|
|
49
|
+
platform?: NodeJS.Platform;
|
|
50
|
+
/**
|
|
51
|
+
* Reader for the macOS Keychain `Claude Code-credentials` entry. Defaults to
|
|
52
|
+
* shelling out to `security`; injected in tests. Returns the raw JSON string,
|
|
53
|
+
* or `null` when no entry exists.
|
|
54
|
+
*/
|
|
55
|
+
readClaudeKeychain?: () => Promise<string | null>;
|
|
56
|
+
}
|
|
57
|
+
export type CredentialUpserter = (provider: string, credential: AuthCredential) => unknown | Promise<unknown>;
|
|
58
|
+
export interface ImportSummary {
|
|
59
|
+
imported: ImportableCredential[];
|
|
60
|
+
failed: Array<{
|
|
61
|
+
credential: ImportableCredential;
|
|
62
|
+
error: string;
|
|
63
|
+
}>;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Discover Claude Code and Codex CLI credentials across files, the macOS
|
|
67
|
+
* Keychain, and environment variables. Never throws for individual unreadable or
|
|
68
|
+
* malformed sources — those land in {@link CredentialDiscoveryResult.skipped}.
|
|
69
|
+
*/
|
|
70
|
+
export declare function discoverExternalCredentials(options?: DiscoveryOptions): Promise<CredentialDiscoveryResult>;
|
|
71
|
+
/** Redacted one-line summary of an importable credential. Never includes secrets. */
|
|
72
|
+
export declare function formatCredentialSummary(credential: ImportableCredential): string;
|
|
73
|
+
/** Redacted summary lines for an entire discovery result. Never includes secrets. */
|
|
74
|
+
export declare function formatDiscoverySummary(result: CredentialDiscoveryResult): string[];
|
|
75
|
+
/**
|
|
76
|
+
* Persist discovered credentials via `upsert`. Each credential is imported
|
|
77
|
+
* independently; a failure on one is recorded without aborting the rest.
|
|
78
|
+
*/
|
|
79
|
+
export declare function importCredentials(credentials: readonly ImportableCredential[], upsert: CredentialUpserter): Promise<ImportSummary>;
|
|
@@ -18,6 +18,8 @@ interface RalplanHudState extends WorkflowGateHudState {
|
|
|
18
18
|
stage?: string;
|
|
19
19
|
waiting?: string;
|
|
20
20
|
iteration?: number;
|
|
21
|
+
iterationFromIndex?: number;
|
|
22
|
+
stages?: string;
|
|
21
23
|
verdict?: string;
|
|
22
24
|
latestSummary?: string;
|
|
23
25
|
pendingApproval?: boolean;
|
|
@@ -61,6 +63,18 @@ interface TeamHudState extends WorkflowGateHudState {
|
|
|
61
63
|
};
|
|
62
64
|
}
|
|
63
65
|
export declare function buildDeepInterviewHudSummary(state: DeepInterviewHudState): WorkflowHudSummary;
|
|
66
|
+
export interface DeepInterviewHudDeriveOptions {
|
|
67
|
+
phase?: string;
|
|
68
|
+
specStatus?: string;
|
|
69
|
+
updatedAt?: string;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Single source of deep-interview HUD derivation. Reads a complete (normalized)
|
|
73
|
+
* mode-state envelope so recorder, `gjc state write`, reconcile, seed, and handoff
|
|
74
|
+
* all produce identical chips. Topology-aware `target`/`weakest` come from
|
|
75
|
+
* `state.topology`; `legacy_missing` topology omits those chips (no synthetic values).
|
|
76
|
+
*/
|
|
77
|
+
export declare function deriveDeepInterviewHud(payload: Record<string, unknown>, options?: DeepInterviewHudDeriveOptions): WorkflowHudSummary;
|
|
64
78
|
export declare function buildRalplanHudSummary(state: RalplanHudState): WorkflowHudSummary;
|
|
65
79
|
export declare function buildUltragoalHudSummary(state: UltragoalHudState): WorkflowHudSummary;
|
|
66
80
|
export declare function buildTeamHudSummary(state: TeamHudState): WorkflowHudSummary;
|
|
@@ -105,6 +105,7 @@ interface FinalizeSubprocessOutputResult {
|
|
|
105
105
|
export declare const SUBAGENT_WARNING_NULL_YIELD = "SYSTEM WARNING: Subagent called yield with null data.";
|
|
106
106
|
export declare const SUBAGENT_WARNING_MISSING_YIELD = "SYSTEM WARNING: Subagent exited without calling yield tool after 3 reminders.";
|
|
107
107
|
export declare function finalizeSubprocessOutput(args: FinalizeSubprocessOutputArgs): FinalizeSubprocessOutputResult;
|
|
108
|
+
export declare function createSubagentSettings(baseSettings: Settings): Settings;
|
|
108
109
|
/**
|
|
109
110
|
* Run a single agent in-process.
|
|
110
111
|
*/
|
|
@@ -11,7 +11,7 @@ export declare function renderCall(args: TaskParams, _options: RenderResultOptio
|
|
|
11
11
|
* `subagent` await panel. Reuses the internal task-progress renderer so the
|
|
12
12
|
* await panel stays at parity with the inline task panel.
|
|
13
13
|
*/
|
|
14
|
-
export declare function renderSubagentLiveProgress(progress: AgentProgress, expanded: boolean, theme: Theme, spinnerFrame?: number): string[];
|
|
14
|
+
export declare function renderSubagentLiveProgress(progress: AgentProgress, expanded: boolean, theme: Theme, spinnerFrame?: number, staticTime?: boolean): string[];
|
|
15
15
|
/**
|
|
16
16
|
* Render the tool result.
|
|
17
17
|
*/
|
|
@@ -20,7 +20,7 @@ import * as z from "zod/v4";
|
|
|
20
20
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
21
21
|
import { type Theme } from "../modes/theme/theme";
|
|
22
22
|
import type { ToolSession } from ".";
|
|
23
|
-
declare const askSchema: z.ZodObject<{
|
|
23
|
+
export declare const askSchema: z.ZodObject<{
|
|
24
24
|
questions: z.ZodArray<z.ZodObject<{
|
|
25
25
|
id: z.ZodString;
|
|
26
26
|
question: z.ZodString;
|
|
@@ -29,6 +29,13 @@ declare const askSchema: z.ZodObject<{
|
|
|
29
29
|
}, z.core.$strip>>;
|
|
30
30
|
multi: z.ZodOptional<z.ZodBoolean>;
|
|
31
31
|
recommended: z.ZodOptional<z.ZodNumber>;
|
|
32
|
+
deepInterview: z.ZodOptional<z.ZodObject<{
|
|
33
|
+
round_id: z.ZodOptional<z.ZodString>;
|
|
34
|
+
round: z.ZodNumber;
|
|
35
|
+
component: z.ZodString;
|
|
36
|
+
dimension: z.ZodString;
|
|
37
|
+
ambiguity: z.ZodNumber;
|
|
38
|
+
}, z.core.$strip>>;
|
|
32
39
|
}, z.core.$strip>>;
|
|
33
40
|
}, z.core.$strip>;
|
|
34
41
|
export type AskToolInput = z.infer<typeof askSchema>;
|
|
@@ -73,6 +80,13 @@ export declare class AskTool implements AgentTool<typeof askSchema, AskToolDetai
|
|
|
73
80
|
}, z.core.$strip>>;
|
|
74
81
|
multi: z.ZodOptional<z.ZodBoolean>;
|
|
75
82
|
recommended: z.ZodOptional<z.ZodNumber>;
|
|
83
|
+
deepInterview: z.ZodOptional<z.ZodObject<{
|
|
84
|
+
round_id: z.ZodOptional<z.ZodString>;
|
|
85
|
+
round: z.ZodNumber;
|
|
86
|
+
component: z.ZodString;
|
|
87
|
+
dimension: z.ZodString;
|
|
88
|
+
ambiguity: z.ZodNumber;
|
|
89
|
+
}, z.core.$strip>>;
|
|
76
90
|
}, z.core.$strip>>;
|
|
77
91
|
}, z.core.$strip>;
|
|
78
92
|
readonly strict = true;
|
|
@@ -10,7 +10,13 @@
|
|
|
10
10
|
import type { Component } from "@gajae-code/tui";
|
|
11
11
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
12
12
|
import type { Theme } from "../modes/theme/theme";
|
|
13
|
-
import type
|
|
13
|
+
import { type SubagentToolDetails } from "./subagent";
|
|
14
|
+
/** Test-only seam (PR3 deterministic cache-hit assertions). */
|
|
15
|
+
export declare const subagentBodyCacheTestHooks: {
|
|
16
|
+
readonly bodyRenders: number;
|
|
17
|
+
readonly size: number;
|
|
18
|
+
reset(): void;
|
|
19
|
+
};
|
|
14
20
|
export declare const subagentToolRenderer: {
|
|
15
21
|
inline: boolean;
|
|
16
22
|
renderCall(_args: unknown, _options: RenderResultOptions, theme: Theme): Component;
|
|
@@ -46,6 +46,12 @@ export interface SubagentSnapshot {
|
|
|
46
46
|
progress?: AgentProgress;
|
|
47
47
|
/** True when a live in-session progress producer exists for this subagent. */
|
|
48
48
|
liveProgressAvailable?: boolean;
|
|
49
|
+
/** Model the subagent actually runs on (after any auth fallback). */
|
|
50
|
+
effectiveModel?: string;
|
|
51
|
+
/** Model originally requested via role/preset mapping; differs from effective on fallback. */
|
|
52
|
+
requestedModel?: string;
|
|
53
|
+
/** True when the requested model lacked credentials and fell back to the parent model. */
|
|
54
|
+
modelFellBack?: boolean;
|
|
49
55
|
}
|
|
50
56
|
export interface SubagentToolDetails {
|
|
51
57
|
subagents: SubagentSnapshot[];
|
|
@@ -84,4 +90,25 @@ export declare class SubagentTool implements AgentTool<typeof subagentSchema, Su
|
|
|
84
90
|
constructor(session: ToolSession);
|
|
85
91
|
execute(_toolCallId: string, params: SubagentParams, signal?: AbortSignal, onUpdate?: AgentToolUpdateCallback<SubagentToolDetails>, _context?: AgentToolContext): Promise<AgentToolResult<SubagentToolDetails>>;
|
|
86
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Canonical, value-based rendered-state signature for the `subagent` await panel.
|
|
95
|
+
*
|
|
96
|
+
* Producer-side await gating compares this signature against the last emitted one
|
|
97
|
+
* and only fires `onUpdate` when the *rendered* state actually changed. Unchanged
|
|
98
|
+
* idle ticks therefore stop rebuilding the renderer component and stop mutating
|
|
99
|
+
* transcript lines above the viewport, which is what triggers TUI full-redraw
|
|
100
|
+
* storms (`tui.ts` `firstChanged < viewportTop`).
|
|
101
|
+
*
|
|
102
|
+
* It is deliberately value-based, never object identity: `AsyncJobManager.record-
|
|
103
|
+
* SubagentProgress` stores a `structuredClone` but `getSubagentProgress` returns
|
|
104
|
+
* the retained object by reference, so identity comparison would be both noisy and
|
|
105
|
+
* unsafe.
|
|
106
|
+
*
|
|
107
|
+
* Time-derived fields are intentionally excluded so the panel does not churn while
|
|
108
|
+
* idle: raw durations (`durationMs`), current-tool elapsed (`currentToolStartMs`),
|
|
109
|
+
* and retry countdowns (`retryState.startedAtMs`) are omitted. Idle duration and
|
|
110
|
+
* countdown ticking is sacrificed by design; every real transition still changes
|
|
111
|
+
* the signature.
|
|
112
|
+
*/
|
|
113
|
+
export declare function subagentAwaitRenderedStateSignature(subagents: readonly SubagentSnapshot[]): string;
|
|
87
114
|
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AgentTool } from "@gajae-code/agent-core";
|
|
2
|
+
import { type UltragoalAskBlockDiagnostic } from "../gjc-runtime/ultragoal-guard";
|
|
3
|
+
export declare function formatUltragoalAskBlockMessage(diagnostic: UltragoalAskBlockDiagnostic): string;
|
|
4
|
+
export declare function assertUltragoalAskAllowed(cwd: string): Promise<void>;
|
|
5
|
+
export declare function guardToolForUltragoalAsk<T extends AgentTool>(tool: T, getCwd: () => string): T;
|
|
@@ -10,7 +10,7 @@ import * as z from "zod/v4";
|
|
|
10
10
|
import type { CustomTool } from "../../extensibility/custom-tools/types";
|
|
11
11
|
import type { ToolSession } from "../../tools";
|
|
12
12
|
import { type SearchRenderDetails } from "./render";
|
|
13
|
-
import type { SearchProviderId } from "./types";
|
|
13
|
+
import type { ActiveSearchModelContext, SearchProviderId } from "./types";
|
|
14
14
|
/** Web search tool parameters schema */
|
|
15
15
|
export declare const webSearchSchema: z.ZodObject<{
|
|
16
16
|
query: z.ZodString;
|
|
@@ -40,7 +40,7 @@ export declare function runSearchQuery(params: SearchQueryParams, options?: {
|
|
|
40
40
|
authStorage?: AuthStorage;
|
|
41
41
|
sessionId?: string;
|
|
42
42
|
signal?: AbortSignal;
|
|
43
|
-
|
|
43
|
+
activeModelContext?: ActiveSearchModelContext;
|
|
44
44
|
}): Promise<{
|
|
45
45
|
content: Array<{
|
|
46
46
|
type: "text";
|
|
@@ -80,6 +80,6 @@ export declare class WebSearchTool implements AgentTool<typeof webSearchSchema,
|
|
|
80
80
|
/** Web search tool as CustomTool (for TUI rendering support) */
|
|
81
81
|
export declare const webSearchCustomTool: CustomTool<typeof webSearchSchema, SearchRenderDetails>;
|
|
82
82
|
export declare function getSearchTools(): CustomTool<any, any>[];
|
|
83
|
-
export { getSearchProvider, setPreferredSearchProvider } from "./provider";
|
|
83
|
+
export { getSearchProvider, setPreferredSearchProvider, setSearchFallbackProviders } from "./provider";
|
|
84
84
|
export type { SearchProviderId as SearchProvider, SearchResponse } from "./types";
|
|
85
|
-
export { isSearchProviderPreference } from "./types";
|
|
85
|
+
export { isConfigurableSearchProviderId, isSearchProviderPreference } from "./types";
|
|
@@ -1,28 +1,24 @@
|
|
|
1
1
|
import type { AuthStorage } from "@gajae-code/ai";
|
|
2
2
|
import type { SearchProvider } from "./providers/base";
|
|
3
|
-
import type { SearchProviderId } from "./types";
|
|
3
|
+
import type { ActiveSearchModelContext, SearchProviderId } from "./types";
|
|
4
4
|
export type { SearchParams } from "./providers/base";
|
|
5
5
|
export { SearchProvider } from "./providers/base";
|
|
6
|
-
/** Cheap, sync metadata accessor — never triggers a provider load. */
|
|
7
6
|
export declare function getSearchProviderLabel(id: SearchProviderId): string;
|
|
8
|
-
/**
|
|
9
|
-
* Resolve and cache a provider instance. First call for a given id loads the
|
|
10
|
-
* underlying module; subsequent calls return the cached singleton.
|
|
11
|
-
*/
|
|
12
7
|
export declare function getSearchProvider(id: SearchProviderId): Promise<SearchProvider>;
|
|
13
8
|
export declare const SEARCH_PROVIDER_ORDER: SearchProviderId[];
|
|
14
|
-
/** Set the preferred web search provider from settings */
|
|
15
9
|
export declare function setPreferredSearchProvider(provider: SearchProviderId | "auto"): void;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
export declare function
|
|
10
|
+
export declare function setSearchFallbackProviders(ids: readonly string[]): void;
|
|
11
|
+
export interface ResolveProviderChainOptions {
|
|
12
|
+
authStorage: AuthStorage;
|
|
13
|
+
sessionId?: string;
|
|
14
|
+
signal?: AbortSignal;
|
|
15
|
+
preferredProvider?: SearchProviderId | "auto";
|
|
16
|
+
activeModelContext?: ActiveSearchModelContext;
|
|
17
|
+
fallbackProviders?: readonly SearchProviderId[];
|
|
18
|
+
}
|
|
19
|
+
export declare function looksHostedModelId(modelId: string | undefined): boolean;
|
|
20
|
+
export declare function isLocalBaseUrl(baseUrl: string | undefined): boolean;
|
|
21
|
+
export declare function inferNativeProviderFromModel(ctx: ActiveSearchModelContext | undefined): SearchProviderId | undefined;
|
|
22
|
+
export declare function canUseGenericCredentials(authStorage: AuthStorage, ctx: ActiveSearchModelContext | undefined, sessionId?: string, signal?: AbortSignal): Promise<boolean>;
|
|
23
|
+
export declare function shouldTryGenericOpenAICompat(authStorage: AuthStorage, ctx: ActiveSearchModelContext | undefined, sessionId?: string, signal?: AbortSignal): Promise<boolean>;
|
|
24
|
+
export declare function resolveProviderChain(options: ResolveProviderChainOptions): Promise<SearchProvider[]>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AuthStorage } from "@gajae-code/ai";
|
|
2
|
-
import type { SearchProviderId, SearchResponse } from "../types";
|
|
2
|
+
import type { ActiveSearchModelContext, SearchProviderId, SearchResponse } from "../types";
|
|
3
3
|
/**
|
|
4
4
|
* Shared web search parameters passed to providers.
|
|
5
5
|
*
|
|
@@ -49,6 +49,7 @@ export interface SearchParams {
|
|
|
49
49
|
* caller's agent session when available; otherwise omit.
|
|
50
50
|
*/
|
|
51
51
|
sessionId?: string;
|
|
52
|
+
activeModelContext?: ActiveSearchModelContext;
|
|
52
53
|
}
|
|
53
54
|
/** Base class for web search providers. */
|
|
54
55
|
export declare abstract class SearchProvider {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { SearchResponse } from "../types";
|
|
2
|
+
import type { SearchParams } from "./base";
|
|
3
|
+
import { SearchProvider } from "./base";
|
|
4
|
+
export declare class OpenAICompatibleSearchProvider extends SearchProvider {
|
|
5
|
+
readonly id: "openai-compatible";
|
|
6
|
+
readonly label = "OpenAI-compatible";
|
|
7
|
+
isAvailable(): boolean;
|
|
8
|
+
search(params: SearchParams): Promise<SearchResponse>;
|
|
9
|
+
}
|
|
@@ -4,9 +4,21 @@
|
|
|
4
4
|
* Unified types for web search responses across supported providers.
|
|
5
5
|
*/
|
|
6
6
|
/** Supported web search providers */
|
|
7
|
-
export type SearchProviderId = "duckduckgo" | "exa" | "brave" | "jina" | "kimi" | "zai" | "anthropic" | "perplexity" | "gemini" | "codex" | "tavily" | "parallel" | "kagi" | "synthetic" | "searxng";
|
|
7
|
+
export type SearchProviderId = "duckduckgo" | "exa" | "brave" | "jina" | "kimi" | "zai" | "anthropic" | "perplexity" | "gemini" | "codex" | "tavily" | "parallel" | "kagi" | "synthetic" | "searxng" | "openai-compatible";
|
|
8
|
+
export type WebSearchMode = "on" | "off" | "auto";
|
|
9
|
+
export interface ActiveSearchModelContext {
|
|
10
|
+
provider: string;
|
|
11
|
+
modelId: string;
|
|
12
|
+
wireModelId?: string;
|
|
13
|
+
api: string;
|
|
14
|
+
baseUrl?: string;
|
|
15
|
+
headers?: Record<string, string>;
|
|
16
|
+
webSearch?: WebSearchMode;
|
|
17
|
+
}
|
|
18
|
+
export declare const CONFIGURABLE_SEARCH_PROVIDER_IDS: readonly ["duckduckgo", "exa", "brave", "jina", "kimi", "zai", "anthropic", "perplexity", "gemini", "codex", "tavily", "parallel", "kagi", "synthetic", "searxng"];
|
|
8
19
|
export declare function isSearchProviderId(value: string): value is SearchProviderId;
|
|
9
|
-
export declare function
|
|
20
|
+
export declare function isConfigurableSearchProviderId(value: string): value is (typeof CONFIGURABLE_SEARCH_PROVIDER_IDS)[number];
|
|
21
|
+
export declare function isSearchProviderPreference(value: string): value is (typeof CONFIGURABLE_SEARCH_PROVIDER_IDS)[number] | "auto";
|
|
10
22
|
/** Source returned by search (all providers) */
|
|
11
23
|
export interface SearchSource {
|
|
12
24
|
title: string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@gajae-code/coding-agent",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.2",
|
|
5
5
|
"description": "Gajae Code CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://gaebal-gajae.dev",
|
|
7
7
|
"author": "Yeachan-Heo",
|
|
@@ -51,12 +51,12 @@
|
|
|
51
51
|
"@agentclientprotocol/sdk": "0.21.0",
|
|
52
52
|
"@babel/parser": "^7.29.3",
|
|
53
53
|
"@mozilla/readability": "^0.6.0",
|
|
54
|
-
"@gajae-code/stats": "0.5.
|
|
55
|
-
"@gajae-code/agent-core": "0.5.
|
|
56
|
-
"@gajae-code/ai": "0.5.
|
|
57
|
-
"@gajae-code/natives": "0.5.
|
|
58
|
-
"@gajae-code/tui": "0.5.
|
|
59
|
-
"@gajae-code/utils": "0.5.
|
|
54
|
+
"@gajae-code/stats": "0.5.2",
|
|
55
|
+
"@gajae-code/agent-core": "0.5.2",
|
|
56
|
+
"@gajae-code/ai": "0.5.2",
|
|
57
|
+
"@gajae-code/natives": "0.5.2",
|
|
58
|
+
"@gajae-code/tui": "0.5.2",
|
|
59
|
+
"@gajae-code/utils": "0.5.2",
|
|
60
60
|
"@puppeteer/browsers": "^2.13.0",
|
|
61
61
|
"@types/turndown": "5.0.6",
|
|
62
62
|
"@xterm/headless": "^6.0.0",
|
package/scripts/build-binary.ts
CHANGED
|
@@ -5,6 +5,12 @@ import * as path from "node:path";
|
|
|
5
5
|
const packageDir = path.join(import.meta.dir, "..");
|
|
6
6
|
const outputPath = path.join(packageDir, "dist", "gjc");
|
|
7
7
|
const nativeDir = path.join(packageDir, "..", "natives", "native");
|
|
8
|
+
// Lazy native tokenizer entrypoint. `agent-core/compaction` loads this from
|
|
9
|
+
// the explicit native entrypoint instead of a package-name dynamic require of
|
|
10
|
+
// `@gajae-code/natives`, because those fail inside Bun standalone `$bunfs`.
|
|
11
|
+
// Listing the module here makes the absolute target path exist in the compiled
|
|
12
|
+
// bunfs.
|
|
13
|
+
const nativeTokenizerEntrypoint = "../natives/native/index.js";
|
|
8
14
|
|
|
9
15
|
function shouldAdhocSignDarwinBinary(): boolean {
|
|
10
16
|
return process.platform === "darwin";
|
|
@@ -66,6 +72,7 @@ async function main(): Promise<void> {
|
|
|
66
72
|
"../stats/src/sync-worker.ts",
|
|
67
73
|
"./src/tools/browser/tab-worker-entry.ts",
|
|
68
74
|
"./src/eval/js/worker-entry.ts",
|
|
75
|
+
nativeTokenizerEntrypoint,
|
|
69
76
|
"--outfile",
|
|
70
77
|
"dist/gjc",
|
|
71
78
|
],
|
package/src/async/job-manager.ts
CHANGED
|
@@ -13,6 +13,14 @@ export interface AsyncJob {
|
|
|
13
13
|
type: "bash" | "task";
|
|
14
14
|
status: "running" | "completed" | "failed" | "cancelled" | "paused";
|
|
15
15
|
startTime: number;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Wall-clock ms when the job left the `running` state (completed, failed,
|
|
19
|
+
* cancelled, or paused). Undefined while running. Frozen on the first
|
|
20
|
+
* terminal/pause transition so elapsed-time renderers stop counting once a
|
|
21
|
+
* job is no longer active instead of growing forever against `Date.now()`.
|
|
22
|
+
*/
|
|
23
|
+
endTime?: number;
|
|
16
24
|
label: string;
|
|
17
25
|
abortController: AbortController;
|
|
18
26
|
promise: Promise<void>;
|
|
@@ -28,6 +36,16 @@ export interface AsyncJob {
|
|
|
28
36
|
ownerId?: string;
|
|
29
37
|
}
|
|
30
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Elapsed wall-clock ms for a job, frozen once it stops running. While the job
|
|
41
|
+
* is active (`endTime` undefined) this counts against `now`; after it stops it
|
|
42
|
+
* returns the fixed `endTime - startTime` span so status renderers do not keep
|
|
43
|
+
* incrementing a completed job's timer.
|
|
44
|
+
*/
|
|
45
|
+
export function jobElapsedMs(job: Pick<AsyncJob, "startTime" | "endTime">, now: number = Date.now()): number {
|
|
46
|
+
return Math.max(0, (job.endTime ?? now) - job.startTime);
|
|
47
|
+
}
|
|
48
|
+
|
|
31
49
|
export interface AsyncJobMetadata {
|
|
32
50
|
subagent?: {
|
|
33
51
|
id: string;
|
|
@@ -80,6 +98,12 @@ export interface SubagentRecord {
|
|
|
80
98
|
/** False for ephemeral sessions (no persistent artifacts dir). */
|
|
81
99
|
resumable: boolean;
|
|
82
100
|
queued?: { ownerId?: string; seq: number; message?: string; createdAt: number };
|
|
101
|
+
/** Resolved model the subagent was asked to use, e.g. "openai-codex/gpt-5.5". */
|
|
102
|
+
requestedModel?: string;
|
|
103
|
+
/** Model actually used after auth fallback (#985); equals requestedModel when no fallback. */
|
|
104
|
+
effectiveModel?: string;
|
|
105
|
+
/** True when the requested model lacked credentials and the subagent fell back to the parent model. */
|
|
106
|
+
modelFellBack?: boolean;
|
|
83
107
|
}
|
|
84
108
|
|
|
85
109
|
/** Lightweight, manager-owned resume payload. The async layer treats `data` as opaque. */
|
|
@@ -368,6 +392,7 @@ export class AsyncJobManager {
|
|
|
368
392
|
// delivery and no eviction scheduling: a paused subagent stays
|
|
369
393
|
// listed and resumable from its sessionFile.
|
|
370
394
|
job.status = "paused";
|
|
395
|
+
this.#freezeEndTime(job);
|
|
371
396
|
if (outcome.note) job.resultText = outcome.note;
|
|
372
397
|
this.#markRecordPaused(id);
|
|
373
398
|
this.#drainResumeQueue();
|
|
@@ -375,6 +400,7 @@ export class AsyncJobManager {
|
|
|
375
400
|
}
|
|
376
401
|
|
|
377
402
|
job.status = "completed";
|
|
403
|
+
this.#freezeEndTime(job);
|
|
378
404
|
job.resultText = outcome.text;
|
|
379
405
|
this.#enqueueDelivery(id, outcome.text);
|
|
380
406
|
this.#runLifecycle(id, "terminal");
|
|
@@ -393,6 +419,7 @@ export class AsyncJobManager {
|
|
|
393
419
|
this.#runLifecycle(id, "terminal");
|
|
394
420
|
const errorText = error instanceof Error ? error.message : String(error);
|
|
395
421
|
job.status = "failed";
|
|
422
|
+
this.#freezeEndTime(job);
|
|
396
423
|
job.errorText = errorText;
|
|
397
424
|
this.#enqueueDelivery(id, errorText);
|
|
398
425
|
this.#scheduleEviction(id);
|
|
@@ -428,10 +455,22 @@ export class AsyncJobManager {
|
|
|
428
455
|
if (job.status !== "running") return false;
|
|
429
456
|
this.#runLifecycle(id, "cancel");
|
|
430
457
|
job.status = "cancelled";
|
|
458
|
+
this.#freezeEndTime(job);
|
|
431
459
|
job.abortController.abort();
|
|
432
460
|
return true;
|
|
433
461
|
}
|
|
434
462
|
|
|
463
|
+
/**
|
|
464
|
+
* Freeze the wall-clock instant a job stopped running. Idempotent: the
|
|
465
|
+
* first stop (completed/failed/cancelled/paused) wins so elapsed-time
|
|
466
|
+
* renderers report a stable duration instead of counting against
|
|
467
|
+
* `Date.now()` forever. A resumed subagent registers a brand-new job with
|
|
468
|
+
* its own `startTime`, so a paused job's frozen `endTime` is never reused.
|
|
469
|
+
*/
|
|
470
|
+
#freezeEndTime(job: AsyncJob): void {
|
|
471
|
+
job.endTime ??= Date.now();
|
|
472
|
+
}
|
|
473
|
+
|
|
435
474
|
#runLifecycle(jobId: string, phase: "cancel" | "terminal" | "evict"): void {
|
|
436
475
|
const fired = this.#lifecyclePhases.get(jobId) ?? new Set<"cancel" | "terminal" | "evict">();
|
|
437
476
|
if (fired.has(phase)) return;
|
|
@@ -503,6 +542,18 @@ export class AsyncJobManager {
|
|
|
503
542
|
this.#subagentRecords.set(record.subagentId, record);
|
|
504
543
|
}
|
|
505
544
|
|
|
545
|
+
/** Patch model metadata onto an existing subagent record (best-effort; no-op if unknown). */
|
|
546
|
+
updateSubagentModel(
|
|
547
|
+
subagentId: string,
|
|
548
|
+
model: { requestedModel?: string; effectiveModel?: string; modelFellBack?: boolean },
|
|
549
|
+
): void {
|
|
550
|
+
const record = this.#subagentRecords.get(subagentId);
|
|
551
|
+
if (!record) return;
|
|
552
|
+
record.requestedModel = model.requestedModel;
|
|
553
|
+
record.effectiveModel = model.effectiveModel;
|
|
554
|
+
record.modelFellBack = model.modelFellBack;
|
|
555
|
+
}
|
|
556
|
+
|
|
506
557
|
getSubagentRecord(subagentId: string, filter?: AsyncJobFilter): SubagentRecord | undefined {
|
|
507
558
|
const rec = this.#subagentRecords.get(subagentId.trim());
|
|
508
559
|
if (!rec) return undefined;
|
|
@@ -978,6 +1029,7 @@ export class AsyncJobManager {
|
|
|
978
1029
|
for (const job of this.getRunningJobs(filter)) {
|
|
979
1030
|
this.#runLifecycle(job.id, "cancel");
|
|
980
1031
|
job.status = "cancelled";
|
|
1032
|
+
this.#freezeEndTime(job);
|
|
981
1033
|
job.abortController.abort();
|
|
982
1034
|
this.#scheduleEviction(job.id);
|
|
983
1035
|
}
|