@gajae-code/coding-agent 0.8.0 → 0.8.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 +48 -0
- package/dist/types/cli/completion-cli.d.ts +41 -0
- package/dist/types/cli/config-cli.d.ts +1 -0
- package/dist/types/cli/notify-cli.d.ts +7 -0
- package/dist/types/cli.d.ts +124 -1
- package/dist/types/commands/completion.d.ts +29 -0
- package/dist/types/commands/config.d.ts +3 -0
- package/dist/types/commands/deep-interview.d.ts +3 -0
- package/dist/types/config/file-lock.d.ts +7 -6
- package/dist/types/config/keybindings.d.ts +2 -2
- package/dist/types/config/model-profile-activation.d.ts +6 -0
- package/dist/types/config/settings.d.ts +8 -0
- package/dist/types/extensibility/extensions/runner.d.ts +2 -1
- package/dist/types/extensibility/extensions/types.d.ts +8 -0
- package/dist/types/gjc-runtime/deep-interview-ambiguity.d.ts +39 -0
- package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +10 -1
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +1 -1
- package/dist/types/gjc-runtime/deep-interview-state.d.ts +12 -0
- package/dist/types/gjc-runtime/team-runtime.d.ts +2 -1
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +1 -0
- package/dist/types/main.d.ts +4 -1
- package/dist/types/modes/components/model-selector.d.ts +4 -0
- package/dist/types/modes/components/queued-message-selector.d.ts +12 -0
- package/dist/types/modes/components/settings-selector.d.ts +2 -0
- package/dist/types/modes/controllers/input-controller.d.ts +1 -3
- package/dist/types/modes/print-mode.d.ts +13 -1
- package/dist/types/modes/prompt-action-autocomplete.d.ts +1 -1
- package/dist/types/notifications/config.d.ts +8 -1
- package/dist/types/notifications/daemon-paths.d.ts +1 -0
- package/dist/types/notifications/index.d.ts +6 -3
- package/dist/types/notifications/lifecycle-commands.d.ts +11 -3
- package/dist/types/notifications/telegram-daemon.d.ts +18 -3
- package/dist/types/notifications/telegram-reference.d.ts +0 -5
- package/dist/types/runtime-api-key.d.ts +7 -0
- package/dist/types/session/agent-session.d.ts +10 -0
- package/dist/types/session/agent-storage.d.ts +1 -0
- package/dist/types/task/executor.d.ts +2 -0
- package/dist/types/tools/computer.d.ts +2 -2
- package/dist/types/tools/skill.d.ts +1 -1
- package/dist/types/workflow/workflow-intent-diff.d.ts +8 -2
- package/dist/types/workflow/workflow-intent-report-consumer.d.ts +50 -0
- package/dist/types/workflow/workflow-intent-report-schema.d.ts +2 -0
- package/dist/types/workflow/workflow-intent-report.d.ts +48 -0
- package/package.json +7 -7
- package/src/cli/completion-cli.ts +234 -0
- package/src/cli/config-cli.ts +37 -9
- package/src/cli/fast-help.ts +1 -0
- package/src/cli/notify-cli.ts +91 -7
- package/src/cli.ts +3 -1
- package/src/commands/completion.ts +84 -0
- package/src/commands/config.ts +2 -0
- package/src/commands/deep-interview.ts +2 -1
- package/src/config/file-lock.ts +73 -34
- package/src/config/keybindings.ts +2 -2
- package/src/config/model-profile-activation.ts +65 -0
- package/src/config/model-registry.ts +14 -2
- package/src/config/settings.ts +22 -0
- package/src/coordinator-mcp/server.ts +67 -12
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +38 -5
- package/src/defaults/gjc/skills/ralplan/SKILL.md +15 -11
- package/src/defaults/gjc/skills/team/SKILL.md +1 -1
- package/src/extensibility/extensions/runner.ts +2 -0
- package/src/extensibility/extensions/types.ts +9 -0
- package/src/extensibility/skills.ts +30 -2
- package/src/gjc-runtime/deep-interview-ambiguity.ts +206 -0
- package/src/gjc-runtime/deep-interview-recorder.ts +62 -8
- package/src/gjc-runtime/deep-interview-runtime.ts +210 -2
- package/src/gjc-runtime/deep-interview-state.ts +13 -0
- package/src/gjc-runtime/session-state-sidecar.ts +59 -11
- package/src/gjc-runtime/state-runtime.ts +12 -2
- package/src/gjc-runtime/team-runtime.ts +23 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +73 -19
- package/src/hooks/native-skill-hook.ts +29 -0
- package/src/internal-urls/docs-index.generated.ts +2 -2
- package/src/main.ts +52 -41
- package/src/modes/acp/acp-agent.ts +7 -6
- package/src/modes/components/model-selector.ts +54 -11
- package/src/modes/components/queued-message-selector.ts +92 -0
- package/src/modes/components/settings-selector.ts +4 -0
- package/src/modes/components/welcome.ts +160 -44
- package/src/modes/controllers/command-controller.ts +4 -4
- package/src/modes/controllers/extension-ui-controller.ts +4 -10
- package/src/modes/controllers/input-controller.ts +186 -25
- package/src/modes/controllers/selector-controller.ts +122 -27
- package/src/modes/interactive-mode.ts +43 -16
- package/src/modes/print-mode.ts +43 -4
- package/src/modes/prompt-action-autocomplete.ts +24 -13
- package/src/modes/utils/hotkeys-markdown.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +2 -2
- package/src/notifications/config.ts +9 -1
- package/src/notifications/daemon-paths.ts +2 -0
- package/src/notifications/index.ts +39 -9
- package/src/notifications/lifecycle-commands.ts +37 -7
- package/src/notifications/lifecycle-orchestrator.ts +19 -6
- package/src/notifications/telegram-daemon-control.ts +3 -1
- package/src/notifications/telegram-daemon.ts +231 -43
- package/src/notifications/telegram-reference.ts +0 -16
- package/src/prompts/system/system-prompt.md +3 -0
- package/src/prompts/tools/computer.md +2 -2
- package/src/runtime-api-key.ts +16 -0
- package/src/sdk.ts +20 -6
- package/src/session/agent-session.ts +225 -31
- package/src/session/agent-storage.ts +4 -0
- package/src/session/session-manager.ts +44 -2
- package/src/slash-commands/builtin-registry.ts +153 -71
- package/src/task/executor.ts +7 -4
- package/src/task/index.ts +9 -3
- package/src/task/output-manager.ts +16 -6
- package/src/task/receipt.ts +26 -7
- package/src/tools/computer.ts +246 -43
- package/src/tools/skill.ts +1 -1
- package/src/tools/telegram-send.ts +6 -0
- package/src/workflow/workflow-intent-diff.ts +29 -6
- package/src/workflow/workflow-intent-report-consumer.ts +221 -0
- package/src/workflow/workflow-intent-report-schema.ts +129 -0
- package/src/workflow/workflow-intent-report.ts +135 -0
|
@@ -28,7 +28,7 @@ import type { ImageContent, TextContent } from "@gajae-code/ai";
|
|
|
28
28
|
import { NotificationServer } from "@gajae-code/natives";
|
|
29
29
|
import { logger, postmortem } from "@gajae-code/utils";
|
|
30
30
|
import { Settings } from "../config/settings";
|
|
31
|
-
import type { ExtensionCommandContext, ExtensionContext
|
|
31
|
+
import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext } from "../extensibility/extensions";
|
|
32
32
|
import { registerAskAnswerSource } from "../tools/ask-answer-registry";
|
|
33
33
|
import { registerTelegramFileSink } from "./attachment-registry";
|
|
34
34
|
import {
|
|
@@ -100,7 +100,7 @@ export interface SessionCloseFrame {
|
|
|
100
100
|
chatId: string;
|
|
101
101
|
token: string;
|
|
102
102
|
target: SessionCloseTarget;
|
|
103
|
-
/**
|
|
103
|
+
/** Required force-only close flag; false/omitted is rejected by daemon policy. */
|
|
104
104
|
force?: boolean;
|
|
105
105
|
}
|
|
106
106
|
|
|
@@ -336,6 +336,8 @@ interface SessionRuntime {
|
|
|
336
336
|
disposeAnswerSource: () => void;
|
|
337
337
|
/** Deregisters this session's Telegram file sink. */
|
|
338
338
|
disposeFileSink: () => void;
|
|
339
|
+
/** Deregisters this session's unattended workflow-gate listener. */
|
|
340
|
+
disposeGateListener: () => void;
|
|
339
341
|
redact: boolean;
|
|
340
342
|
verbosity: "lean" | "verbose";
|
|
341
343
|
sessionTag: string;
|
|
@@ -358,6 +360,8 @@ interface ResolvedSettings {
|
|
|
358
360
|
settingsAvailable: boolean;
|
|
359
361
|
}
|
|
360
362
|
|
|
363
|
+
const TELEGRAM_FILE_REDACTION_ERROR = "Telegram file attachments are disabled while notifications redaction is on.";
|
|
364
|
+
|
|
361
365
|
const defaultConfig: NotificationConfig = {
|
|
362
366
|
enabled: false,
|
|
363
367
|
botToken: undefined,
|
|
@@ -379,7 +383,9 @@ export function notificationsEnabled(): boolean {
|
|
|
379
383
|
return process.env.GJC_NOTIFICATIONS === "1" || Boolean(process.env.GJC_NOTIFICATIONS_TOKEN);
|
|
380
384
|
}
|
|
381
385
|
|
|
382
|
-
function resolveSettings(): ResolvedSettings {
|
|
386
|
+
function resolveSettings(settingsOverride?: Settings): ResolvedSettings {
|
|
387
|
+
if (settingsOverride)
|
|
388
|
+
return { settings: settingsOverride, cfg: getNotificationConfig(settingsOverride), settingsAvailable: true };
|
|
383
389
|
try {
|
|
384
390
|
const settings = Settings.instance;
|
|
385
391
|
return { settings, cfg: getNotificationConfig(settings), settingsAvailable: true };
|
|
@@ -491,7 +497,7 @@ function sessionIdFromFile(file: string | undefined): string | undefined {
|
|
|
491
497
|
return underscore >= 0 ? base.slice(underscore + 1) : undefined;
|
|
492
498
|
}
|
|
493
499
|
|
|
494
|
-
export
|
|
500
|
+
export function createNotificationsExtension(api: ExtensionAPI, options: { settings?: Settings } = {}): void {
|
|
495
501
|
const runtimes = new Map<string, SessionRuntime>();
|
|
496
502
|
const disabledSessions = new Set<string>();
|
|
497
503
|
const sessionId = (ctx: ExtensionContext): string => ctx.sessionManager.getSessionId();
|
|
@@ -503,9 +509,16 @@ export const createNotificationsExtension: ExtensionFactory = api => {
|
|
|
503
509
|
runtimes.delete(id);
|
|
504
510
|
try {
|
|
505
511
|
rt.cancelPostmortemCleanup();
|
|
512
|
+
} catch {}
|
|
513
|
+
try {
|
|
506
514
|
rt.disposeAnswerSource();
|
|
515
|
+
} catch {}
|
|
516
|
+
try {
|
|
507
517
|
rt.disposeFileSink();
|
|
508
518
|
} catch {}
|
|
519
|
+
try {
|
|
520
|
+
rt.disposeGateListener();
|
|
521
|
+
} catch {}
|
|
509
522
|
// Resolve any still-pending interactive asks so the ask tool is not left hanging.
|
|
510
523
|
for (const pending of rt.pendingInteractive.values()) pending.resolve(undefined);
|
|
511
524
|
rt.pendingInteractive.clear();
|
|
@@ -529,10 +542,14 @@ export const createNotificationsExtension: ExtensionFactory = api => {
|
|
|
529
542
|
return isSessionNotificationsEnabled({ cfg, env: process.env, sessionDisabled: disabledSessions.has(id) });
|
|
530
543
|
}
|
|
531
544
|
|
|
545
|
+
function isNotificationEligibleContext(ctx: ExtensionContext): boolean {
|
|
546
|
+
return ctx.sessionMetadata?.kind !== "sub";
|
|
547
|
+
}
|
|
548
|
+
|
|
532
549
|
async function startSession(ctx: ExtensionContext): Promise<"started" | "already" | "disabled" | "failed"> {
|
|
533
550
|
const id = sessionId(ctx);
|
|
534
|
-
const { settings, cfg, settingsAvailable } = resolveSettings();
|
|
535
|
-
if (!isEnabledForSession(id, cfg)) return "disabled";
|
|
551
|
+
const { settings, cfg, settingsAvailable } = resolveSettings(options.settings);
|
|
552
|
+
if (!isNotificationEligibleContext(ctx) || !isEnabledForSession(id, cfg)) return "disabled";
|
|
536
553
|
if (runtimes.has(id)) return "already";
|
|
537
554
|
|
|
538
555
|
const stateRoot = path.join(ctx.cwd, ".gjc", "state");
|
|
@@ -660,6 +677,10 @@ export const createNotificationsExtension: ExtensionFactory = api => {
|
|
|
660
677
|
tag,
|
|
661
678
|
);
|
|
662
679
|
const disposeFileSink = registerTelegramFileSink(id, async file => {
|
|
680
|
+
if (runtime?.redact ?? redact) {
|
|
681
|
+
return { ok: false, error: TELEGRAM_FILE_REDACTION_ERROR };
|
|
682
|
+
}
|
|
683
|
+
|
|
663
684
|
try {
|
|
664
685
|
const data = await fs.promises.readFile(file.path);
|
|
665
686
|
server.pushFrame(
|
|
@@ -683,6 +704,7 @@ export const createNotificationsExtension: ExtensionFactory = api => {
|
|
|
683
704
|
pendingInteractive,
|
|
684
705
|
disposeAnswerSource,
|
|
685
706
|
disposeFileSink,
|
|
707
|
+
disposeGateListener: () => {},
|
|
686
708
|
cancelPostmortemCleanup: () => {},
|
|
687
709
|
redact,
|
|
688
710
|
verbosity,
|
|
@@ -726,7 +748,7 @@ export const createNotificationsExtension: ExtensionFactory = api => {
|
|
|
726
748
|
|
|
727
749
|
// Unattended: a real ask emits a workflow gate; register it repliable by gate_id.
|
|
728
750
|
if (unattended && gate?.onGateEmitted) {
|
|
729
|
-
gate.onGateEmitted(g => {
|
|
751
|
+
runtime.disposeGateListener = gate.onGateEmitted(g => {
|
|
730
752
|
const options = (g.options ?? []).map(o => String((o as { label?: unknown }).label ?? ""));
|
|
731
753
|
gateOptions.set(g.gate_id, options);
|
|
732
754
|
const promptCtx = g.context as { prompt?: unknown; title?: unknown } | undefined;
|
|
@@ -761,7 +783,7 @@ export const createNotificationsExtension: ExtensionFactory = api => {
|
|
|
761
783
|
async handler(args: string, ctx: ExtensionCommandContext): Promise<void> {
|
|
762
784
|
const id = sessionId(ctx);
|
|
763
785
|
const command = args.trim().split(/\s+/, 1)[0]?.toLowerCase() || "status";
|
|
764
|
-
const resolved = resolveSettings();
|
|
786
|
+
const resolved = resolveSettings(options.settings);
|
|
765
787
|
const enabledWithoutLocalOff = isSessionNotificationsEnabled({
|
|
766
788
|
cfg: resolved.cfg,
|
|
767
789
|
env: process.env,
|
|
@@ -781,6 +803,10 @@ export const createNotificationsExtension: ExtensionFactory = api => {
|
|
|
781
803
|
}
|
|
782
804
|
|
|
783
805
|
if (command === "on") {
|
|
806
|
+
if (!isNotificationEligibleContext(ctx)) {
|
|
807
|
+
ctx.ui.notify("Notifications are disabled for subagent sessions.", "warning");
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
784
810
|
if (process.env.GJC_NOTIFICATIONS === "0") {
|
|
785
811
|
ctx.ui.notify(
|
|
786
812
|
"Notifications remain disabled: GJC_NOTIFICATIONS=0 is an authoritative opt-out.",
|
|
@@ -878,6 +904,10 @@ export const createNotificationsExtension: ExtensionFactory = api => {
|
|
|
878
904
|
rt.sessionTag,
|
|
879
905
|
);
|
|
880
906
|
rt.disposeFileSink = registerTelegramFileSink(newId, async file => {
|
|
907
|
+
if (rt.redact) {
|
|
908
|
+
return { ok: false, error: TELEGRAM_FILE_REDACTION_ERROR };
|
|
909
|
+
}
|
|
910
|
+
|
|
881
911
|
try {
|
|
882
912
|
const data = await fs.promises.readFile(file.path);
|
|
883
913
|
rt.server.pushFrame(
|
|
@@ -1099,4 +1129,4 @@ export const createNotificationsExtension: ExtensionFactory = api => {
|
|
|
1099
1129
|
api.on("session_shutdown", async (_event, ctx) => {
|
|
1100
1130
|
await stopSession(sessionId(ctx));
|
|
1101
1131
|
});
|
|
1102
|
-
}
|
|
1132
|
+
}
|
|
@@ -15,6 +15,19 @@ import * as os from "node:os";
|
|
|
15
15
|
import type { SessionCloseTarget, SessionCreateTarget, SessionLifecycleResponse, SessionResumeTarget } from "./index";
|
|
16
16
|
|
|
17
17
|
export type LifecycleCommandVerb = "session_create" | "session_close" | "session_resume";
|
|
18
|
+
function normalizeLifecycleCommandToken(
|
|
19
|
+
token: string,
|
|
20
|
+
ctx: { chatType?: string; botUsername?: string } = {},
|
|
21
|
+
): string | undefined {
|
|
22
|
+
const at = token.indexOf("@");
|
|
23
|
+
const command = at === -1 ? token : token.slice(0, at);
|
|
24
|
+
if (!/^\/session_(create|close|resume|recent)\b/.test(command)) return undefined;
|
|
25
|
+
if (at === -1) return ctx.chatType === undefined || ctx.chatType === "private" ? command : undefined;
|
|
26
|
+
|
|
27
|
+
const botUsername = ctx.botUsername;
|
|
28
|
+
if (!botUsername || token.slice(at + 1).toLowerCase() !== botUsername.toLowerCase()) return undefined;
|
|
29
|
+
return command;
|
|
30
|
+
}
|
|
18
31
|
|
|
19
32
|
/** A parsed, validated lifecycle command (transport identity added by caller). */
|
|
20
33
|
export type ParsedLifecycleCommand =
|
|
@@ -36,10 +49,24 @@ const USAGE = [
|
|
|
36
49
|
"/session_recent [create|resume]",
|
|
37
50
|
].join("\n");
|
|
38
51
|
|
|
39
|
-
/** True when the text begins
|
|
40
|
-
export function
|
|
52
|
+
/** True when the text begins with any /session_* token, regardless of addressability. */
|
|
53
|
+
export function isLifecycleCommandLikeText(text: string | undefined): boolean {
|
|
54
|
+
if (!text) return false;
|
|
55
|
+
const [token] = text.trim().split(/\s+/, 1);
|
|
56
|
+
if (!token) return false;
|
|
57
|
+
const at = token.indexOf("@");
|
|
58
|
+
const command = at === -1 ? token : token.slice(0, at);
|
|
59
|
+
return /^\/session_(create|close|resume|recent)\b/.test(command);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** True when the text begins an addressable /session_* command (cheap pre-gate). */
|
|
63
|
+
export function isLifecycleCommandText(
|
|
64
|
+
text: string | undefined,
|
|
65
|
+
ctx: { chatType?: string; botUsername?: string } = {},
|
|
66
|
+
): boolean {
|
|
41
67
|
if (!text) return false;
|
|
42
|
-
|
|
68
|
+
const [rawCommand] = text.trim().split(/\s+/, 1);
|
|
69
|
+
return normalizeLifecycleCommandToken(rawCommand ?? "", ctx) !== undefined;
|
|
43
70
|
}
|
|
44
71
|
|
|
45
72
|
/**
|
|
@@ -50,9 +77,14 @@ export function isLifecycleCommandText(text: string | undefined): boolean {
|
|
|
50
77
|
* The caller MUST have already enforced paired-chat authorization; this function
|
|
51
78
|
* performs grammar + target validation only.
|
|
52
79
|
*/
|
|
53
|
-
export function parseLifecycleCommand(
|
|
54
|
-
|
|
80
|
+
export function parseLifecycleCommand(
|
|
81
|
+
text: string | undefined,
|
|
82
|
+
ctx: { chatType?: string; botUsername?: string } = {},
|
|
83
|
+
): ParsedLifecycleCommand {
|
|
55
84
|
const raw = (text ?? "").trim();
|
|
85
|
+
const [rawCommand, ...args] = raw.split(/\s+/);
|
|
86
|
+
const command = normalizeLifecycleCommandToken(rawCommand ?? "", ctx);
|
|
87
|
+
if (command === undefined) return { kind: "none" };
|
|
56
88
|
|
|
57
89
|
// MVP: reject any initial-prompt separator outright (no prompt handling yet).
|
|
58
90
|
if (/\s--(\s|$)/.test(raw)) {
|
|
@@ -63,8 +95,6 @@ export function parseLifecycleCommand(text: string | undefined): ParsedLifecycle
|
|
|
63
95
|
};
|
|
64
96
|
}
|
|
65
97
|
|
|
66
|
-
const [command, ...args] = raw.split(/\s+/);
|
|
67
|
-
|
|
68
98
|
if (command === "/session_recent") {
|
|
69
99
|
const which = args[0];
|
|
70
100
|
if (which === undefined || which === "create" || which === "resume") {
|
|
@@ -252,7 +252,17 @@ export async function handleLifecycleRequest(
|
|
|
252
252
|
return { status: "error", reason: "rate_limited", message: "create rate limit exceeded" };
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
-
// 4.
|
|
255
|
+
// 4. Close is intentionally force-only until a graceful close contract exists.
|
|
256
|
+
if (frame.type === "session_close" && frame.force !== true) {
|
|
257
|
+
await deps.audit({ ...baseAudit, event: "rejected", reason: "invalid_target" });
|
|
258
|
+
return {
|
|
259
|
+
status: "error",
|
|
260
|
+
reason: "invalid_target",
|
|
261
|
+
message: "session_close requires force=true; graceful close is not supported",
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// 5. Preallocate ids + write in_progress (fsynced) BEFORE any spawn.
|
|
256
266
|
const lifecycleRequestId = frame.type === "session_create" ? frame.lifecycleRequestId : deps.newLifecycleRequestId();
|
|
257
267
|
const intendedSessionId =
|
|
258
268
|
frame.type === "session_create" ? frame.intendedSessionId || deps.newSessionId() : deps.newSessionId();
|
|
@@ -344,15 +354,18 @@ export async function handleLifecycleRequest(
|
|
|
344
354
|
await deps.audit({ ...baseAudit, event: "success", sessionId: resumed.sessionId });
|
|
345
355
|
return { status: "ok", entry, mode: resumed.mode };
|
|
346
356
|
} catch (err) {
|
|
347
|
-
// A side effect may have occurred; do not
|
|
348
|
-
// uncertain so a retry reconciles instead of duplicating.
|
|
357
|
+
// A side effect may have occurred; do not repeat it automatically. Mark
|
|
358
|
+
// terminal-uncertain so a retry reconciles instead of duplicating work.
|
|
359
|
+
let reason: LifecycleErrorReason = "terminal_uncertain";
|
|
360
|
+
if (frame.type === "session_create") reason = "spawn_failed";
|
|
361
|
+
if (frame.type === "session_close") reason = "close_refused";
|
|
349
362
|
Object.assign(entry, {
|
|
350
363
|
state: "terminal_uncertain",
|
|
351
364
|
updatedAt: deps.now(),
|
|
352
|
-
reason
|
|
365
|
+
reason,
|
|
353
366
|
});
|
|
354
367
|
await deps.store.write(doc);
|
|
355
|
-
await deps.audit({ ...baseAudit, event: "terminal_uncertain", reason
|
|
356
|
-
return { status: "error", reason: "terminal_uncertain", message:
|
|
368
|
+
await deps.audit({ ...baseAudit, event: "terminal_uncertain", reason });
|
|
369
|
+
return { status: "error", reason: "terminal_uncertain", message: `${frame.type} effect failed: ${String(err)}` };
|
|
357
370
|
}
|
|
358
371
|
}
|
|
@@ -269,6 +269,7 @@ export class TelegramDaemonController implements BuiltInDaemonController {
|
|
|
269
269
|
{ settings: this.settings, roots, tokenFingerprint: fp, chatId },
|
|
270
270
|
this.spawnDeps(),
|
|
271
271
|
);
|
|
272
|
+
warnings.push(...spawned.warnings);
|
|
272
273
|
const after = await this.status();
|
|
273
274
|
return this.result(
|
|
274
275
|
action,
|
|
@@ -351,6 +352,7 @@ export class TelegramDaemonController implements BuiltInDaemonController {
|
|
|
351
352
|
{ settings: this.settings, roots, tokenFingerprint: fp, chatId },
|
|
352
353
|
this.spawnDeps(),
|
|
353
354
|
);
|
|
355
|
+
warnings.push(...spawned.warnings);
|
|
354
356
|
const after = await this.status();
|
|
355
357
|
if (spawned.result === "attached") {
|
|
356
358
|
// A live owner already exists; attaching to it is a valid running end-state.
|
|
@@ -360,7 +362,7 @@ export class TelegramDaemonController implements BuiltInDaemonController {
|
|
|
360
362
|
}
|
|
361
363
|
return this.result(
|
|
362
364
|
action,
|
|
363
|
-
spawned.result !== "disabled",
|
|
365
|
+
spawned.result !== "disabled" && spawned.result !== "blocked",
|
|
364
366
|
`reloaded telegram daemon (${spawned.result})`,
|
|
365
367
|
before,
|
|
366
368
|
after,
|