@gajae-code/coding-agent 0.12.7 → 0.12.10
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 +48 -0
- package/dist/types/cli/notify-cli.d.ts +1 -0
- package/dist/types/commands/notify.d.ts +4 -0
- package/dist/types/commands/sdk.d.ts +23 -0
- package/dist/types/config/file-lock.d.ts +3 -0
- package/dist/types/config/model-discovery-manager.d.ts +6 -1
- package/dist/types/config/model-registry.d.ts +2 -0
- package/dist/types/config/resolve-config-value.d.ts +2 -1
- package/dist/types/config/settings-schema.d.ts +17 -1
- package/dist/types/discovery/agents-md.d.ts +11 -1
- package/dist/types/main.d.ts +1 -0
- package/dist/types/modes/components/hook-selector.d.ts +20 -0
- package/dist/types/modes/components/notifications-settings-editor.d.ts +53 -4
- package/dist/types/modes/controllers/extension-ui-controller.d.ts +1 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +4 -2
- package/dist/types/modes/types.d.ts +6 -0
- package/dist/types/sdk/broker/broker.d.ts +5 -1
- package/dist/types/sdk/broker/lifecycle-ledger.d.ts +1 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +11 -1
- package/dist/types/sdk/bus/config.d.ts +75 -113
- package/dist/types/sdk/bus/daemon-paths.d.ts +1 -0
- package/dist/types/sdk/bus/discord-live-provider.d.ts +8 -2
- package/dist/types/sdk/bus/discord-provider.d.ts +19 -0
- package/dist/types/sdk/bus/index.d.ts +1 -1
- package/dist/types/sdk/bus/notification-orchestration.d.ts +127 -18
- package/dist/types/sdk/bus/notification-service.d.ts +54 -4
- package/dist/types/sdk/bus/session-control.d.ts +8 -3
- package/dist/types/sdk/bus/slack-live-provider.d.ts +9 -2
- package/dist/types/sdk/bus/slack-provider.d.ts +22 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +8 -1
- package/dist/types/sdk/client/discovery.d.ts +2 -1
- package/dist/types/sdk/host/query/handlers.d.ts +2 -0
- package/dist/types/sdk/index.d.ts +1 -0
- package/dist/types/sdk/providers.d.ts +22 -0
- package/dist/types/sdk/session-directory.d.ts +1 -1
- package/dist/types/session/internal/managed-session-scope.d.ts +17 -1
- package/dist/types/session/internal/managed-session-storage.d.ts +19 -1
- package/dist/types/session/internal/native-publish-outcome.d.ts +3 -2
- package/dist/types/session/internal/session-open-errors.d.ts +5 -0
- package/dist/types/session/session-manager.d.ts +3 -1
- package/dist/types/session/session-storage.d.ts +2 -0
- package/dist/types/system-prompt.d.ts +12 -1
- package/dist/types/tools/composer-bash-policy.d.ts +9 -1
- package/package.json +10 -8
- package/scripts/build-sdk-package-smoke.ts +51 -0
- package/scripts/capture-notifications-settings-showcase.ts +1 -1
- package/scripts/verify-gjc-sdk-canonicalization.ts +14 -1
- package/src/cli/notify-cli.ts +215 -99
- package/src/commands/notify.ts +19 -8
- package/src/commands/sdk.ts +54 -0
- package/src/config/file-lock.ts +6 -0
- package/src/config/model-discovery-manager.ts +50 -8
- package/src/config/model-profiles.ts +8 -0
- package/src/config/model-registry.ts +866 -76
- package/src/config/resolve-config-value.ts +10 -8
- package/src/config/settings-schema.ts +25 -15
- package/src/config/settings.ts +15 -15
- package/src/discovery/agents-md.ts +76 -19
- package/src/gjc-runtime/psmux-detect.ts +12 -16
- package/src/gjc-runtime/session-state-sidecar.ts +12 -2
- package/src/gjc-runtime/tmux-sessions.ts +8 -1
- package/src/internal-urls/docs-index.generated.ts +10 -9
- package/src/main.ts +43 -7
- package/src/modes/DESIGN.md +11 -11
- package/src/modes/components/extensions/inspector-panel.ts +9 -5
- package/src/modes/components/hook-selector.ts +155 -44
- package/src/modes/components/model-selector.ts +242 -49
- package/src/modes/components/notifications-settings-editor.ts +631 -85
- package/src/modes/controllers/extension-ui-controller.ts +114 -15
- package/src/modes/controllers/selector-controller.ts +525 -93
- package/src/modes/print-mode.ts +3 -0
- package/src/modes/types.ts +6 -0
- package/src/prompts/system/system-prompt.md +1 -0
- package/src/sdk/broker/broker.ts +54 -10
- package/src/sdk/broker/lifecycle-ledger.ts +34 -1
- package/src/sdk/broker/lifecycle.ts +47 -50
- package/src/sdk/bus/chat-daemon-cli.ts +12 -5
- package/src/sdk/bus/chat-daemon-control.ts +35 -6
- package/src/sdk/bus/chat-daemon-runtime.ts +16 -2
- package/src/sdk/bus/config.ts +534 -286
- package/src/sdk/bus/daemon-paths.ts +2 -0
- package/src/sdk/bus/discord-live-provider.ts +57 -2
- package/src/sdk/bus/discord-provider.ts +21 -0
- package/src/sdk/bus/index.ts +97 -35
- package/src/sdk/bus/notification-orchestration.ts +371 -68
- package/src/sdk/bus/notification-service.ts +571 -137
- package/src/sdk/bus/session-control.ts +119 -44
- package/src/sdk/bus/slack-live-provider.ts +78 -2
- package/src/sdk/bus/slack-provider.ts +24 -0
- package/src/sdk/bus/telegram-daemon-cli.ts +9 -2
- package/src/sdk/bus/telegram-daemon-contract.ts +8 -1
- package/src/sdk/bus/telegram-daemon-control.ts +3 -3
- package/src/sdk/bus/telegram-daemon.ts +23 -15
- package/src/sdk/client/discovery.ts +10 -4
- package/src/sdk/host/query/handlers.ts +20 -1
- package/src/sdk/index.ts +1 -0
- package/src/sdk/protocol/operation-inventory.generated.json +18 -0
- package/src/sdk/protocol/operation-registry.ts +5 -2
- package/src/sdk/providers.ts +51 -0
- package/src/sdk/session-directory.ts +1 -0
- package/src/sdk/session.ts +34 -14
- package/src/session/agent-session.ts +109 -37
- package/src/session/internal/managed-session-scope.ts +981 -450
- package/src/session/internal/managed-session-storage.ts +418 -47
- package/src/session/internal/native-publish-outcome.ts +15 -3
- package/src/session/internal/session-open-errors.ts +11 -0
- package/src/session/session-manager.ts +27 -3
- package/src/session/session-storage.ts +72 -5
- package/src/slash-commands/builtin-registry.ts +117 -15
- package/src/system-prompt.ts +28 -15
- package/src/task/index.ts +9 -3
- package/src/tools/ask.ts +1 -1
- package/src/tools/bash.ts +4 -2
- package/src/tools/composer-bash-policy.ts +21 -5
- package/src/tools/telegram-send.ts +4 -2
- package/src/utils/command-args.ts +19 -30
- package/src/utils/lang-from-path.ts +2 -4
package/src/commands/sdk.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { applyStartupModelProfiles, createSessionManager } from "../main";
|
|
|
9
9
|
import { initializeExtensions } from "../modes/runtime-init";
|
|
10
10
|
import { ACP_MCP_REQUEST_TIMEOUT_MS, ACP_MCP_STARTUP_HEADROOM_MS } from "../sdk/acp/mcp";
|
|
11
11
|
import { Broker } from "../sdk/broker/broker";
|
|
12
|
+
import { readBrokerDiscovery } from "../sdk/broker/discovery";
|
|
12
13
|
import { completeBrokerProcess } from "../sdk/broker/internal";
|
|
13
14
|
import {
|
|
14
15
|
type LifecycleTranscriptEvidence,
|
|
@@ -58,6 +59,54 @@ export async function lifecycleArgs(
|
|
|
58
59
|
};
|
|
59
60
|
}
|
|
60
61
|
|
|
62
|
+
/**
|
|
63
|
+
* How long a session host tolerates the complete absence of a live broker
|
|
64
|
+
* publication before treating itself as orphaned. Hosts intentionally survive
|
|
65
|
+
* broker restarts (a replacement broker republishes discovery within seconds),
|
|
66
|
+
* so this must comfortably exceed a restart window while still bounding the
|
|
67
|
+
* lifetime of hosts whose broker is gone for good — otherwise every crashed or
|
|
68
|
+
* torn-down broker leaks a detached multi-hundred-megabyte host forever.
|
|
69
|
+
*/
|
|
70
|
+
export const SESSION_HOST_BROKER_ABSENCE_GRACE_MS = 10 * 60_000;
|
|
71
|
+
const SESSION_HOST_BROKER_POLL_MS = 15_000;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Resolves only once no live broker publication has been observable in
|
|
75
|
+
* `agentDir` for the full grace window. A reappearing broker (including a
|
|
76
|
+
* replacement with a different pid) resets the window; an unreadable
|
|
77
|
+
* publication is not proof of orphanhood but accrues against the same bound.
|
|
78
|
+
*/
|
|
79
|
+
export async function watchSessionHostBrokerLiveness(deps: {
|
|
80
|
+
agentDir: string;
|
|
81
|
+
now?: () => number;
|
|
82
|
+
sleep?: (ms: number) => Promise<void>;
|
|
83
|
+
readDiscovery?: (agentDir: string) => Promise<unknown>;
|
|
84
|
+
graceMs?: number;
|
|
85
|
+
pollMs?: number;
|
|
86
|
+
}): Promise<void> {
|
|
87
|
+
const now = deps.now ?? Date.now;
|
|
88
|
+
const sleep = deps.sleep ?? (async ms => await Bun.sleep(ms));
|
|
89
|
+
const readDiscovery = deps.readDiscovery ?? readBrokerDiscovery;
|
|
90
|
+
const graceMs = deps.graceMs ?? SESSION_HOST_BROKER_ABSENCE_GRACE_MS;
|
|
91
|
+
const pollMs = deps.pollMs ?? SESSION_HOST_BROKER_POLL_MS;
|
|
92
|
+
let absentSince: number | null = null;
|
|
93
|
+
for (;;) {
|
|
94
|
+
let live: unknown = null;
|
|
95
|
+
try {
|
|
96
|
+
live = await readDiscovery(deps.agentDir);
|
|
97
|
+
} catch {
|
|
98
|
+
// Transient read failures are ambiguity, not proof of orphanhood.
|
|
99
|
+
}
|
|
100
|
+
if (live) {
|
|
101
|
+
absentSince = null;
|
|
102
|
+
} else {
|
|
103
|
+
absentSince ??= now();
|
|
104
|
+
if (now() - absentSince >= graceMs) return;
|
|
105
|
+
}
|
|
106
|
+
await sleep(pollMs);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
61
110
|
type LifecycleTranscriptSource = {
|
|
62
111
|
cwd: string;
|
|
63
112
|
path: string;
|
|
@@ -505,6 +554,11 @@ export async function runSessionHost(
|
|
|
505
554
|
}
|
|
506
555
|
process.once("SIGTERM", stop);
|
|
507
556
|
process.once("SIGINT", stop);
|
|
557
|
+
// A detached host whose broker is gone for good would otherwise live (and
|
|
558
|
+
// hold its session's memory) forever; reap it through the same graceful
|
|
559
|
+
// teardown a SIGTERM would take once the bounded absence grace elapses.
|
|
560
|
+
await watchSessionHostBrokerLiveness({ agentDir });
|
|
561
|
+
stop();
|
|
508
562
|
await new Promise<void>(() => {});
|
|
509
563
|
}
|
|
510
564
|
|
package/src/config/file-lock.ts
CHANGED
|
@@ -17,6 +17,10 @@ const DEFAULT_OPTIONS: Required<FileLockOptions> = {
|
|
|
17
17
|
|
|
18
18
|
type LockInfo = FileLockOwnerToken;
|
|
19
19
|
|
|
20
|
+
export const FileLockTestHooks: {
|
|
21
|
+
afterParentMkdir?: (lockPath: string) => void | Promise<void>;
|
|
22
|
+
} = {};
|
|
23
|
+
|
|
20
24
|
/**
|
|
21
25
|
* Returns the OS-provided process start timestamp for PID-reuse detection.
|
|
22
26
|
* `ps` is available on the supported Unix hosts (macOS and Linux), unlike
|
|
@@ -237,6 +241,8 @@ async function removeStaleLockForAcquire(lockPath: string, snapshot: LockStaleSn
|
|
|
237
241
|
|
|
238
242
|
async function tryAcquireLock(lockPath: string): Promise<LockInfo | null> {
|
|
239
243
|
await fs.mkdir(path.dirname(lockPath), { recursive: true });
|
|
244
|
+
const afterParentMkdir = FileLockTestHooks.afterParentMkdir;
|
|
245
|
+
if (afterParentMkdir) await afterParentMkdir(lockPath);
|
|
240
246
|
try {
|
|
241
247
|
await fs.mkdir(lockPath);
|
|
242
248
|
return await writeLockInfo(lockPath);
|
|
@@ -37,6 +37,8 @@ export interface DiscoveryMergeInput {
|
|
|
37
37
|
models: readonly Model<Api>[];
|
|
38
38
|
state: ProviderDiscoveryState;
|
|
39
39
|
warning?: string;
|
|
40
|
+
authGeneration?: string;
|
|
41
|
+
fetched?: boolean;
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
export interface ProviderDiscoveryCallbacks<TProvider extends DiscoveryProvider> {
|
|
@@ -44,7 +46,9 @@ export interface ProviderDiscoveryCallbacks<TProvider extends DiscoveryProvider>
|
|
|
44
46
|
requiresAuth: (provider: TProvider) => boolean;
|
|
45
47
|
peekApiKey: (provider: TProvider) => Promise<string | undefined>;
|
|
46
48
|
isAuthenticated: (apiKey: string | undefined) => boolean;
|
|
47
|
-
fetchModels: (provider: TProvider) => Promise<Model<Api>[]>;
|
|
49
|
+
fetchModels: (provider: TProvider, apiKey: string | undefined) => Promise<Model<Api>[]>;
|
|
50
|
+
getEvidenceGeneration?: (provider: TProvider) => string;
|
|
51
|
+
canPublishCache?: (provider: TProvider) => boolean;
|
|
48
52
|
}
|
|
49
53
|
|
|
50
54
|
/** Owns configured discovery inputs, status, cache lifecycle, and refresh generations. */
|
|
@@ -89,6 +93,11 @@ export class ModelDiscoveryManager<TProvider extends DiscoveryProvider> {
|
|
|
89
93
|
const state = this.#states.get(provider);
|
|
90
94
|
return state === undefined ? undefined : this.#snapshot(state);
|
|
91
95
|
}
|
|
96
|
+
invalidate(provider: string): void {
|
|
97
|
+
this.#invalidate(provider);
|
|
98
|
+
this.#states.delete(provider);
|
|
99
|
+
this.#lastWarnings.delete(provider);
|
|
100
|
+
}
|
|
92
101
|
|
|
93
102
|
loadCached(provider: TProvider, cacheDbPath?: string): readonly Model<Api>[] {
|
|
94
103
|
const cache = readModelCache<Api>(provider.provider, 24 * 60 * 60 * 1000, Date.now, cacheDbPath);
|
|
@@ -133,9 +142,21 @@ export class ModelDiscoveryManager<TProvider extends DiscoveryProvider> {
|
|
|
133
142
|
models: models.map(model => model.id),
|
|
134
143
|
});
|
|
135
144
|
|
|
145
|
+
let authGeneration = callbacks.getEvidenceGeneration?.(provider);
|
|
146
|
+
let apiKey: string | undefined;
|
|
136
147
|
if (callbacks.requiresAuth(provider)) {
|
|
137
|
-
|
|
148
|
+
apiKey = await callbacks.peekApiKey(provider);
|
|
149
|
+
const resolvedGeneration = callbacks.getEvidenceGeneration?.(provider);
|
|
138
150
|
if (!this.isCurrent(token)) return this.#stale(token);
|
|
151
|
+
if (authGeneration !== resolvedGeneration) {
|
|
152
|
+
authGeneration = resolvedGeneration;
|
|
153
|
+
// Resolving a command-backed key can update the evidence generation. Keep
|
|
154
|
+
// the key resolved for this refresh so round-robin selection cannot switch
|
|
155
|
+
// credentials between the request and its published evidence.
|
|
156
|
+
if (!this.isCurrent(token) || authGeneration !== callbacks.getEvidenceGeneration?.(provider)) {
|
|
157
|
+
return this.#stale(token);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
139
160
|
if (!callbacks.isAuthenticated(apiKey)) return unauthenticated(cachedModels);
|
|
140
161
|
}
|
|
141
162
|
|
|
@@ -145,10 +166,14 @@ export class ModelDiscoveryManager<TProvider extends DiscoveryProvider> {
|
|
|
145
166
|
staticModels: [],
|
|
146
167
|
cacheDbPath: callbacks.cacheDbPath,
|
|
147
168
|
cacheTtlMs: 24 * 60 * 60 * 1000,
|
|
148
|
-
canPublishCache: () =>
|
|
169
|
+
canPublishCache: () =>
|
|
170
|
+
this.isCurrent(token) &&
|
|
171
|
+
(callbacks.getEvidenceGeneration === undefined ||
|
|
172
|
+
callbacks.getEvidenceGeneration(provider) === authGeneration) &&
|
|
173
|
+
(callbacks.canPublishCache?.(provider) ?? true),
|
|
149
174
|
fetchDynamicModels: async () => {
|
|
150
175
|
try {
|
|
151
|
-
return await callbacks.fetchModels(provider);
|
|
176
|
+
return await callbacks.fetchModels(provider, apiKey);
|
|
152
177
|
} catch (cause) {
|
|
153
178
|
error = cause instanceof Error ? cause.message : String(cause);
|
|
154
179
|
return null;
|
|
@@ -156,7 +181,11 @@ export class ModelDiscoveryManager<TProvider extends DiscoveryProvider> {
|
|
|
156
181
|
},
|
|
157
182
|
});
|
|
158
183
|
const result = await manager.refresh(strategy);
|
|
159
|
-
if (
|
|
184
|
+
if (
|
|
185
|
+
!this.isCurrent(token) ||
|
|
186
|
+
(callbacks.getEvidenceGeneration !== undefined && callbacks.getEvidenceGeneration(provider) !== authGeneration)
|
|
187
|
+
)
|
|
188
|
+
return this.#stale(token);
|
|
160
189
|
const status: ProviderDiscoveryStatus = error
|
|
161
190
|
? result.models.length > 0
|
|
162
191
|
? "cached"
|
|
@@ -166,7 +195,9 @@ export class ModelDiscoveryManager<TProvider extends DiscoveryProvider> {
|
|
|
166
195
|
? "cached"
|
|
167
196
|
: "idle"
|
|
168
197
|
: result.models.length > 0
|
|
169
|
-
?
|
|
198
|
+
? result.stale
|
|
199
|
+
? "cached"
|
|
200
|
+
: "ok"
|
|
170
201
|
: "empty";
|
|
171
202
|
const state: ProviderDiscoveryState = {
|
|
172
203
|
provider: provider.provider,
|
|
@@ -177,7 +208,7 @@ export class ModelDiscoveryManager<TProvider extends DiscoveryProvider> {
|
|
|
177
208
|
models: result.models.map(model => model.id),
|
|
178
209
|
error,
|
|
179
210
|
};
|
|
180
|
-
return this.#complete(token, result.models, state, error);
|
|
211
|
+
return this.#complete(token, result.models, state, error, authGeneration, result.fetched);
|
|
181
212
|
}
|
|
182
213
|
|
|
183
214
|
#complete(
|
|
@@ -185,6 +216,8 @@ export class ModelDiscoveryManager<TProvider extends DiscoveryProvider> {
|
|
|
185
216
|
models: readonly Model<Api>[],
|
|
186
217
|
state: ProviderDiscoveryState,
|
|
187
218
|
error?: string,
|
|
219
|
+
authGeneration?: string,
|
|
220
|
+
fetched?: boolean,
|
|
188
221
|
): DiscoveryMergeInput {
|
|
189
222
|
const current = this.isCurrent(token);
|
|
190
223
|
if (current) this.#states.set(token.provider, this.#snapshot(state));
|
|
@@ -193,7 +226,16 @@ export class ModelDiscoveryManager<TProvider extends DiscoveryProvider> {
|
|
|
193
226
|
if (error) this.#lastWarnings.set(token.provider, error);
|
|
194
227
|
else this.#lastWarnings.delete(token.provider);
|
|
195
228
|
}
|
|
196
|
-
return this.#snapshot({
|
|
229
|
+
return this.#snapshot({
|
|
230
|
+
provider: token.provider,
|
|
231
|
+
token,
|
|
232
|
+
current,
|
|
233
|
+
models,
|
|
234
|
+
state,
|
|
235
|
+
warning,
|
|
236
|
+
authGeneration,
|
|
237
|
+
fetched,
|
|
238
|
+
});
|
|
197
239
|
}
|
|
198
240
|
|
|
199
241
|
#stale(token: DiscoveryRefreshToken): DiscoveryMergeInput {
|
|
@@ -291,6 +291,13 @@ export const BUILTIN_MODEL_PROFILES: readonly ModelProfileDefinition[] = [
|
|
|
291
291
|
architect: "alibaba-token-plan/qwen3.8-max-preview:xhigh",
|
|
292
292
|
critic: "alibaba-token-plan/glm-5.2:high",
|
|
293
293
|
}),
|
|
294
|
+
profile("alibaba-token-plan-pro", ["alibaba-token-plan"], {
|
|
295
|
+
default: "alibaba-token-plan/qwen3.8-max-preview:medium",
|
|
296
|
+
executor: "alibaba-token-plan/deepseek-v4-flash-0731:max",
|
|
297
|
+
planner: "alibaba-token-plan/glm-5.2:high",
|
|
298
|
+
architect: "alibaba-token-plan/qwen3.8-max-preview:xhigh",
|
|
299
|
+
critic: "alibaba-token-plan/glm-5.2:xhigh",
|
|
300
|
+
}),
|
|
294
301
|
profile("alibaba-token-plan-qwenmaxxing", ["alibaba-token-plan"], {
|
|
295
302
|
default: "alibaba-token-plan/qwen3.8-max-preview:medium",
|
|
296
303
|
executor: "alibaba-token-plan/qwen3.8-max-preview:low",
|
|
@@ -361,6 +368,7 @@ const PROFILE_PRESENTATION: Record<string, ModelProfilePresentation> = {
|
|
|
361
368
|
"minimax-medium": { displayName: "MiniMax Medium", providerGroup: "MINIMAX" },
|
|
362
369
|
"minimax-pro": { displayName: "MiniMax Pro", providerGroup: "MINIMAX" },
|
|
363
370
|
"alibaba-token-plan-balanced": { displayName: "Balanced", providerGroup: "ALIBABA TOKEN PLAN" },
|
|
371
|
+
"alibaba-token-plan-pro": { displayName: "Pro", providerGroup: "ALIBABA TOKEN PLAN" },
|
|
364
372
|
"alibaba-token-plan-qwenmaxxing": { displayName: "QwenMaxxing", providerGroup: "ALIBABA TOKEN PLAN" },
|
|
365
373
|
"opus-codex": { displayName: "Opus + Codex", providerGroup: "COMBOS" },
|
|
366
374
|
"codex-opencodego": { displayName: "Codex + OpenCodeGo", providerGroup: "COMBOS" },
|