@songsid/agend 2.1.5-beta.2 → 2.1.5-beta.20

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.
Files changed (91) hide show
  1. package/dist/backend/claude-code.d.ts +12 -0
  2. package/dist/backend/claude-code.js +14 -2
  3. package/dist/backend/claude-code.js.map +1 -1
  4. package/dist/backend/codex.d.ts +25 -1
  5. package/dist/backend/codex.js +76 -0
  6. package/dist/backend/codex.js.map +1 -1
  7. package/dist/backend/kiro.js +30 -2
  8. package/dist/backend/kiro.js.map +1 -1
  9. package/dist/backend/types.d.ts +70 -0
  10. package/dist/backend/types.js +23 -1
  11. package/dist/backend/types.js.map +1 -1
  12. package/dist/channel/adapters/discord.d.ts +17 -2
  13. package/dist/channel/adapters/discord.js +82 -8
  14. package/dist/channel/adapters/discord.js.map +1 -1
  15. package/dist/channel/adapters/telegram.d.ts +2 -2
  16. package/dist/channel/adapters/telegram.js +8 -8
  17. package/dist/channel/adapters/telegram.js.map +1 -1
  18. package/dist/channel/types.d.ts +22 -1
  19. package/dist/cli.js +37 -37
  20. package/dist/cli.js.map +1 -1
  21. package/dist/config.d.ts +4 -0
  22. package/dist/config.js +4 -0
  23. package/dist/config.js.map +1 -1
  24. package/dist/daemon.d.ts +181 -21
  25. package/dist/daemon.js +1054 -225
  26. package/dist/daemon.js.map +1 -1
  27. package/dist/deadline.d.ts +23 -0
  28. package/dist/deadline.js +29 -0
  29. package/dist/deadline.js.map +1 -0
  30. package/dist/fleet-context.d.ts +17 -1
  31. package/dist/fleet-context.js.map +1 -1
  32. package/dist/fleet-manager.d.ts +189 -2
  33. package/dist/fleet-manager.js +808 -119
  34. package/dist/fleet-manager.js.map +1 -1
  35. package/dist/full-restart.d.ts +20 -0
  36. package/dist/full-restart.js +39 -0
  37. package/dist/full-restart.js.map +1 -0
  38. package/dist/instance-lifecycle.d.ts +8 -2
  39. package/dist/instance-lifecycle.js +47 -3
  40. package/dist/instance-lifecycle.js.map +1 -1
  41. package/dist/instance-removal.d.ts +13 -0
  42. package/dist/instance-removal.js +14 -0
  43. package/dist/instance-removal.js.map +1 -0
  44. package/dist/instructions.js +2 -2
  45. package/dist/instructions.js.map +1 -1
  46. package/dist/locale.js +54 -4
  47. package/dist/locale.js.map +1 -1
  48. package/dist/login-controller.d.ts +31 -4
  49. package/dist/login-controller.js +52 -4
  50. package/dist/login-controller.js.map +1 -1
  51. package/dist/login-flows.d.ts +29 -0
  52. package/dist/login-flows.js +48 -1
  53. package/dist/login-flows.js.map +1 -1
  54. package/dist/outbound-handlers.d.ts +1 -0
  55. package/dist/outbound-handlers.js +118 -29
  56. package/dist/outbound-handlers.js.map +1 -1
  57. package/dist/outbound-schemas.d.ts +7 -0
  58. package/dist/outbound-schemas.js +3 -0
  59. package/dist/outbound-schemas.js.map +1 -1
  60. package/dist/pane-input-residue.d.ts +25 -2
  61. package/dist/pane-input-residue.js +31 -2
  62. package/dist/pane-input-residue.js.map +1 -1
  63. package/dist/restart-progress.d.ts +35 -5
  64. package/dist/restart-progress.js +177 -34
  65. package/dist/restart-progress.js.map +1 -1
  66. package/dist/service-restart-selection.d.ts +27 -0
  67. package/dist/service-restart-selection.js +25 -0
  68. package/dist/service-restart-selection.js.map +1 -0
  69. package/dist/topic-commands.d.ts +27 -2
  70. package/dist/topic-commands.js +59 -13
  71. package/dist/topic-commands.js.map +1 -1
  72. package/dist/turn-reply-guard.d.ts +41 -0
  73. package/dist/turn-reply-guard.js +77 -0
  74. package/dist/turn-reply-guard.js.map +1 -0
  75. package/dist/ui/web-terminal/terminal.html +1 -0
  76. package/dist/update-marker.d.ts +11 -1
  77. package/dist/update-marker.js +19 -4
  78. package/dist/update-marker.js.map +1 -1
  79. package/dist/update-progress.d.ts +1 -1
  80. package/dist/update-progress.js +12 -0
  81. package/dist/update-progress.js.map +1 -1
  82. package/dist/usage/providers.d.ts +39 -0
  83. package/dist/usage/providers.js +69 -3
  84. package/dist/usage/providers.js.map +1 -1
  85. package/dist/web-api.d.ts +2 -1
  86. package/dist/web-api.js +2 -1
  87. package/dist/web-api.js.map +1 -1
  88. package/dist/web-terminal-http.d.ts +8 -0
  89. package/dist/web-terminal-http.js +29 -3
  90. package/dist/web-terminal-http.js.map +1 -1
  91. package/package.json +1 -1
