@gajae-code/coding-agent 0.12.6 → 0.12.8
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 +22 -1
- package/dist/types/async/job-manager.d.ts +36 -1
- package/dist/types/commands/notify.d.ts +4 -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/eval/backend.d.ts +2 -2
- package/dist/types/exec/bash-executor.d.ts +8 -10
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +0 -36
- package/dist/types/internal-urls/registry-helpers.d.ts +0 -18
- 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/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 -3
- package/dist/types/sdk/bus/config.d.ts +75 -113
- 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 +31 -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 +9 -4
- package/dist/types/sdk/client/discovery.d.ts +2 -1
- package/dist/types/sdk/host/host.d.ts +2 -23
- package/dist/types/sdk/host/query/handlers.d.ts +2 -0
- package/dist/types/sdk/host/reverse-leases.d.ts +4 -7
- 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/artifacts.d.ts +5 -8
- package/dist/types/session/client-bridge.d.ts +0 -14
- package/dist/types/session/internal/managed-session-scope.d.ts +17 -1
- package/dist/types/session/internal/managed-session-storage.d.ts +11 -4
- package/dist/types/session/internal/native-publish-outcome.d.ts +1 -0
- package/dist/types/session/internal/session-open-errors.d.ts +5 -0
- package/dist/types/session/messages.d.ts +1 -4
- package/dist/types/session/session-manager.d.ts +7 -6
- package/dist/types/session/session-storage.d.ts +2 -0
- package/dist/types/session/streaming-output.d.ts +0 -32
- package/dist/types/task/receipt.d.ts +1 -2
- package/dist/types/task/types.d.ts +43 -178
- package/dist/types/tools/bash.d.ts +1 -1
- package/dist/types/tools/fetch.d.ts +0 -3
- package/dist/types/tools/output-meta.d.ts +5 -37
- package/dist/types/tools/subagent.d.ts +15 -0
- package/dist/types/tools/todo-write.d.ts +3 -0
- package/dist/types/tools/tool-result.d.ts +0 -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/src/async/job-manager.ts +430 -46
- package/src/cli/notify-cli.ts +204 -94
- package/src/commands/notify.ts +19 -8
- package/src/config/file-lock.ts +6 -0
- package/src/config/model-discovery-manager.ts +50 -8
- package/src/config/model-registry.ts +862 -75
- 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/cursor.ts +13 -20
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +2 -3
- package/src/eval/backend.ts +2 -2
- package/src/exec/bash-executor.ts +151 -425
- package/src/gjc-runtime/session-state-sidecar.ts +12 -2
- package/src/gjc-runtime/ultragoal-runtime.ts +3 -280
- package/src/gjc-runtime/workflow-manifest.generated.json +1 -40
- package/src/gjc-runtime/workflow-manifest.ts +0 -12
- package/src/internal-urls/agent-protocol.ts +38 -98
- package/src/internal-urls/artifact-protocol.ts +17 -28
- package/src/internal-urls/docs-index.generated.ts +7 -7
- package/src/internal-urls/registry-helpers.ts +0 -62
- package/src/main.ts +43 -7
- package/src/modes/DESIGN.md +11 -11
- package/src/modes/acp/acp-agent.ts +0 -24
- package/src/modes/acp/acp-client-bridge.ts +11 -154
- 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 +464 -50
- package/src/prompts/tools/bash.md +2 -2
- package/src/sdk/acp/adapter.ts +9 -200
- 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 -8
- package/src/sdk/bus/chat-daemon-runtime.ts +16 -2
- package/src/sdk/bus/config.ts +534 -286
- 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 +105 -359
- package/src/sdk/bus/notification-orchestration.ts +371 -68
- package/src/sdk/bus/notification-service.ts +431 -130
- 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 +9 -4
- 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/host.ts +9 -187
- package/src/sdk/host/query/handlers.ts +20 -1
- package/src/sdk/host/reverse-leases.ts +42 -249
- 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 +10 -7
- package/src/session/agent-session.ts +59 -202
- package/src/session/artifacts.ts +74 -211
- package/src/session/client-bridge.ts +0 -15
- package/src/session/internal/managed-session-scope.ts +981 -450
- package/src/session/internal/managed-session-storage.ts +362 -124
- package/src/session/internal/native-publish-outcome.ts +3 -1
- package/src/session/internal/session-open-errors.ts +11 -0
- package/src/session/messages.ts +7 -32
- package/src/session/session-manager.ts +48 -15
- package/src/session/session-storage.ts +72 -5
- package/src/session/streaming-output.ts +40 -198
- package/src/slash-commands/builtin-registry.ts +82 -4
- package/src/task/index.ts +237 -65
- package/src/task/receipt.ts +2 -4
- package/src/task/render.ts +0 -30
- package/src/task/types.ts +10 -34
- package/src/tools/ask.ts +1 -1
- package/src/tools/bash.ts +239 -818
- package/src/tools/eval.ts +4 -99
- package/src/tools/fetch.ts +15 -77
- package/src/tools/find.ts +3 -7
- package/src/tools/output-meta.ts +114 -696
- package/src/tools/search.ts +4 -9
- package/src/tools/subagent.ts +97 -75
- package/src/tools/telegram-send.ts +4 -2
- package/src/tools/todo-write.ts +47 -0
- package/src/tools/tool-result.ts +0 -1
- package/dist/types/gjc-runtime/ultragoal-review-source.d.ts +0 -83
- package/dist/types/utils/artifact-id.d.ts +0 -2
- package/src/gjc-runtime/ultragoal-review-source.ts +0 -378
- package/src/utils/artifact-id.ts +0 -6
|
@@ -19,7 +19,7 @@ import { GJC_MODEL_ASSIGNMENT_TARGETS, type GjcModelAssignmentTargetId } from ".
|
|
|
19
19
|
import { formatModelSelectorValue } from "../../config/model-resolver";
|
|
20
20
|
import { selectorHead } from "../../config/model-selector-value";
|
|
21
21
|
import type { ModelProfileConfig } from "../../config/models-config-schema";
|
|
22
|
-
import { type Settings, settings } from "../../config/settings";
|
|
22
|
+
import { type Settings, type SettingsAtomicReceipt, settings } from "../../config/settings";
|
|
23
23
|
import { DebugSelectorComponent } from "../../debug";
|
|
24
24
|
import { disableProvider, enableProvider } from "../../discovery";
|
|
25
25
|
import { clearPluginRootsAndCaches, resolveActiveProjectRegistryPath } from "../../discovery/helpers";
|
|
@@ -50,16 +50,29 @@ import {
|
|
|
50
50
|
stopInteractiveActivityIndicator,
|
|
51
51
|
suspendInteractiveActivityIndicator,
|
|
52
52
|
} from "../../modes/types";
|
|
53
|
-
import {
|
|
53
|
+
import { ChatDaemonController } from "../../sdk/bus/chat-daemon-control";
|
|
54
|
+
import {
|
|
55
|
+
getCurrentTelegramActivationMarker,
|
|
56
|
+
getNotificationConfig,
|
|
57
|
+
isProviderEffectivelyEnabled,
|
|
58
|
+
isTelegramComplete,
|
|
59
|
+
maskToken,
|
|
60
|
+
type NotificationProvider,
|
|
61
|
+
} from "../../sdk/bus/config";
|
|
54
62
|
import {
|
|
55
63
|
clearTelegramActivationMarker,
|
|
56
64
|
createTelegramActivationMarker,
|
|
65
|
+
mutateNotificationProvider,
|
|
66
|
+
type NotificationProviderConfigurationMutation,
|
|
67
|
+
type NotificationProviderRuntimeAuthority,
|
|
57
68
|
observedTelegramActivationMarker,
|
|
58
69
|
persistTelegramActivationMarker,
|
|
59
70
|
proposedTelegramIdentity,
|
|
60
71
|
reconcileCommittedTelegramConfiguration,
|
|
72
|
+
removeNotificationProvider,
|
|
61
73
|
removeTelegramConfiguration,
|
|
62
74
|
saveTelegramInactive,
|
|
75
|
+
setGlobalNotificationsEnabled,
|
|
63
76
|
} from "../../sdk/bus/notification-orchestration";
|
|
64
77
|
import {
|
|
65
78
|
buildNotificationStatusReport,
|
|
@@ -141,6 +154,7 @@ import { JobsOverlayComponent } from "../components/jobs-overlay";
|
|
|
141
154
|
import { ModelSelectorComponent } from "../components/model-selector";
|
|
142
155
|
import type {
|
|
143
156
|
NotificationsEditorOperations,
|
|
157
|
+
PreparedNotificationProviderConfiguration,
|
|
144
158
|
PreparedTelegramConfiguration,
|
|
145
159
|
} from "../components/notifications-settings-editor";
|
|
146
160
|
import { OAuthSelectorComponent } from "../components/oauth-selector";
|
|
@@ -234,6 +248,7 @@ type TelegramDaemonStopResult = {
|
|
|
234
248
|
|
|
235
249
|
export interface NotificationsEditorOperationDependencies {
|
|
236
250
|
getNotificationConfig: typeof getNotificationConfig;
|
|
251
|
+
getCurrentTelegramActivationMarker: typeof getCurrentTelegramActivationMarker;
|
|
237
252
|
maskToken: typeof maskToken;
|
|
238
253
|
buildNotificationStatusReport: typeof buildNotificationStatusReport;
|
|
239
254
|
checkNotificationHealth: typeof checkNotificationHealth;
|
|
@@ -258,10 +273,12 @@ export interface NotificationsEditorOperationDependencies {
|
|
|
258
273
|
reloadTelegramDaemon(settings: Settings): Promise<{ ok: boolean; message: string }>;
|
|
259
274
|
restartTelegramDaemon(settings: Settings): Promise<{ ok: boolean; message: string }>;
|
|
260
275
|
stopTelegramDaemon(settings: Settings): Promise<TelegramDaemonStopResult>;
|
|
276
|
+
providerRuntime?: NotificationProviderRuntimeAuthority;
|
|
261
277
|
}
|
|
262
278
|
|
|
263
279
|
const notificationEditorOperationDependencies: NotificationsEditorOperationDependencies = {
|
|
264
280
|
getNotificationConfig,
|
|
281
|
+
getCurrentTelegramActivationMarker,
|
|
265
282
|
maskToken,
|
|
266
283
|
buildNotificationStatusReport,
|
|
267
284
|
checkNotificationHealth,
|
|
@@ -298,9 +315,9 @@ function unavailableNotificationSessionStatus(): NotificationSessionStatus {
|
|
|
298
315
|
return {
|
|
299
316
|
eligible: false,
|
|
300
317
|
locallyEnabled: true,
|
|
301
|
-
|
|
318
|
+
genericSessionEnabled: false,
|
|
319
|
+
genericEligibilitySource: "none",
|
|
302
320
|
running: false,
|
|
303
|
-
environment: "off",
|
|
304
321
|
};
|
|
305
322
|
}
|
|
306
323
|
|
|
@@ -328,6 +345,10 @@ export function createNotificationsEditorOperations(
|
|
|
328
345
|
): NotificationsEditorOperations {
|
|
329
346
|
const services = { ...notificationEditorOperationDependencies, ...overrides };
|
|
330
347
|
const drafts = new WeakMap<PreparedTelegramConfiguration, string>();
|
|
348
|
+
const providerDrafts = new WeakMap<
|
|
349
|
+
PreparedNotificationProviderConfiguration,
|
|
350
|
+
{ botToken?: string; appToken?: string }
|
|
351
|
+
>();
|
|
331
352
|
const sessionContext = () => ({ sessionManager: ctx.sessionManager });
|
|
332
353
|
const notifyAfterDurableCommit = async (): Promise<void> => {
|
|
333
354
|
await ctx.notifyConfigChanged?.();
|
|
@@ -340,12 +361,52 @@ export function createNotificationsEditorOperations(
|
|
|
340
361
|
});
|
|
341
362
|
const telegramSetupPreflight = async (): Promise<TelegramSetupPreflight> =>
|
|
342
363
|
await services.resolveTelegramSetupPreflight(ctx.settings);
|
|
364
|
+
const providerRuntime: NotificationProviderRuntimeAuthority = services.providerRuntime ?? {
|
|
365
|
+
activate: async provider => {
|
|
366
|
+
if (provider === "telegram") {
|
|
367
|
+
const result = await reconnect();
|
|
368
|
+
if (result === "blocked_identity" || result === "disabled") {
|
|
369
|
+
throw new Error("Telegram activation failed after the durable save.");
|
|
370
|
+
}
|
|
371
|
+
await ctx.session.notificationSessionController?.reconcileCurrentSession(sessionContext());
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
const result = await new ChatDaemonController(ctx.settings, provider).ensure();
|
|
375
|
+
if (result === "disabled") throw new Error(`${provider} activation failed after the durable save.`);
|
|
376
|
+
},
|
|
377
|
+
deactivate: async provider => {
|
|
378
|
+
if (provider === "telegram") {
|
|
379
|
+
const result = await services.stopTelegramDaemon(ctx.settings);
|
|
380
|
+
if (!result.ok) throw new Error(result.message);
|
|
381
|
+
await ctx.session.notificationSessionController?.reconcileCurrentSession(sessionContext());
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
const result = await new ChatDaemonController(ctx.settings, provider).stop();
|
|
385
|
+
if (!result.ok) throw new Error(result.message);
|
|
386
|
+
},
|
|
387
|
+
};
|
|
343
388
|
|
|
344
389
|
return {
|
|
345
390
|
loadState: async () => {
|
|
346
391
|
const config = services.getNotificationConfig(ctx.settings);
|
|
392
|
+
const status = services.buildNotificationStatusReport(ctx.settings);
|
|
393
|
+
const runtime = async (provider: NotificationProvider) => {
|
|
394
|
+
const daemon =
|
|
395
|
+
provider === "telegram"
|
|
396
|
+
? await new TelegramDaemonController(ctx.settings).status()
|
|
397
|
+
: await new ChatDaemonController(ctx.settings, provider).status();
|
|
398
|
+
return daemon.health === "running" ? "ready" : daemon.health === "not_configured" ? "inactive" : "failed";
|
|
399
|
+
};
|
|
400
|
+
const [telegramRuntime, discordRuntime, slackRuntime] = await Promise.all([
|
|
401
|
+
runtime("telegram"),
|
|
402
|
+
runtime("discord"),
|
|
403
|
+
runtime("slack"),
|
|
404
|
+
]);
|
|
405
|
+
status.telegram.runtime = telegramRuntime;
|
|
406
|
+
status.discord.runtime = discordRuntime;
|
|
407
|
+
status.slack.runtime = slackRuntime;
|
|
347
408
|
return {
|
|
348
|
-
status
|
|
409
|
+
status,
|
|
349
410
|
session:
|
|
350
411
|
ctx.session.notificationSessionController?.query(sessionContext()) ??
|
|
351
412
|
unavailableNotificationSessionStatus(),
|
|
@@ -362,13 +423,14 @@ export function createNotificationsEditorOperations(
|
|
|
362
423
|
};
|
|
363
424
|
},
|
|
364
425
|
|
|
365
|
-
refreshHealth: async ({ probe, signal }) => {
|
|
426
|
+
refreshHealth: async ({ probe, provider, signal }) => {
|
|
366
427
|
if (signal?.aborted) throw new Error("Notification health refresh cancelled.");
|
|
367
428
|
try {
|
|
368
429
|
const input: Parameters<typeof checkNotificationHealth>[0] & { signal?: AbortSignal } = {
|
|
369
430
|
settings: ctx.settings,
|
|
370
431
|
stateRoot: path.join(ctx.sessionManager.getCwd(), ".gjc", "state"),
|
|
371
432
|
probe,
|
|
433
|
+
provider,
|
|
372
434
|
signal,
|
|
373
435
|
};
|
|
374
436
|
const report = await services.checkNotificationHealth(input);
|
|
@@ -390,9 +452,21 @@ export function createNotificationsEditorOperations(
|
|
|
390
452
|
}
|
|
391
453
|
},
|
|
392
454
|
|
|
393
|
-
sendTest: async
|
|
455
|
+
sendTest: async provider => {
|
|
394
456
|
try {
|
|
395
|
-
const result = await services.sendNotificationTest({
|
|
457
|
+
const result = await services.sendNotificationTest({
|
|
458
|
+
settings: ctx.settings,
|
|
459
|
+
provider,
|
|
460
|
+
deps: {
|
|
461
|
+
providerRuntimeStatus: async selected => {
|
|
462
|
+
const status =
|
|
463
|
+
selected === "telegram"
|
|
464
|
+
? await new TelegramDaemonController(ctx.settings).status()
|
|
465
|
+
: await new ChatDaemonController(ctx.settings, selected).status();
|
|
466
|
+
return status.health === "running" ? "ready" : "inactive";
|
|
467
|
+
},
|
|
468
|
+
},
|
|
469
|
+
});
|
|
396
470
|
return {
|
|
397
471
|
...result,
|
|
398
472
|
detail: services.sanitizeDiagnostic(
|
|
@@ -531,12 +605,14 @@ export function createNotificationsEditorOperations(
|
|
|
531
605
|
commitConfigure: async draft => {
|
|
532
606
|
const token = drafts.get(draft);
|
|
533
607
|
if (!token) throw new Error("The Telegram setup draft expired. Re-enter the masked bot token.");
|
|
608
|
+
let receipt: SettingsAtomicReceipt | undefined;
|
|
534
609
|
try {
|
|
535
610
|
const inactiveMarkerToClear = observedTelegramActivationMarker(ctx.settings, token, draft.chatId);
|
|
536
|
-
|
|
611
|
+
receipt = await ctx.settings.commitAtomicBatch([
|
|
537
612
|
{ path: "notifications.enabled", op: "set", value: true },
|
|
538
613
|
{ path: "notifications.telegram.botToken", op: "set", value: token },
|
|
539
614
|
{ path: "notifications.telegram.chatId", op: "set", value: draft.chatId },
|
|
615
|
+
{ path: "notifications.telegram.enabled", op: "set", value: true },
|
|
540
616
|
{ path: "notifications.telegram.rich.enabled", op: "set", value: draft.richEnabled },
|
|
541
617
|
{ path: "notifications.telegram.richDraft.enabled", op: "set", value: draft.richDraftEnabled },
|
|
542
618
|
{ path: "notifications.telegram.streaming.enabled", op: "set", value: draft.streamingEnabled },
|
|
@@ -571,12 +647,20 @@ export function createNotificationsEditorOperations(
|
|
|
571
647
|
marker: activationMarker,
|
|
572
648
|
},
|
|
573
649
|
});
|
|
574
|
-
|
|
650
|
+
let observerFailed = false;
|
|
651
|
+
try {
|
|
652
|
+
await notifyAfterDurableCommit();
|
|
653
|
+
} catch {
|
|
654
|
+
observerFailed = true;
|
|
655
|
+
}
|
|
575
656
|
if (activation.status === "blocked_identity") {
|
|
576
657
|
return {
|
|
577
658
|
status: "blocked_identity" as const,
|
|
578
659
|
receipt,
|
|
579
|
-
message: services.sanitizeDiagnostic(
|
|
660
|
+
message: services.sanitizeDiagnostic(
|
|
661
|
+
`${activation.message}${observerFailed ? " The settings observer also failed after the durable commit." : ""}`,
|
|
662
|
+
token,
|
|
663
|
+
),
|
|
580
664
|
restore: async () => {
|
|
581
665
|
const restored = await activation.restore();
|
|
582
666
|
if (restored.status === "restored" || restored.status === "still_blocked") {
|
|
@@ -587,12 +671,36 @@ export function createNotificationsEditorOperations(
|
|
|
587
671
|
retainCommitted: () => activation.retainCommitted(),
|
|
588
672
|
};
|
|
589
673
|
}
|
|
674
|
+
if (activation.status === "activation_failed") {
|
|
675
|
+
return {
|
|
676
|
+
status: "activation_failed" as const,
|
|
677
|
+
receipt,
|
|
678
|
+
message: services.sanitizeDiagnostic(
|
|
679
|
+
`${activation.message}${observerFailed ? " The settings observer also failed after the durable commit." : ""}`,
|
|
680
|
+
token,
|
|
681
|
+
),
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
if (observerFailed) {
|
|
685
|
+
return {
|
|
686
|
+
status: "observer_failed" as const,
|
|
687
|
+
receipt,
|
|
688
|
+
message: "Telegram configuration was saved and activated, but the settings observer failed.",
|
|
689
|
+
};
|
|
690
|
+
}
|
|
590
691
|
return {
|
|
591
692
|
status: "saved" as const,
|
|
592
693
|
receipt,
|
|
593
694
|
message: services.sanitizeDiagnostic("Telegram configuration saved and reconciled.", token),
|
|
594
695
|
};
|
|
595
696
|
} catch (error) {
|
|
697
|
+
if (receipt) {
|
|
698
|
+
return {
|
|
699
|
+
status: "activation_failed" as const,
|
|
700
|
+
receipt,
|
|
701
|
+
message: "Telegram configuration was saved, but post-commit activation failed.",
|
|
702
|
+
};
|
|
703
|
+
}
|
|
596
704
|
throw notificationOperationError(services, error, token);
|
|
597
705
|
}
|
|
598
706
|
},
|
|
@@ -607,7 +715,15 @@ export function createNotificationsEditorOperations(
|
|
|
607
715
|
chatId: draft.chatId,
|
|
608
716
|
});
|
|
609
717
|
drafts.delete(draft);
|
|
610
|
-
|
|
718
|
+
try {
|
|
719
|
+
await notifyAfterDurableCommit();
|
|
720
|
+
} catch {
|
|
721
|
+
return {
|
|
722
|
+
status: "observer_failed" as const,
|
|
723
|
+
receipt: result.receipt,
|
|
724
|
+
message: "Telegram configuration was saved inactive, but the settings observer failed.",
|
|
725
|
+
};
|
|
726
|
+
}
|
|
611
727
|
return {
|
|
612
728
|
status: "saved_inactive" as const,
|
|
613
729
|
receipt: result.receipt,
|
|
@@ -622,28 +738,289 @@ export function createNotificationsEditorOperations(
|
|
|
622
738
|
drafts.delete(draft);
|
|
623
739
|
},
|
|
624
740
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
741
|
+
prepareProviderConfiguration: async input => {
|
|
742
|
+
const cfg = services.getNotificationConfig(ctx.settings);
|
|
743
|
+
const consumeSecret = (action: typeof input.botToken): string | undefined => {
|
|
744
|
+
if (!action.value) return undefined;
|
|
745
|
+
const value = action.value.consume();
|
|
746
|
+
return action.action === "replace" ? value : undefined;
|
|
747
|
+
};
|
|
748
|
+
const botToken = consumeSecret(input.botToken);
|
|
749
|
+
const appToken = input.appToken ? consumeSecret(input.appToken) : undefined;
|
|
750
|
+
if (input.botToken.action === "replace" && !botToken?.trim()) {
|
|
751
|
+
throw new Error("A non-blank bot token replacement is required.");
|
|
752
|
+
}
|
|
753
|
+
if (input.provider === "slack" && input.appToken?.action === "replace" && !appToken?.trim()) {
|
|
754
|
+
throw new Error("A non-blank Slack app token replacement is required.");
|
|
634
755
|
}
|
|
756
|
+
if (input.provider === "discord") {
|
|
757
|
+
const applicationId = input.applicationId?.trim() || undefined;
|
|
758
|
+
const guildId = input.guildId?.trim() || undefined;
|
|
759
|
+
const parentChannelId = input.parentChannelId?.trim() || undefined;
|
|
760
|
+
const resolvedApplicationId = applicationId ?? cfg.discord.applicationId;
|
|
761
|
+
const resolvedGuildId = guildId ?? cfg.discord.guildId;
|
|
762
|
+
const resolvedParentChannelId = parentChannelId ?? cfg.discord.parentChannelId;
|
|
763
|
+
const removesSecret = input.botToken.action === "remove";
|
|
764
|
+
if (!removesSecret && (!resolvedApplicationId || !resolvedGuildId || !resolvedParentChannelId)) {
|
|
765
|
+
throw new Error("Discord application, guild, and parent channel IDs are required.");
|
|
766
|
+
}
|
|
767
|
+
if (!removesSecret && input.botToken.action === "keep" && !cfg.discord.botToken) {
|
|
768
|
+
throw new Error("Discord has no stored bot token to keep.");
|
|
769
|
+
}
|
|
770
|
+
const draft: PreparedNotificationProviderConfiguration = {
|
|
771
|
+
provider: "discord",
|
|
772
|
+
botTokenDisposition: input.botToken.action,
|
|
773
|
+
botTokenMask: maskToken(botToken ?? cfg.discord.botToken),
|
|
774
|
+
...(applicationId === undefined ? {} : { applicationId }),
|
|
775
|
+
...(guildId === undefined ? {} : { guildId }),
|
|
776
|
+
...(parentChannelId === undefined ? {} : { parentChannelId }),
|
|
777
|
+
applicationIdDisplay: resolvedApplicationId,
|
|
778
|
+
guildIdDisplay: resolvedGuildId,
|
|
779
|
+
parentChannelIdDisplay: resolvedParentChannelId,
|
|
780
|
+
};
|
|
781
|
+
providerDrafts.set(draft, { ...(botToken === undefined ? {} : { botToken }) });
|
|
782
|
+
return draft;
|
|
783
|
+
}
|
|
784
|
+
const workspaceId = input.workspaceId?.trim() || undefined;
|
|
785
|
+
const channelId = input.channelId?.trim() || undefined;
|
|
786
|
+
const authorizedUserId = input.authorizedUserId?.trim() || undefined;
|
|
787
|
+
const resolvedWorkspaceId = workspaceId ?? cfg.slack.workspaceId;
|
|
788
|
+
const resolvedChannelId = channelId ?? cfg.slack.channelId;
|
|
789
|
+
const resolvedAuthorizedUserId = authorizedUserId ?? cfg.slack.authorizedUserId;
|
|
790
|
+
const appDisposition = input.appToken?.action ?? "keep";
|
|
791
|
+
const removesSecret = input.botToken.action === "remove" || appDisposition === "remove";
|
|
792
|
+
if (!removesSecret && (!resolvedWorkspaceId || !resolvedChannelId)) {
|
|
793
|
+
throw new Error("Slack workspace and channel IDs are required.");
|
|
794
|
+
}
|
|
795
|
+
if (!removesSecret && input.botToken.action === "keep" && !cfg.slack.botToken) {
|
|
796
|
+
throw new Error("Slack has no stored bot token to keep.");
|
|
797
|
+
}
|
|
798
|
+
if (!removesSecret && appDisposition === "keep" && !cfg.slack.appToken) {
|
|
799
|
+
throw new Error("Slack has no stored app token to keep.");
|
|
800
|
+
}
|
|
801
|
+
const draft: PreparedNotificationProviderConfiguration = {
|
|
802
|
+
provider: "slack",
|
|
803
|
+
botTokenDisposition: input.botToken.action,
|
|
804
|
+
botTokenMask: maskToken(botToken ?? cfg.slack.botToken),
|
|
805
|
+
appTokenDisposition: appDisposition,
|
|
806
|
+
appTokenMask: maskToken(appToken ?? cfg.slack.appToken),
|
|
807
|
+
...(workspaceId === undefined ? {} : { workspaceId }),
|
|
808
|
+
...(channelId === undefined ? {} : { channelId }),
|
|
809
|
+
...(authorizedUserId === undefined ? {} : { authorizedUserId }),
|
|
810
|
+
workspaceIdDisplay: resolvedWorkspaceId,
|
|
811
|
+
channelIdDisplay: resolvedChannelId,
|
|
812
|
+
authorizedUserIdDisplay: resolvedAuthorizedUserId,
|
|
813
|
+
};
|
|
814
|
+
providerDrafts.set(draft, {
|
|
815
|
+
...(botToken === undefined ? {} : { botToken }),
|
|
816
|
+
...(appToken === undefined ? {} : { appToken }),
|
|
817
|
+
});
|
|
818
|
+
return draft;
|
|
635
819
|
},
|
|
636
820
|
|
|
637
|
-
|
|
821
|
+
commitProviderConfiguration: async draft => {
|
|
822
|
+
const secrets = providerDrafts.get(draft) ?? {};
|
|
638
823
|
try {
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
824
|
+
let mutation: NotificationProviderConfigurationMutation;
|
|
825
|
+
if (draft.provider === "discord") {
|
|
826
|
+
mutation = {
|
|
827
|
+
provider: "discord",
|
|
828
|
+
botToken:
|
|
829
|
+
draft.botTokenDisposition === "replace"
|
|
830
|
+
? { action: "replace", value: secrets.botToken ?? "" }
|
|
831
|
+
: { action: draft.botTokenDisposition },
|
|
832
|
+
applicationId: draft.applicationId,
|
|
833
|
+
guildId: draft.guildId,
|
|
834
|
+
parentChannelId: draft.parentChannelId,
|
|
835
|
+
};
|
|
836
|
+
} else {
|
|
837
|
+
const appDisposition = draft.appTokenDisposition ?? "keep";
|
|
838
|
+
mutation = {
|
|
839
|
+
provider: "slack",
|
|
840
|
+
botToken:
|
|
841
|
+
draft.botTokenDisposition === "replace"
|
|
842
|
+
? { action: "replace", value: secrets.botToken ?? "" }
|
|
843
|
+
: { action: draft.botTokenDisposition },
|
|
844
|
+
appToken:
|
|
845
|
+
appDisposition === "replace"
|
|
846
|
+
? { action: "replace", value: secrets.appToken ?? "" }
|
|
847
|
+
: { action: appDisposition },
|
|
848
|
+
workspaceId: draft.workspaceId,
|
|
849
|
+
channelId: draft.channelId,
|
|
850
|
+
authorizedUserId: draft.authorizedUserId,
|
|
851
|
+
};
|
|
852
|
+
}
|
|
853
|
+
const removesSecret = draft.botTokenDisposition === "remove" || draft.appTokenDisposition === "remove";
|
|
854
|
+
const result = await mutateNotificationProvider({
|
|
855
|
+
settings: ctx.settings,
|
|
856
|
+
mutation,
|
|
857
|
+
configureAndActivate: !removesSecret,
|
|
858
|
+
...(removesSecret ? { desiredEnabled: false } : {}),
|
|
859
|
+
notifyConfigChanged: notifyAfterDurableCommit,
|
|
860
|
+
runtime: providerRuntime,
|
|
861
|
+
});
|
|
862
|
+
const outcome =
|
|
863
|
+
result.status === "commit_failed"
|
|
864
|
+
? "failed"
|
|
865
|
+
: result.status === "activation_failed" ||
|
|
866
|
+
result.status === "deactivation_failed" ||
|
|
867
|
+
result.observerFailed
|
|
868
|
+
? "degraded"
|
|
869
|
+
: "success";
|
|
870
|
+
const observerSuffix =
|
|
871
|
+
result.status !== "commit_failed" && result.observerFailed
|
|
872
|
+
? " The settings observer also failed after the durable commit."
|
|
873
|
+
: "";
|
|
874
|
+
return {
|
|
875
|
+
...(result.status === "commit_failed" ? {} : { receipt: result.receipt }),
|
|
876
|
+
outcome,
|
|
877
|
+
message:
|
|
878
|
+
(result.status === "activated"
|
|
879
|
+
? `${draft.provider} configuration saved and activated.`
|
|
880
|
+
: result.status === "activation_failed"
|
|
881
|
+
? `${draft.provider} configuration and desired intent were saved, but runtime activation failed.`
|
|
882
|
+
: result.status === "deactivation_failed"
|
|
883
|
+
? `${draft.provider} desired-off configuration was saved, but runtime deactivation failed.`
|
|
884
|
+
: result.status === "commit_failed"
|
|
885
|
+
? `${draft.provider} configuration was not saved because the CAS commit failed.`
|
|
886
|
+
: `${draft.provider} configuration saved.`) + observerSuffix,
|
|
887
|
+
};
|
|
888
|
+
} finally {
|
|
889
|
+
providerDrafts.delete(draft);
|
|
890
|
+
}
|
|
891
|
+
},
|
|
892
|
+
|
|
893
|
+
discardProviderConfiguration: draft => {
|
|
894
|
+
providerDrafts.delete(draft);
|
|
895
|
+
},
|
|
896
|
+
|
|
897
|
+
setProviderDesired: async (provider, enabled) => {
|
|
898
|
+
if (provider === "telegram" && enabled) {
|
|
899
|
+
const config = services.getNotificationConfig(ctx.settings);
|
|
900
|
+
if (services.getCurrentTelegramActivationMarker(config)) {
|
|
901
|
+
return {
|
|
902
|
+
outcome: "failed",
|
|
903
|
+
message:
|
|
904
|
+
"Telegram remains inactive because its exact activation marker must be restored or cleared after safe owner readiness.",
|
|
905
|
+
};
|
|
906
|
+
}
|
|
646
907
|
}
|
|
908
|
+
const mutation: NotificationProviderConfigurationMutation =
|
|
909
|
+
provider === "telegram"
|
|
910
|
+
? { provider, botToken: { action: "keep" } }
|
|
911
|
+
: provider === "discord"
|
|
912
|
+
? { provider, botToken: { action: "keep" } }
|
|
913
|
+
: { provider, botToken: { action: "keep" }, appToken: { action: "keep" } };
|
|
914
|
+
const result = await mutateNotificationProvider({
|
|
915
|
+
settings: ctx.settings,
|
|
916
|
+
mutation,
|
|
917
|
+
desiredEnabled: enabled,
|
|
918
|
+
notifyConfigChanged: notifyAfterDurableCommit,
|
|
919
|
+
runtime: providerRuntime,
|
|
920
|
+
});
|
|
921
|
+
const outcome =
|
|
922
|
+
result.status === "commit_failed"
|
|
923
|
+
? "failed"
|
|
924
|
+
: result.status === "activation_failed" ||
|
|
925
|
+
result.status === "deactivation_failed" ||
|
|
926
|
+
result.observerFailed
|
|
927
|
+
? "degraded"
|
|
928
|
+
: "success";
|
|
929
|
+
return {
|
|
930
|
+
...(result.status === "commit_failed" ? {} : { receipt: result.receipt }),
|
|
931
|
+
outcome,
|
|
932
|
+
message:
|
|
933
|
+
(result.status === "activation_failed"
|
|
934
|
+
? `${provider} desired intent was saved, but activation failed.`
|
|
935
|
+
: result.status === "deactivation_failed"
|
|
936
|
+
? `${provider} desired-off intent was saved, but deactivation failed.`
|
|
937
|
+
: result.status === "commit_failed"
|
|
938
|
+
? `${provider} desired intent was not saved because the CAS commit failed.`
|
|
939
|
+
: `${provider} desired intent ${enabled ? "enabled" : "disabled"}.`) +
|
|
940
|
+
(result.status !== "commit_failed" && result.observerFailed
|
|
941
|
+
? " The settings observer also failed after the durable commit."
|
|
942
|
+
: ""),
|
|
943
|
+
};
|
|
944
|
+
},
|
|
945
|
+
|
|
946
|
+
removeProvider: async provider => {
|
|
947
|
+
if (provider === "telegram") {
|
|
948
|
+
return { message: "Use the Telegram removal action to preserve root-registration fencing." };
|
|
949
|
+
}
|
|
950
|
+
const result = await removeNotificationProvider({
|
|
951
|
+
settings: ctx.settings,
|
|
952
|
+
provider,
|
|
953
|
+
runtime: providerRuntime,
|
|
954
|
+
notifyConfigChanged: notifyAfterDurableCommit,
|
|
955
|
+
});
|
|
956
|
+
const degraded =
|
|
957
|
+
result.status === "deactivation_failed" || ("observerFailed" in result && result.observerFailed);
|
|
958
|
+
return {
|
|
959
|
+
...("receipt" in result && result.receipt ? { receipt: result.receipt } : {}),
|
|
960
|
+
outcome:
|
|
961
|
+
result.status === "commit_failed" || result.status === "commit_failed_after_teardown"
|
|
962
|
+
? "failed"
|
|
963
|
+
: degraded
|
|
964
|
+
? "degraded"
|
|
965
|
+
: "success",
|
|
966
|
+
message:
|
|
967
|
+
(result.status === "removed"
|
|
968
|
+
? `${provider} configuration removed.`
|
|
969
|
+
: result.status === "deactivation_failed"
|
|
970
|
+
? `${provider} configuration was removed, but runtime deactivation failed.`
|
|
971
|
+
: `${provider} configuration removal failed.`) +
|
|
972
|
+
("observerFailed" in result && result.observerFailed
|
|
973
|
+
? " The settings observer also failed after the durable commit."
|
|
974
|
+
: ""),
|
|
975
|
+
};
|
|
976
|
+
},
|
|
977
|
+
|
|
978
|
+
enableGlobally: async () => {
|
|
979
|
+
const result = await setGlobalNotificationsEnabled({
|
|
980
|
+
settings: ctx.settings,
|
|
981
|
+
enabled: true,
|
|
982
|
+
notifyConfigChanged: notifyAfterDurableCommit,
|
|
983
|
+
runtime: providerRuntime,
|
|
984
|
+
});
|
|
985
|
+
const degraded =
|
|
986
|
+
result.status === "global_activation_partial" || ("observerFailed" in result && result.observerFailed);
|
|
987
|
+
return {
|
|
988
|
+
...(result.status === "commit_failed" ? {} : { receipt: result.receipt }),
|
|
989
|
+
outcome: result.status === "commit_failed" ? "failed" : degraded ? "degraded" : "success",
|
|
990
|
+
message:
|
|
991
|
+
(result.status === "global_activation_partial"
|
|
992
|
+
? `Global notifications were enabled, but activation failed for ${result.failed.join(", ")}.`
|
|
993
|
+
: result.status === "commit_failed"
|
|
994
|
+
? "Global notifications were not enabled because the CAS commit failed."
|
|
995
|
+
: "Global notifications enabled using stored provider intent.") +
|
|
996
|
+
(result.status !== "commit_failed" && result.observerFailed
|
|
997
|
+
? " The settings observer also failed after the durable commit."
|
|
998
|
+
: ""),
|
|
999
|
+
};
|
|
1000
|
+
},
|
|
1001
|
+
|
|
1002
|
+
disableGlobally: async () => {
|
|
1003
|
+
const result = await setGlobalNotificationsEnabled({
|
|
1004
|
+
settings: ctx.settings,
|
|
1005
|
+
enabled: false,
|
|
1006
|
+
notifyConfigChanged: notifyAfterDurableCommit,
|
|
1007
|
+
runtime: providerRuntime,
|
|
1008
|
+
});
|
|
1009
|
+
const degraded =
|
|
1010
|
+
result.status === "global_deactivation_partial" || ("observerFailed" in result && result.observerFailed);
|
|
1011
|
+
return {
|
|
1012
|
+
...(result.status === "commit_failed" ? {} : { receipt: result.receipt }),
|
|
1013
|
+
outcome: result.status === "commit_failed" ? "failed" : degraded ? "degraded" : "success",
|
|
1014
|
+
message:
|
|
1015
|
+
(result.status === "global_deactivation_partial"
|
|
1016
|
+
? `Global notifications were disabled, but teardown failed for ${result.failed.join(", ")}.`
|
|
1017
|
+
: result.status === "commit_failed"
|
|
1018
|
+
? "Global notifications were not disabled because the CAS commit failed."
|
|
1019
|
+
: "Global notifications disabled; provider configuration and desired intent were preserved.") +
|
|
1020
|
+
(result.status !== "commit_failed" && result.observerFailed
|
|
1021
|
+
? " The settings observer also failed after the durable commit."
|
|
1022
|
+
: ""),
|
|
1023
|
+
};
|
|
647
1024
|
},
|
|
648
1025
|
|
|
649
1026
|
removeTelegram: async () => {
|
|
@@ -676,17 +1053,27 @@ export function createNotificationsEditorOperations(
|
|
|
676
1053
|
},
|
|
677
1054
|
},
|
|
678
1055
|
});
|
|
1056
|
+
const postCommitFailures: string[] = [];
|
|
679
1057
|
if (runtimePrepared && controller) {
|
|
680
|
-
|
|
681
|
-
|
|
1058
|
+
try {
|
|
1059
|
+
await controller.clearBlockedRuntime(sessionContext());
|
|
1060
|
+
await controller.reconcileCurrentSession(sessionContext());
|
|
1061
|
+
} catch {
|
|
1062
|
+
postCommitFailures.push("current-session reconciliation failed");
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
try {
|
|
1066
|
+
await notifyAfterDurableCommit();
|
|
1067
|
+
} catch {
|
|
1068
|
+
postCommitFailures.push("settings observer failed");
|
|
682
1069
|
}
|
|
683
|
-
await notifyAfterDurableCommit();
|
|
684
1070
|
return {
|
|
685
1071
|
receipt: result.receipt,
|
|
1072
|
+
outcome: postCommitFailures.length === 0 ? "success" : "degraded",
|
|
686
1073
|
globallyDisabled: result.globallyDisabled,
|
|
687
|
-
message:
|
|
688
|
-
? "
|
|
689
|
-
|
|
1074
|
+
message: `Telegram configuration removed without changing the global master.${
|
|
1075
|
+
postCommitFailures.length === 0 ? "" : ` Post-commit ${postCommitFailures.join(" and ")}.`
|
|
1076
|
+
}`,
|
|
690
1077
|
};
|
|
691
1078
|
} catch (error) {
|
|
692
1079
|
if (runtimePrepared) {
|
|
@@ -715,7 +1102,10 @@ export function createNotificationsEditorOperations(
|
|
|
715
1102
|
try {
|
|
716
1103
|
const before = services.getNotificationConfig(ctx.settings);
|
|
717
1104
|
const disablingToolActivity =
|
|
718
|
-
|
|
1105
|
+
isProviderEffectivelyEnabled(before, "telegram") &&
|
|
1106
|
+
isTelegramComplete(before) &&
|
|
1107
|
+
before.toolActivity.enabled &&
|
|
1108
|
+
!preferences.toolActivityEnabled;
|
|
719
1109
|
if (disablingToolActivity) {
|
|
720
1110
|
const stopped = await services.stopTelegramDaemon(ctx.settings);
|
|
721
1111
|
if (!stopped.ok)
|
|
@@ -725,7 +1115,7 @@ export function createNotificationsEditorOperations(
|
|
|
725
1115
|
daemonWasRunningForDisable = stopped.before?.health === "running";
|
|
726
1116
|
}
|
|
727
1117
|
|
|
728
|
-
let receipt:
|
|
1118
|
+
let receipt: SettingsAtomicReceipt;
|
|
729
1119
|
try {
|
|
730
1120
|
receipt = await ctx.settings.commitAtomicBatch([
|
|
731
1121
|
{ path: "notifications.redact", op: "set", value: preferences.redact },
|
|
@@ -758,16 +1148,31 @@ export function createNotificationsEditorOperations(
|
|
|
758
1148
|
throw error;
|
|
759
1149
|
}
|
|
760
1150
|
|
|
1151
|
+
const postCommitFailures: string[] = [];
|
|
761
1152
|
const config = services.getNotificationConfig(ctx.settings);
|
|
762
|
-
if (
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
1153
|
+
if (isProviderEffectivelyEnabled(config, "telegram") && isTelegramComplete(config)) {
|
|
1154
|
+
try {
|
|
1155
|
+
const reload = daemonWasRunningForDisable
|
|
1156
|
+
? await services.restartTelegramDaemon(ctx.settings)
|
|
1157
|
+
: await services.reloadTelegramDaemon(ctx.settings);
|
|
1158
|
+
if (!reload.ok) postCommitFailures.push(`daemon reload failed: ${reload.message}`);
|
|
1159
|
+
} catch {
|
|
1160
|
+
postCommitFailures.push("daemon reload failed");
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
try {
|
|
1164
|
+
await notifyAfterDurableCommit();
|
|
1165
|
+
} catch {
|
|
1166
|
+
postCommitFailures.push("settings observer failed");
|
|
768
1167
|
}
|
|
769
|
-
|
|
770
|
-
|
|
1168
|
+
return {
|
|
1169
|
+
receipt,
|
|
1170
|
+
outcome: postCommitFailures.length === 0 ? "success" : "degraded",
|
|
1171
|
+
message:
|
|
1172
|
+
postCommitFailures.length === 0
|
|
1173
|
+
? "Notification preferences saved atomically."
|
|
1174
|
+
: `Notification preferences were saved, but post-commit ${postCommitFailures.join(" and ")}.`,
|
|
1175
|
+
};
|
|
771
1176
|
} catch (error) {
|
|
772
1177
|
throw notificationOperationError(services, error, services.getNotificationConfig(ctx.settings).botToken);
|
|
773
1178
|
}
|
|
@@ -2544,6 +2949,9 @@ export class SelectorController {
|
|
|
2544
2949
|
this.ctx.showStatus(`Logging in to ${providerId}…`);
|
|
2545
2950
|
const manualInput = this.ctx.oauthManualInput;
|
|
2546
2951
|
const useManualInput = CALLBACK_SERVER_PROVIDERS.has(providerId as OAuthProvider);
|
|
2952
|
+
if (providerId === "opencodex") {
|
|
2953
|
+
this.ctx.showStatus("Checking the local OpenCodex proxy…");
|
|
2954
|
+
}
|
|
2547
2955
|
try {
|
|
2548
2956
|
await this.ctx.session.modelRegistry.authStorage.login(providerId as OAuthProvider, {
|
|
2549
2957
|
onAuth: (info: { url: string; instructions?: string }) => {
|
|
@@ -2592,11 +3000,17 @@ export class SelectorController {
|
|
|
2592
3000
|
});
|
|
2593
3001
|
await this.ctx.session.modelRegistry.refresh();
|
|
2594
3002
|
this.ctx.chatContainer.addChild(new Spacer(1));
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
3003
|
+
const successMessage =
|
|
3004
|
+
providerId === "opencodex"
|
|
3005
|
+
? `${theme.status.success} OpenCodex proxy status checked`
|
|
3006
|
+
: `${theme.status.success} Successfully logged in to ${providerId}`;
|
|
3007
|
+
this.ctx.chatContainer.addChild(new Text(theme.fg("success", successMessage), 1, 0));
|
|
3008
|
+
if (providerId !== "opencodex") {
|
|
3009
|
+
this.ctx.chatContainer.addChild(
|
|
3010
|
+
new Text(theme.fg("dim", `Credentials saved to ${getAgentDbPath()}`), 1, 0),
|
|
3011
|
+
);
|
|
3012
|
+
await this.#handlePostLoginModelProfileRecommendation(providerId);
|
|
3013
|
+
}
|
|
2600
3014
|
this.ctx.ui.requestRender();
|
|
2601
3015
|
} catch (error: unknown) {
|
|
2602
3016
|
this.ctx.showError(`Login failed: ${error instanceof Error ? error.message : String(error)}`);
|