@gajae-code/coding-agent 0.12.11 → 0.12.13
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 +68 -0
- package/dist/types/cli/marketplace-hint.d.ts +28 -0
- package/dist/types/cli/notify-cli.d.ts +42 -1
- package/dist/types/cli/update-cli.d.ts +9 -3
- package/dist/types/cli.d.ts +10 -0
- package/dist/types/commands/notify.d.ts +6 -0
- package/dist/types/config/file-lock-gc.d.ts +13 -1
- package/dist/types/config/file-lock.d.ts +3 -0
- package/dist/types/config/model-registry.d.ts +6 -0
- package/dist/types/config/models-config-schema.d.ts +99 -0
- package/dist/types/coordinator/contract.d.ts +1 -1
- package/dist/types/coordinator-mcp/question-state.d.ts +3 -1
- package/dist/types/extensibility/extensions/index.d.ts +1 -0
- package/dist/types/extensibility/extensions/ouroboros-ooo-bridge.d.ts +13 -0
- package/dist/types/extensibility/extensions/prefix-command-bridge.d.ts +0 -1
- package/dist/types/extensibility/extensions/types.d.ts +2 -0
- package/dist/types/gjc-runtime/deep-interview-state.d.ts +14 -0
- package/dist/types/gjc-runtime/gc-runtime.d.ts +11 -0
- package/dist/types/main.d.ts +6 -2
- package/dist/types/modes/acp/acp-agent.d.ts +24 -1
- package/dist/types/modes/components/session-selector.d.ts +1 -1
- package/dist/types/modes/utils/host-status.d.ts +23 -0
- package/dist/types/runtime-mcp/types.d.ts +2 -0
- package/dist/types/sdk/broker/lifecycle.d.ts +12 -0
- package/dist/types/sdk/bus/chat-daemon-cli.d.ts +3 -0
- package/dist/types/sdk/bus/chat-daemon-command-channel.d.ts +244 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +11 -1
- package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +7 -0
- package/dist/types/sdk/bus/control-plane-frames.d.ts +43 -0
- package/dist/types/sdk/bus/conversation-store.d.ts +18 -0
- package/dist/types/sdk/bus/existing-thread-readiness.d.ts +71 -0
- package/dist/types/sdk/bus/html-format.d.ts +10 -0
- package/dist/types/sdk/bus/notification-service.d.ts +10 -0
- package/dist/types/sdk/bus/slack-daemon.d.ts +27 -0
- package/dist/types/sdk/bus/slack-live-provider.d.ts +11 -0
- package/dist/types/sdk/bus/slack-provider.d.ts +14 -0
- package/dist/types/sdk/bus/slack-thread-binding.d.ts +140 -0
- package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +2 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +28 -7
- package/dist/types/sdk/bus/telegram-daemon.d.ts +119 -17
- package/dist/types/sdk/bus/telegram-reference.d.ts +20 -1
- package/dist/types/sdk/bus/topic-registry.d.ts +130 -85
- package/dist/types/sdk/host/host.d.ts +52 -0
- package/dist/types/sdk/lifecycle-session.d.ts +6 -0
- package/dist/types/sdk/session-activation.d.ts +41 -0
- package/dist/types/sdk/session.d.ts +18 -0
- package/dist/types/sdk/startup-capability.d.ts +8 -1
- package/dist/types/session/agent-session.d.ts +7 -2
- package/dist/types/session/artifacts.d.ts +2 -2
- package/dist/types/session/session-manager.d.ts +40 -6
- package/dist/types/tools/index.d.ts +15 -0
- package/dist/types/utils/npm-registry.d.ts +71 -0
- package/examples/extensions/README.md +38 -4
- package/examples/extensions/ooo-bridge.ts +15 -0
- package/package.json +8 -8
- package/scripts/generate-sdk-operation-inventory.ts +4 -0
- package/src/async/job-manager.ts +9 -2
- package/src/cli/fast-help.ts +1 -0
- package/src/cli/marketplace-hint.ts +39 -0
- package/src/cli/notify-cli.ts +226 -2
- package/src/cli/plugin-cli.ts +10 -0
- package/src/cli/update-cli.ts +90 -23
- package/src/cli.ts +23 -0
- package/src/commands/notify.ts +27 -3
- package/src/commands/sdk.ts +1 -0
- package/src/config/file-lock-gc.ts +65 -26
- package/src/config/file-lock.ts +61 -16
- package/src/config/model-profiles.ts +46 -30
- package/src/config/model-registry.ts +17 -5
- package/src/config/models-config-schema.ts +9 -4
- package/src/coordinator/contract.ts +1 -0
- package/src/coordinator-mcp/question-state.ts +2 -0
- package/src/coordinator-mcp/server.ts +358 -7
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +1 -1
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +2 -0
- package/src/extensibility/extensions/index.ts +1 -0
- package/src/extensibility/extensions/ouroboros-ooo-bridge.ts +235 -0
- package/src/extensibility/extensions/prefix-command-bridge.ts +4 -9
- package/src/extensibility/extensions/runner.ts +15 -2
- package/src/extensibility/extensions/types.ts +2 -0
- package/src/gjc-runtime/deep-interview-recorder.ts +9 -5
- package/src/gjc-runtime/deep-interview-state.ts +27 -3
- package/src/gjc-runtime/gc-render.ts +8 -1
- package/src/gjc-runtime/gc-runtime.ts +15 -1
- package/src/gjc-runtime/launch-tmux.ts +53 -1
- package/src/internal-urls/docs-index.generated.ts +14 -13
- package/src/main.ts +214 -70
- package/src/modes/DESIGN.md +8 -5
- package/src/modes/acp/acp-agent.ts +123 -7
- package/src/modes/components/footer.ts +10 -18
- package/src/modes/components/model-selector.ts +52 -5
- package/src/modes/components/session-selector.ts +26 -3
- package/src/modes/components/status-line/gh.ts +23 -2
- package/src/modes/controllers/event-controller.ts +3 -0
- package/src/modes/controllers/extension-ui-controller.ts +2 -0
- package/src/modes/controllers/input-controller.ts +11 -0
- package/src/modes/controllers/selector-controller.ts +8 -2
- package/src/modes/interactive-mode.ts +7 -1
- package/src/modes/print-mode.ts +10 -0
- package/src/modes/utils/host-status.ts +38 -0
- package/src/prompts/system/project-prompt.md +19 -0
- package/src/runtime-mcp/types.ts +2 -0
- package/src/sdk/broker/lifecycle.ts +60 -3
- package/src/sdk/bus/chat-daemon-cli.ts +42 -0
- package/src/sdk/bus/chat-daemon-command-channel.ts +921 -0
- package/src/sdk/bus/chat-daemon-control.ts +16 -3
- package/src/sdk/bus/chat-daemon-runtime.ts +257 -21
- package/src/sdk/bus/control-plane-frames.ts +51 -0
- package/src/sdk/bus/conversation-store.ts +29 -1
- package/src/sdk/bus/existing-thread-readiness.ts +155 -0
- package/src/sdk/bus/html-format.ts +19 -3
- package/src/sdk/bus/index.ts +91 -12
- package/src/sdk/bus/notification-service.ts +28 -1
- package/src/sdk/bus/rich-render.ts +3 -2
- package/src/sdk/bus/slack-daemon.ts +99 -4
- package/src/sdk/bus/slack-live-provider.ts +32 -2
- package/src/sdk/bus/slack-provider.ts +11 -0
- package/src/sdk/bus/slack-thread-binding.ts +641 -0
- package/src/sdk/bus/telegram-daemon-cli.ts +11 -0
- package/src/sdk/bus/telegram-daemon-contract.ts +28 -7
- package/src/sdk/bus/telegram-daemon.ts +2007 -509
- package/src/sdk/bus/telegram-reference.ts +114 -15
- package/src/sdk/bus/topic-registry.ts +674 -181
- package/src/sdk/host/host.ts +180 -1
- package/src/sdk/lifecycle-session.ts +8 -2
- package/src/sdk/protocol/operation-inventory.generated.json +22 -0
- package/src/sdk/session-activation.ts +127 -0
- package/src/sdk/session.ts +144 -29
- package/src/sdk/startup-capability.ts +10 -1
- package/src/session/agent-session.ts +220 -13
- package/src/session/artifacts.ts +56 -13
- package/src/session/internal/managed-session-storage.ts +228 -7
- package/src/session/session-manager.ts +225 -60
- package/src/setup/provider-presets.json +3 -3
- package/src/task/index.ts +92 -44
- package/src/thinking-metadata.ts +2 -1
- package/src/tools/ask.ts +10 -0
- package/src/tools/index.ts +15 -0
- package/src/tools/todo-write.ts +4 -4
- package/src/utils/npm-registry.ts +660 -0
|
@@ -14,12 +14,15 @@
|
|
|
14
14
|
* Dependency-free: uses global `fetch` and `WebSocket` (Bun/Node 22+).
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import * as crypto from "node:crypto";
|
|
17
18
|
import * as fs from "node:fs";
|
|
19
|
+
import { logger } from "@gajae-code/utils";
|
|
18
20
|
import {
|
|
19
21
|
bold,
|
|
20
22
|
buildCompactChoiceGrid,
|
|
21
23
|
escapeHtml,
|
|
22
24
|
numberedOptionList,
|
|
25
|
+
renumberableOptionText,
|
|
23
26
|
splitTelegramHtml,
|
|
24
27
|
TELEGRAM_PARSE_MODE,
|
|
25
28
|
} from "./html-format";
|
|
@@ -33,6 +36,44 @@ const REFERENCE_CLIENT_HELLO = {
|
|
|
33
36
|
capabilities: ["ask_controls_v1"],
|
|
34
37
|
} as const;
|
|
35
38
|
|
|
39
|
+
const MAX_DIAGNOSTIC_CAPABILITIES = 4;
|
|
40
|
+
const MAX_DIAGNOSTIC_CAPABILITY_CODE_POINTS = 64;
|
|
41
|
+
const MAX_DIAGNOSTIC_ERROR_NAME_CODE_POINTS = 64;
|
|
42
|
+
const MAX_DIAGNOSTIC_ERROR_MESSAGE_CODE_POINTS = 128;
|
|
43
|
+
|
|
44
|
+
function boundedDiagnosticText(value: string, maxCodePoints: number): string {
|
|
45
|
+
let result = "";
|
|
46
|
+
let codePoints = 0;
|
|
47
|
+
for (const character of value) {
|
|
48
|
+
const codePoint = character.codePointAt(0)!;
|
|
49
|
+
if (codePoint <= 0x1f || (codePoint >= 0x7f && codePoint <= 0x9f)) continue;
|
|
50
|
+
result += character;
|
|
51
|
+
codePoints++;
|
|
52
|
+
if (codePoints === maxCodePoints) break;
|
|
53
|
+
}
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function boundedDiagnosticCallbackError(error: unknown): Readonly<{ errorName: string; errorMessage: string }> {
|
|
58
|
+
let errorName = "UnknownError";
|
|
59
|
+
let errorMessage = "Diagnostic callback threw";
|
|
60
|
+
try {
|
|
61
|
+
if (error instanceof Error) {
|
|
62
|
+
errorName = boundedDiagnosticText(error.name, MAX_DIAGNOSTIC_ERROR_NAME_CODE_POINTS) || "Error";
|
|
63
|
+
errorMessage =
|
|
64
|
+
boundedDiagnosticText(error.message, MAX_DIAGNOSTIC_ERROR_MESSAGE_CODE_POINTS) ||
|
|
65
|
+
"Diagnostic callback threw";
|
|
66
|
+
} else {
|
|
67
|
+
errorMessage =
|
|
68
|
+
boundedDiagnosticText(String(error), MAX_DIAGNOSTIC_ERROR_MESSAGE_CODE_POINTS) ||
|
|
69
|
+
"Diagnostic callback threw";
|
|
70
|
+
}
|
|
71
|
+
} catch {
|
|
72
|
+
// Hostile thrown values must not escape the diagnostic failure boundary.
|
|
73
|
+
}
|
|
74
|
+
return Object.freeze({ errorName, errorMessage });
|
|
75
|
+
}
|
|
76
|
+
|
|
36
77
|
/** One inline-keyboard button. */
|
|
37
78
|
export interface InlineButton {
|
|
38
79
|
text: string;
|
|
@@ -85,18 +126,27 @@ export interface CallbackRoute {
|
|
|
85
126
|
sessionId: string;
|
|
86
127
|
actionId: string;
|
|
87
128
|
answer: TelegramCallbackAnswer;
|
|
129
|
+
/** Durable audit metadata only; never sufficient to route a callback after restart. */
|
|
130
|
+
chatId?: string;
|
|
131
|
+
messageId?: number;
|
|
132
|
+
ownerId?: string;
|
|
133
|
+
generation?: number;
|
|
88
134
|
}
|
|
89
135
|
|
|
90
136
|
export interface SerializedAliasTable {
|
|
91
|
-
version: 1;
|
|
137
|
+
version: 1 | 2;
|
|
92
138
|
next: number;
|
|
93
139
|
routes: Record<string, CallbackRoute>;
|
|
94
140
|
}
|
|
95
141
|
|
|
96
142
|
export interface AliasTable {
|
|
143
|
+
allocate(isReserved?: (alias: string) => boolean): string;
|
|
144
|
+
activate(alias: string, route: CallbackRoute): boolean;
|
|
97
145
|
put(route: CallbackRoute): string;
|
|
98
146
|
get(alias: string): CallbackRoute | undefined;
|
|
147
|
+
update(alias: string, patch: Partial<CallbackRoute>): boolean;
|
|
99
148
|
delete(alias: string): boolean;
|
|
149
|
+
clear(): void;
|
|
100
150
|
serialize(): SerializedAliasTable;
|
|
101
151
|
load(json: unknown): void;
|
|
102
152
|
entries(): Array<[string, CallbackRoute]>;
|
|
@@ -112,7 +162,11 @@ function isCallbackRoute(value: unknown): value is CallbackRoute {
|
|
|
112
162
|
typeof route.answer === "number" ||
|
|
113
163
|
(typeof route.answer === "object" &&
|
|
114
164
|
route.answer !== null &&
|
|
115
|
-
(route.answer as { controlId?: unknown }).controlId === "navigation_forward"))
|
|
165
|
+
(route.answer as { controlId?: unknown }).controlId === "navigation_forward")) &&
|
|
166
|
+
(route.chatId === undefined || typeof route.chatId === "string") &&
|
|
167
|
+
(route.messageId === undefined || (Number.isSafeInteger(route.messageId) && route.messageId > 0)) &&
|
|
168
|
+
(route.ownerId === undefined || typeof route.ownerId === "string") &&
|
|
169
|
+
(route.generation === undefined || (Number.isSafeInteger(route.generation) && route.generation >= 0))
|
|
116
170
|
);
|
|
117
171
|
}
|
|
118
172
|
|
|
@@ -121,24 +175,46 @@ export function createAliasTable(): AliasTable {
|
|
|
121
175
|
let next = 1;
|
|
122
176
|
const routes = new Map<string, CallbackRoute>();
|
|
123
177
|
return {
|
|
124
|
-
|
|
178
|
+
allocate(isReserved) {
|
|
125
179
|
let alias: string;
|
|
126
180
|
do {
|
|
127
|
-
|
|
128
|
-
|
|
181
|
+
// `b1_` is intentionally disjoint from every legacy sequential `aN`
|
|
182
|
+
// token, including accepted keyboards lost before their old daemon
|
|
183
|
+
// could persist them.
|
|
184
|
+
alias = `b1_${crypto.randomBytes(18).toString("base64url")}`;
|
|
185
|
+
} while (routes.has(alias) || isReserved?.(alias) === true);
|
|
186
|
+
next++;
|
|
129
187
|
if (Buffer.byteLength(alias, "utf8") > 64) throw new Error("callback alias exceeded Telegram limit");
|
|
188
|
+
return alias;
|
|
189
|
+
},
|
|
190
|
+
activate(alias, route) {
|
|
191
|
+
if (routes.has(alias) || Buffer.byteLength(alias, "utf8") > 64 || !isCallbackRoute(route)) return false;
|
|
130
192
|
routes.set(alias, { ...route });
|
|
193
|
+
return true;
|
|
194
|
+
},
|
|
195
|
+
put(route) {
|
|
196
|
+
const alias = this.allocate();
|
|
197
|
+
if (!this.activate(alias, route)) throw new Error("callback alias activation failed");
|
|
131
198
|
return alias;
|
|
132
199
|
},
|
|
133
200
|
get(alias) {
|
|
134
201
|
const route = routes.get(alias);
|
|
135
202
|
return route ? { ...route } : undefined;
|
|
136
203
|
},
|
|
204
|
+
update(alias, patch) {
|
|
205
|
+
const route = routes.get(alias);
|
|
206
|
+
if (!route) return false;
|
|
207
|
+
routes.set(alias, { ...route, ...patch });
|
|
208
|
+
return true;
|
|
209
|
+
},
|
|
137
210
|
delete(alias) {
|
|
138
211
|
return routes.delete(alias);
|
|
139
212
|
},
|
|
213
|
+
clear() {
|
|
214
|
+
routes.clear();
|
|
215
|
+
},
|
|
140
216
|
serialize() {
|
|
141
|
-
return { version:
|
|
217
|
+
return { version: 2, next, routes: Object.fromEntries(routes.entries()) };
|
|
142
218
|
},
|
|
143
219
|
load(json) {
|
|
144
220
|
routes.clear();
|
|
@@ -218,7 +294,7 @@ export function buildActionMarkdown(action: {
|
|
|
218
294
|
const options = action.options ?? [];
|
|
219
295
|
const displayOptions = withRecommendedOptionLabel(options, action.recommendedIndex);
|
|
220
296
|
if (options.length === 0) return `${heading}\n\n(reply with text)`;
|
|
221
|
-
const list = displayOptions.map((label, i) => `${i + 1}. ${label
|
|
297
|
+
const list = displayOptions.map((label, i) => `${i + 1}. ${renumberableOptionText(label)}`).join("\n");
|
|
222
298
|
return `${heading}\n\n${list}`;
|
|
223
299
|
}
|
|
224
300
|
|
|
@@ -370,6 +446,12 @@ export function readEndpoint(path: string): { url: string; token: string; pid?:
|
|
|
370
446
|
};
|
|
371
447
|
}
|
|
372
448
|
|
|
449
|
+
/** A bounded, diagnostic-only notification mirrored to reference-client embedders. */
|
|
450
|
+
export type TelegramReferenceDiagnostic = Readonly<{
|
|
451
|
+
code: "action_unavailable";
|
|
452
|
+
requiredCapabilities: readonly string[];
|
|
453
|
+
}>;
|
|
454
|
+
|
|
373
455
|
/** Options for {@link runTelegramReferenceClient}. */
|
|
374
456
|
export interface TelegramReferenceOptions {
|
|
375
457
|
botToken: string;
|
|
@@ -378,6 +460,11 @@ export interface TelegramReferenceOptions {
|
|
|
378
460
|
apiBase?: string;
|
|
379
461
|
fetchImpl?: typeof fetch;
|
|
380
462
|
sound?: TelegramNotificationSound;
|
|
463
|
+
/**
|
|
464
|
+
* Additive mirror of bounded logger diagnostics. It never receives tokens,
|
|
465
|
+
* identifiers, raw frames, Telegram content, or WebSocket replies.
|
|
466
|
+
*/
|
|
467
|
+
onDiagnostic?: (diagnostic: TelegramReferenceDiagnostic) => void;
|
|
381
468
|
}
|
|
382
469
|
|
|
383
470
|
/**
|
|
@@ -434,15 +521,27 @@ export async function runTelegramReferenceClient(opts: TelegramReferenceOptions)
|
|
|
434
521
|
msg.kind ?? "ask",
|
|
435
522
|
);
|
|
436
523
|
} else if (msg.type === "action_unavailable") {
|
|
437
|
-
const requiredCapabilities =
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
`Telegram reference client: server withheld a controlled ask because this client lacks requiredCapabilities=[${requiredCapabilities.join(", ") || "unspecified"}].`,
|
|
524
|
+
const requiredCapabilities = Object.freeze(
|
|
525
|
+
Array.isArray(msg.requiredCapabilities)
|
|
526
|
+
? msg.requiredCapabilities
|
|
527
|
+
.filter((capability): capability is string => typeof capability === "string")
|
|
528
|
+
.slice(0, MAX_DIAGNOSTIC_CAPABILITIES)
|
|
529
|
+
.map(capability => boundedDiagnosticText(capability, MAX_DIAGNOSTIC_CAPABILITY_CODE_POINTS))
|
|
530
|
+
: [],
|
|
445
531
|
);
|
|
532
|
+
const diagnostic: TelegramReferenceDiagnostic = Object.freeze({
|
|
533
|
+
code: "action_unavailable",
|
|
534
|
+
requiredCapabilities,
|
|
535
|
+
});
|
|
536
|
+
logger.warn("Telegram reference client action unavailable", diagnostic);
|
|
537
|
+
try {
|
|
538
|
+
opts.onDiagnostic?.(diagnostic);
|
|
539
|
+
} catch (error) {
|
|
540
|
+
logger.warn("Telegram reference client diagnostic callback failed", {
|
|
541
|
+
code: "diagnostic_callback_failed",
|
|
542
|
+
...boundedDiagnosticCallbackError(error),
|
|
543
|
+
});
|
|
544
|
+
}
|
|
446
545
|
// Diagnostic only: never turn it into a Telegram prompt or option buttons.
|
|
447
546
|
return;
|
|
448
547
|
} else if (msg.type === "action_resolved" && msg.id === latestPendingAskId) {
|