package/dist/daemon.d.ts CHANGED
@@ -11,6 +11,33 @@ import type { StormWindow } from "./storm-window.js";
11
11
  import type { BackendOutageView } from "./backend-outage.js";
12
12
  /** Point a resumed CLI at its one backend-native instruction source. */
13
13
  export declare function buildInstructionReloadNotice(binaryName: string, instanceName: string, instanceDir: string): string;
14
+ /**
15
+ * Whether this backend has to be told in its pane that its instructions moved.
16
+ *
17
+ * A backend that re-reads them on resume already received the new ones from the
18
+ * resume itself, so the notice is pure interruption. Both places that can send
19
+ * it — the warmup paste and the deferred pendingInstructionsNotice — ask through
20
+ * here, so the two cannot drift apart again: the warmup path used to omit this
21
+ * check entirely and told claude-code to reload instructions it had just read.
22
+ */
23
+ export declare function backendNeedsPaneReloadNotice(backend?: {
24
+ instructionsReloadedOnResume?: boolean;
25
+ }): boolean;
26
+ /**
27
+ * What the warmup should do about changed instructions.
28
+ *
29
+ * `skip` — nothing to say, or this backend learns of the change by itself.
30
+ * `defer` — worth saying, but nobody is talking to the instance; say it when a
31
+ * real message next arrives rather than provoking an unsolicited reply.
32
+ * `paste` — say it now, into a pane that already has a delivery in flight.
33
+ */
34
+ export declare function warmupNoticeAction(opts: {
35
+ warmupNeeded: boolean;
36
+ backend?: {
37
+ instructionsReloadedOnResume?: boolean;
38
+ };
39
+ pasteQueueDepth: number;
40
+ }): "skip" | "defer" | "paste";
14
41
  export declare const DEFAULT_STUCK_TIMEOUT_MS: number;
15
42
  export declare const DEFAULT_STATE_IDLE_DEBOUNCE_MS = 2000;
16
43
  export declare const DEFAULT_STATE_SAFETY_SWEEP_MS = 60000;
@@ -172,7 +199,7 @@ export declare class PendingWorkTracker {
172
199
  private lastIdleOrder;
173
200
  constructor(now?: number);
174
201
  recordInbound(now?: number): void;
175
- recordIdle(now?: number): void;
202
+ recordIdle(now?: number): boolean;
176
203
  hasPendingWork(): boolean;
177
204
  }
178
205
  /**
@@ -380,6 +407,14 @@ export declare class Daemon extends EventEmitter {
380
407
  private spawnSettled;
381
408
  private resolveSpawnSettled;
382
409
  private spawnDepth;
410
+ /** Monotonic identity for nested beginSpawn/endSpawn lifecycles. */
411
+ private spawnGeneration;
412
+ /**
413
+ * Keeps passive startup-transient checks alive through the first positively
414
+ * submitted post-spawn message. Without this tail, a transient painted just
415
+ * after the startup scan can still swallow that message's Enter.
416
+ */
417
+ private inputTransientGuardGeneration;
383
418
  private skipResume;
384
419
  private startupAborted;
385
420
  /** First time the current on-screen blocking dialog was seen (0 = none); drives the parked report. */
@@ -412,15 +447,11 @@ export declare class Daemon extends EventEmitter {
412
447
  private instanceStateMonitorActive;
413
448
  private sessionCheckpointWarningEmitted;
414
449
  private statePollInFlight;
415
- private turnHadInbound;
416
- private turnOutboundDelivered;
417
- /** Successful `reply` specifically; cross-instance tools do not satisfy #648. */
418
- private turnReplyDelivered;
419
- private turnCorrelationId;
420
- private turnInboundMarker;
450
+ private turnReplyGuard;
421
451
  /** Prevent a visible stale XML fragment from being recovered on later turns. */
422
452
  private lastMalformedToolCallSignature;
423
453
  private proxyReplySeq;
454
+ private lastReplyDropWarningAt;
424
455
  private autoPauseController;
425
456
  private pauseRequested;
426
457
  /**
@@ -573,6 +604,22 @@ export declare class Daemon extends EventEmitter {
573
604
  private lastErrorCount;
574
605
  private lastDetectedErrorType;
575
606
  private static errorPatternKey;
607
+ /**
608
+ * Undo the auth suspicion a pattern match armed, once the backend's token-free
609
+ * probe has said the credentials are fine.
610
+ *
611
+ * emitErrorPattern arms these BEFORE the pty_error reaches the lifecycle, and
612
+ * the lifecycle's "valid" verdict used to just drop the incident — leaving the
613
+ * daemon permanently suspicious of an auth failure that never existed. That
614
+ * state is not inert: authFailureUnresolved suppresses the stuck/hang
615
+ * notification and holds MCP auto-restart (a later real MCP death is then read
616
+ * as already-confirmed auth trouble rather than re-verified), and the recovery
617
+ * gate suppresses further error detection until a ready pattern shows up.
618
+ *
619
+ * Only what an auth match armed is rolled back. If some other pattern has
620
+ * since armed the recovery gate, that one is still live and stays.
621
+ */
622
+ clearSuspectedAuthFailure(): boolean;
576
623
  private clearErrorRecoveryGate;
577
624
  constructor(name: string, config: InstanceConfig, instanceDir: string, topicMode?: boolean, backend?: CliBackend | undefined, controlClient?: TmuxControlClient | undefined, rootLogger?: Logger, runtimeIdentity?: FleetInstructionsParams["runtimeIdentity"], spawnGate?: SpawnGate | undefined, stormWindow?: StormWindow | undefined,
578
625
  /** Fleet-level "is this CLI's backend down?" memory — see backend-outage.ts. */
@@ -787,10 +834,14 @@ export declare class Daemon extends EventEmitter {
787
834
  */
788
835
  private maybeProxyReplyOnTurnEnd;
789
836
  private isClaudeCodeBackend;
837
+ private replyCompletionGuardEnabled;
838
+ private startReplyRecovery;
839
+ private reportReplyDropWithoutRetry;
840
+ private queueReplyRecoveryPrompt;
841
+ private queueMalformedReplyRecovery;
842
+ private reportUnrecoveredReplyDrop;
790
843
  /** Relay the pane's final text to the channel, marked as a daemon proxy reply. */
791
844
  private sendProxyReply;
792
- /** Send a narrowly extracted #648 reply; operator notification is a separate event. */
793
- private sendRecoveredMalformedReply;
794
845
  /** Context-bound reply path shared by dead-MCP and malformed-call recovery. */
795
846
  private deliverDaemonReply;
796
847
  private clearInstanceStateIdleTimer;
@@ -937,6 +988,18 @@ export declare class Daemon extends EventEmitter {
937
988
  * on purpose ("I trust", "Yes, continue") and would match ordinary prose.
938
989
  */
939
990
  private deliveryBlockingDialogs;
991
+ /** Passive input-unavailable phases relevant to the current spawn only. */
992
+ private guardedInputTransients;
993
+ /** Match a passive transient against the current interactive screen. */
994
+ private inputTransientInPane;
995
+ /** Capture failure is unknown, never evidence that input is available. */
996
+ private probeInputTransient;
997
+ /**
998
+ * Wait under the pane lock for a passive transient to disappear. Unlike a
999
+ * dialog, this state clears by itself, so the wait cannot starve a keypress
1000
+ * dismisser. Stop or a replacement spawn invalidates the captured identity.
1001
+ */
1002
+ private waitForInputTransientToClear;
940
1003
  private static dialogKey;
941
1004
  /** A dialog counts only when it is the CURRENT interactive region, if the backend can tell; else by pattern. */
942
1005
  private static dialogMatches;
@@ -977,10 +1040,10 @@ export declare class Daemon extends EventEmitter {
977
1040
  private isPaneReadyForDelivery;
978
1041
  /**
979
1042
  * Why a pane is not deliverable matters. "busy" may be handed to a native
980
- * input queue or steered (after its own dialog probe); "dialog" and "unknown"
981
- * must never be — a paste + Enter into a dialog answers it with its default,
982
- * and an unreadable pane proves nothing. The silence gate comes first and
983
- * costs no capture, so a CLI that is simply working never pays for the probe.
1043
+ * input queue or steered (after its own dialog probe); "dialog", "transient"
1044
+ * and "unknown" must never be — a paste + Enter into a dialog answers it
1045
+ * with its default, while a startup transient swallows it and an unreadable
1046
+ * pane proves nothing. The silence gate comes first and costs no capture.
984
1047
  */
985
1048
  private paneReadinessForDelivery;
986
1049
  /**
@@ -1005,10 +1068,10 @@ export declare class Daemon extends EventEmitter {
1005
1068
  */
1006
1069
  private submitStrandedInputIfAny;
1007
1070
  /**
1008
- * "stranded": an AgEnD message sits in the input row; "clear": the prompt is
1009
- * at the bottom with no stranded text; "busy": generating, or the prompt is
1010
- * not at the bottom (incl. a blank frame); "unknown": the pane could not be
1011
- * read. Only "clear" is positive evidence.
1071
+ * "stranded": an AgEnD message sits in the input row; "clear": no strand is
1072
+ * visible under the backend's readiness policy; "busy": generating, or (for
1073
+ * a bottom-gated backend) the prompt is not at the bottom; "unknown": the
1074
+ * pane could not be read. Only "clear" permits the next paste.
1012
1075
  */
1013
1076
  private strandedInputState;
1014
1077
  /**
@@ -1054,11 +1117,71 @@ export declare class Daemon extends EventEmitter {
1054
1117
  private sendDeliveryEnter;
1055
1118
  private writeMessageToPane;
1056
1119
  /**
1057
- * True when a busy native-queue paste appears to have landed: Codex shows a
1058
- * `↳` queue marker, or a distinctive slice of the pasted text is on screen.
1059
- * Used only to detect silent paste loss — not as a general ready check.
1120
+ * The single place a pasted message is judged submitted, shared by the
1121
+ * native-queue handoff, the idle-gated redelivery and the system pastes.
1122
+ *
1123
+ * It replaces three divergent weak checks, the weakest of which accepted "the
1124
+ * pasted text is visible somewhere in the pane". That one was satisfied BY
1125
+ * the failure it was meant to catch: text stranded in the input row is on
1126
+ * screen, so a message nobody submitted was confirmed ✅ with no warning
1127
+ * anywhere. Evidence is weighed in order of what it can prove, and the
1128
+ * disqualifying evidence is checked first.
1129
+ */
1130
+ /**
1131
+ * Whether this backend exposes an input row we can actually read, i.e. whether
1132
+ * confirmSubmitted can ever return a verdict stronger than a guess.
1133
+ *
1134
+ * This is a property of the BACKEND, not of one delivery's verdict. Keying the
1135
+ * output-signal fallback off the verdict instead let codex — which can be read
1136
+ * — fall back to "the pane printed something" whenever a paste left no trace,
1137
+ * which is the same false confirmation one layer down.
1138
+ */
1139
+ private canProveSubmission;
1140
+ /** Positive submission retires the startup transient guard for this spawn. */
1141
+ private submittedProof;
1142
+ /**
1143
+ * Decide a submission after an Enter, with one bounded retry.
1144
+ *
1145
+ * Backends we can read must SHOW the text left the input row: neither a
1146
+ * strand nor a vanished paste may be upgraded to success by output, because
1147
+ * the output that would do the upgrading is usually the very redraw the Enter
1148
+ * was lost to. Backends we cannot read keep the legacy output signal — there
1149
+ * is nothing better available for them, and taking it away would fail every
1150
+ * one of their deliveries.
1151
+ *
1152
+ * One ladder, used by every post-Enter confirmation, so an escape hatch
1153
+ * cannot reappear in just one of them (it did: three copies, two of which
1154
+ * still confirmed on output alone).
1155
+ */
1156
+ private confirmAfterEnter;
1157
+ private confirmSubmitted;
1158
+ /**
1159
+ * What the pane currently shows of a given message. Taken once before the
1160
+ * paste and once after, so confirmSubmitted can require a NEW marker or a NEW
1161
+ * echo rather than accepting whatever was already there.
1162
+ */
1163
+ private capturePaneEvidence;
1164
+ private paneEvidence;
1165
+ /**
1166
+ * What identifies THIS message on screen. The routing envelope carries a
1167
+ * message_id that no earlier transcript entry can share, so prefer it: the
1168
+ * body alone is not distinctive enough — short repeated instructions ("carry
1169
+ * on", a status ping) recur verbatim, and an older copy would vouch for a
1170
+ * paste that never landed. System pastes carry no envelope and fall back to
1171
+ * the body signature, which the baseline comparison still ties to this paste.
1172
+ */
1173
+ private submissionSignature;
1174
+ /**
1175
+ * Paste + submit + confirm for the SYSTEM messages that used to go out via
1176
+ * tmux.pasteText: one Enter (two for queue-less backends) and no verification
1177
+ * at all, so a swallowed Enter left the notice sitting in the input row where
1178
+ * the next delivery submitted both as one message. Shares confirmSubmitted
1179
+ * with the delivery path — having one primitive is the point.
1180
+ *
1181
+ * Best effort by design: these notices must never fail a delivery or throw.
1182
+ * The caller already holds paneWriteLock.
1060
1183
  */
1061
- private nativeQueuePasteVisible;
1184
+ private submitSystemPaste;
1062
1185
  /** Re-resolve this instance's tmux window by name (stale id after crash/respawn). */
1063
1186
  private recoverWindow;
1064
1187
  /**
@@ -1119,6 +1242,32 @@ export declare class Daemon extends EventEmitter {
1119
1242
  */
1120
1243
  private waitForSpawnToSettle;
1121
1244
  /** Spawn a CLI window. Returns true if --resume was used successfully. */
1245
+ /**
1246
+ * Positive proof from the CLI that there is no conversation left to resume.
1247
+ *
1248
+ * Only this may justify abandoning a session. A startup that merely ran out of
1249
+ * budget proves nothing: a healthy cold start on a loaded host looks exactly
1250
+ * the same, which is how 9 instances silently lost their history.
1251
+ *
1252
+ * Deliberately does NOT match a bare "--continue": the pane text can mention
1253
+ * the flag (a usage error, an echoed invocation) without the CLI ever saying
1254
+ * the conversation is gone.
1255
+ */
1256
+ private paneSaysNoConversation;
1257
+ /** How many consecutive startups have failed without proving the session is gone. */
1258
+ private unprovenResumeFailures;
1259
+ /** After this many, start fresh anyway — loudly — so a truly broken session still recovers. */
1260
+ private static readonly MAX_UNPROVEN_RESUME_FAILURES;
1261
+ /**
1262
+ * Set the session aside instead of deleting it.
1263
+ *
1264
+ * The whole defect being fixed here is silent, irreversible loss of a user's
1265
+ * conversation. Renaming costs nothing and turns a wrong call into something
1266
+ * recoverable: the id is still on disk under a dated name.
1267
+ */
1268
+ private setSessionAside;
1269
+ /** Keep the newest few set-aside sessions; they are insurance, not an archive. */
1270
+ private pruneAbandonedSessions;
1122
1271
  private spawnClaudeWindow;
1123
1272
  /**
1124
1273
  * Startup budget for this launch: the backend's override (resume-aware), never
@@ -1172,6 +1321,17 @@ export declare class Daemon extends EventEmitter {
1172
1321
  * Returns true if CLI is ready, false if it failed or got stuck.
1173
1322
  */
1174
1323
  private trySpawn;
1324
+ /**
1325
+ * Tell the agent its instructions moved, once the CLI is idle.
1326
+ *
1327
+ * A named method rather than an inline closure so the wiring itself is
1328
+ * testable: warmupNoticeAction's own tests pass even if this call site stops
1329
+ * consulting it, which is exactly the bug this path had — the decision was
1330
+ * made inline and never asked whether the backend needed telling at all.
1331
+ *
1332
+ * Never throws: a missed reload notice must not fail a spawn.
1333
+ */
1334
+ private runWarmupInstructionNotice;
1175
1335
  private trySpawnInsideGate;
1176
1336
  /**
1177
1337
  * The last leg of a spawn: confirm the pane is not positively dead, then run