@songsid/agend 2.1.5 → 2.1.6-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/dist/agent-endpoint.d.ts +18 -0
  2. package/dist/agent-endpoint.js +53 -2
  3. package/dist/agent-endpoint.js.map +1 -1
  4. package/dist/apply-job.d.ts +114 -0
  5. package/dist/apply-job.js +214 -0
  6. package/dist/apply-job.js.map +1 -0
  7. package/dist/backend/claude-code.d.ts +25 -0
  8. package/dist/backend/claude-code.js +127 -0
  9. package/dist/backend/claude-code.js.map +1 -1
  10. package/dist/backend/codex.d.ts +57 -0
  11. package/dist/backend/codex.js +183 -0
  12. package/dist/backend/codex.js.map +1 -1
  13. package/dist/backend/credential-profile.d.ts +159 -0
  14. package/dist/backend/credential-profile.js +340 -0
  15. package/dist/backend/credential-profile.js.map +1 -0
  16. package/dist/backend/factory.js +4 -1
  17. package/dist/backend/factory.js.map +1 -1
  18. package/dist/backend/kiro-auth-store.d.ts +25 -0
  19. package/dist/backend/kiro-auth-store.js +61 -0
  20. package/dist/backend/kiro-auth-store.js.map +1 -0
  21. package/dist/backend/kiro.d.ts +8 -0
  22. package/dist/backend/kiro.js +31 -2
  23. package/dist/backend/kiro.js.map +1 -1
  24. package/dist/backend/muse.d.ts +90 -0
  25. package/dist/backend/muse.js +437 -0
  26. package/dist/backend/muse.js.map +1 -0
  27. package/dist/backend/types.d.ts +54 -0
  28. package/dist/backend/types.js.map +1 -1
  29. package/dist/channel/access-manager.d.ts +20 -0
  30. package/dist/channel/access-manager.js +25 -0
  31. package/dist/channel/access-manager.js.map +1 -1
  32. package/dist/channel/adapters/discord.d.ts +17 -0
  33. package/dist/channel/adapters/discord.js +72 -11
  34. package/dist/channel/adapters/discord.js.map +1 -1
  35. package/dist/channel/adapters/telegram.d.ts +6 -0
  36. package/dist/channel/adapters/telegram.js +36 -0
  37. package/dist/channel/adapters/telegram.js.map +1 -1
  38. package/dist/channel/markdown-chunk.d.ts +8 -3
  39. package/dist/channel/markdown-chunk.js +12 -3
  40. package/dist/channel/markdown-chunk.js.map +1 -1
  41. package/dist/channel/mcp-server.js +9 -12
  42. package/dist/channel/mcp-server.js.map +1 -1
  43. package/dist/channel/mcp-tools.d.ts +6 -2
  44. package/dist/channel/mcp-tools.js +6 -36
  45. package/dist/channel/mcp-tools.js.map +1 -1
  46. package/dist/channel/tool-router.js +32 -3
  47. package/dist/channel/tool-router.js.map +1 -1
  48. package/dist/channel/types.d.ts +18 -0
  49. package/dist/cli.js +113 -0
  50. package/dist/cli.js.map +1 -1
  51. package/dist/config-validator.js +45 -5
  52. package/dist/config-validator.js.map +1 -1
  53. package/dist/connection-secrets.d.ts +96 -0
  54. package/dist/connection-secrets.js +25 -0
  55. package/dist/connection-secrets.js.map +1 -0
  56. package/dist/daemon.d.ts +76 -0
  57. package/dist/daemon.js +489 -103
  58. package/dist/daemon.js.map +1 -1
  59. package/dist/event-log.d.ts +9 -0
  60. package/dist/event-log.js +21 -0
  61. package/dist/event-log.js.map +1 -1
  62. package/dist/fleet-level-config.d.ts +42 -0
  63. package/dist/fleet-level-config.js +78 -0
  64. package/dist/fleet-level-config.js.map +1 -0
  65. package/dist/fleet-lock.d.ts +21 -0
  66. package/dist/fleet-lock.js +42 -8
  67. package/dist/fleet-lock.js.map +1 -1
  68. package/dist/fleet-manager.d.ts +425 -2
  69. package/dist/fleet-manager.js +2055 -182
  70. package/dist/fleet-manager.js.map +1 -1
  71. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +145 -0
  72. package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +11 -1
  73. package/dist/instance-config-impact.d.ts +55 -0
  74. package/dist/instance-config-impact.js +152 -0
  75. package/dist/instance-config-impact.js.map +1 -0
  76. package/dist/instance-lifecycle.js +8 -4
  77. package/dist/instance-lifecycle.js.map +1 -1
  78. package/dist/locale.js +24 -0
  79. package/dist/locale.js.map +1 -1
  80. package/dist/logger.js +42 -25
  81. package/dist/logger.js.map +1 -1
  82. package/dist/muse-usage-relay.d.ts +72 -0
  83. package/dist/muse-usage-relay.js +419 -0
  84. package/dist/muse-usage-relay.js.map +1 -0
  85. package/dist/outbound-handlers.d.ts +5 -1
  86. package/dist/outbound-handlers.js +199 -1
  87. package/dist/outbound-handlers.js.map +1 -1
  88. package/dist/outbound-schemas.d.ts +7 -5
  89. package/dist/outbound-schemas.js +3 -2
  90. package/dist/outbound-schemas.js.map +1 -1
  91. package/dist/provider-probe.d.ts +48 -0
  92. package/dist/provider-probe.js +121 -0
  93. package/dist/provider-probe.js.map +1 -0
  94. package/dist/provider-secret-registry.d.ts +98 -0
  95. package/dist/provider-secret-registry.js +334 -0
  96. package/dist/provider-secret-registry.js.map +1 -0
  97. package/dist/quickstart-api.d.ts +164 -0
  98. package/dist/quickstart-api.js +351 -0
  99. package/dist/quickstart-api.js.map +1 -0
  100. package/dist/quickstart.js +23 -50
  101. package/dist/quickstart.js.map +1 -1
  102. package/dist/scheduler/db.js +17 -5
  103. package/dist/scheduler/db.js.map +1 -1
  104. package/dist/scheduler/db.test.js +34 -1
  105. package/dist/scheduler/db.test.js.map +1 -1
  106. package/dist/scheduler/types.d.ts +4 -0
  107. package/dist/scheduler/types.js.map +1 -1
  108. package/dist/secret-store.d.ts +25 -0
  109. package/dist/secret-store.js +165 -0
  110. package/dist/secret-store.js.map +1 -0
  111. package/dist/self-restart-limit.d.ts +21 -0
  112. package/dist/self-restart-limit.js +129 -0
  113. package/dist/self-restart-limit.js.map +1 -0
  114. package/dist/settings-api.d.ts +116 -0
  115. package/dist/settings-api.js +530 -5
  116. package/dist/settings-api.js.map +1 -1
  117. package/dist/setup-auth.d.ts +113 -0
  118. package/dist/setup-auth.js +181 -0
  119. package/dist/setup-auth.js.map +1 -0
  120. package/dist/setup-form.d.ts +18 -0
  121. package/dist/setup-form.js +315 -0
  122. package/dist/setup-form.js.map +1 -0
  123. package/dist/setup-host.d.ts +162 -0
  124. package/dist/setup-host.js +496 -0
  125. package/dist/setup-host.js.map +1 -0
  126. package/dist/setup-marker.d.ts +8 -0
  127. package/dist/setup-marker.js +39 -0
  128. package/dist/setup-marker.js.map +1 -0
  129. package/dist/setup-tunnel-consent.d.ts +53 -0
  130. package/dist/setup-tunnel-consent.js +82 -0
  131. package/dist/setup-tunnel-consent.js.map +1 -0
  132. package/dist/setup-wizard.js +4 -0
  133. package/dist/setup-wizard.js.map +1 -1
  134. package/dist/steer-capability.js +4 -1
  135. package/dist/steer-capability.js.map +1 -1
  136. package/dist/tips.js +1 -1
  137. package/dist/tips.js.map +1 -1
  138. package/dist/tmux-manager.js +29 -4
  139. package/dist/tmux-manager.js.map +1 -1
  140. package/dist/tool-permissions-notice.d.ts +38 -0
  141. package/dist/tool-permissions-notice.js +92 -0
  142. package/dist/tool-permissions-notice.js.map +1 -0
  143. package/dist/tool-permissions.d.ts +120 -0
  144. package/dist/tool-permissions.js +277 -0
  145. package/dist/tool-permissions.js.map +1 -0
  146. package/dist/topic-commands.js +1 -0
  147. package/dist/topic-commands.js.map +1 -1
  148. package/dist/transcript-sources.d.ts +12 -1
  149. package/dist/transcript-sources.js +19 -3
  150. package/dist/transcript-sources.js.map +1 -1
  151. package/dist/tunnel/cloudflared.d.ts +71 -0
  152. package/dist/tunnel/cloudflared.js +447 -0
  153. package/dist/tunnel/cloudflared.js.map +1 -0
  154. package/dist/tunnel/lease.d.ts +75 -0
  155. package/dist/tunnel/lease.js +209 -0
  156. package/dist/tunnel/lease.js.map +1 -0
  157. package/dist/tunnel/manager.d.ts +56 -0
  158. package/dist/tunnel/manager.js +167 -0
  159. package/dist/tunnel/manager.js.map +1 -0
  160. package/dist/tunnel/types.d.ts +119 -0
  161. package/dist/tunnel/types.js +33 -0
  162. package/dist/tunnel/types.js.map +1 -0
  163. package/dist/types.d.ts +2 -0
  164. package/dist/ui/dashboard.html +4 -3
  165. package/dist/ui/settings.html +808 -156
  166. package/dist/ui/view.html +2 -2
  167. package/dist/usage/i18n-keys.d.ts +1 -1
  168. package/dist/usage/i18n-keys.js +1 -1
  169. package/dist/usage/i18n-keys.js.map +1 -1
  170. package/dist/usage/providers.d.ts +23 -14
  171. package/dist/usage/providers.js +220 -58
  172. package/dist/usage/providers.js.map +1 -1
  173. package/dist/usage/usage-api.d.ts +13 -0
  174. package/dist/usage/usage-api.js +69 -1
  175. package/dist/usage/usage-api.js.map +1 -1
  176. package/dist/web-api.js +8 -5
  177. package/dist/web-api.js.map +1 -1
  178. package/dist/web-auth.d.ts +75 -0
  179. package/dist/web-auth.js +208 -2
  180. package/dist/web-auth.js.map +1 -1
  181. package/dist/web-terminal.d.ts +30 -1
  182. package/dist/web-terminal.js +86 -3
  183. package/dist/web-terminal.js.map +1 -1
  184. package/package.json +2 -1
@@ -0,0 +1,437 @@
1
+ import { join } from "node:path";
2
+ import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync, chmodSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { createHash } from "node:crypto";
5
+ import { resolveBinary, shellQuote, validateModel, warnIfModelMismatch } from "./types.js";
6
+ import { appendWithMarker, removeMarker } from "./marker-utils.js";
7
+ /** Session ids are UUIDs (e.g. "01a0c784-fb91-…"); guard before shell interpolation. */
8
+ const SESSION_ID_RE = /^[0-9a-fA-F-]{8,}$/;
9
+ /**
10
+ * Enough of a session log to reach the `route_facts` record that names the
11
+ * working directory. Measured on a live session: `"cwd"` landed at byte 3899 of
12
+ * a 450KB log, at sequence 4. 64KiB is ~16x that headroom and keeps the scan
13
+ * cheap even with dozens of sessions on disk.
14
+ */
15
+ const SESSION_HEAD_BYTES = 65_536;
16
+ /** Read the workspace a session was started in, without reading the whole log. */
17
+ export function museSessionCwd(head) {
18
+ return head.match(/"cwd":"((?:[^"\\]|\\.)*)"/)?.[1]?.replace(/\\(.)/g, "$1") ?? null;
19
+ }
20
+ /**
21
+ * Meta Muse Code — the `muse` CLI (v1.3.0 verified).
22
+ *
23
+ * Everything below was confirmed against live sessions on 2026-09-22 rather
24
+ * than read out of `--help`, because the two disagree in the places that
25
+ * matter. Three findings shaped this file:
26
+ *
27
+ * 1. The input prompt `❯` stays on screen the entire time muse works, so the
28
+ * ready pattern alone can never say "idle" — hence getBusyPattern().
29
+ * 2. Ctrl+C is QUIT (twice), not cancel. The TUI's own hint is "esc to
30
+ * interrupt", and Escape is what stops a run. Wiring C-c to cancel would
31
+ * have left every instance one stray keypress from death.
32
+ * 3. `--disable-approval` alone still stops at a workspace-trust dialog. It
33
+ * needs `--trust-workspace` beside it to reach the prompt unattended.
34
+ */
35
+ export class MuseBackend {
36
+ instanceDir;
37
+ binaryName = "muse";
38
+ binaryPath;
39
+ // Cached from buildCommand/writeConfig so getSessionId() (which takes no
40
+ // args) can match sessions against this instance's workspace.
41
+ workingDirectory;
42
+ constructor(instanceDir) {
43
+ this.instanceDir = instanceDir;
44
+ this.binaryPath = resolveBinary("muse");
45
+ }
46
+ buildCommand(config) {
47
+ this.workingDirectory = config.workingDirectory;
48
+ // `muse` on PATH is a launcher script that checks for a new release, may
49
+ // replace the binary underneath us, and records an update notice that the
50
+ // next start prints. A fleet agent can run for days; an update arriving
51
+ // mid-run would repaint the pane and swap the CLI. One year in seconds
52
+ // keeps the check quiet while staying inside the launcher's own numeric
53
+ // guard (a non-numeric value also disables it, but undocumented).
54
+ let cmd = `MUSE_UPDATE_INTERVAL_SECONDS=31536000 ${this.binaryPath}`;
55
+ // The daemon may prepare a localhost-only usage relay before spawning Muse.
56
+ // If relay preparation fails this remains unset and Muse connects directly;
57
+ // usage must never become a prerequisite for a working conversation.
58
+ if (config.museBaseUrl)
59
+ cmd += ` --base-url ${shellQuote(config.museBaseUrl)}`;
60
+ // Verified: `--disable-approval` on its own leaves the session parked on
61
+ // "Do you trust this workspace?" forever. Trust is a separate axis, so both
62
+ // flags are needed to reach the prompt unattended.
63
+ //
64
+ // NOT `--yolo`: that disables approval, trust AND the OS sandbox. The
65
+ // sandbox was measured to permit what an agent actually needs — writes in
66
+ // the workspace and to the temp dir, and outbound network through the proxy
67
+ // (curl to example.com returned 200) — so there is nothing to buy by
68
+ // switching it off, and a sandboxed shell is worth keeping.
69
+ if (config.skipPermissions !== false)
70
+ cmd += " --disable-approval --trust-workspace";
71
+ if (config.model) {
72
+ const model = validateModel(config.model);
73
+ warnIfModelMismatch("muse", model);
74
+ cmd += ` --model ${shellQuote(model)}`;
75
+ }
76
+ // muse accepts none|minimal|low|medium|high|xhigh|max|ultra; AgEnD's levels
77
+ // are a subset, so whatever the fleet holds is passed through unchanged.
78
+ if (config.effort)
79
+ cmd += ` --reasoning-effort ${shellQuote(config.effort)}`;
80
+ // Resume is a SUBCOMMAND, and root options may sit on either side of it
81
+ // (stated in `muse resume --help`, and verified: root flags + `resume <id>`
82
+ // launched into the prior conversation with the model flag applied).
83
+ // `resume --last` is workspace-scoped and would silently adopt a session the
84
+ // user started by hand in the same directory, so we resume the id we
85
+ // persisted and nothing else.
86
+ if (!config.skipResume) {
87
+ const sid = this.storedSessionId();
88
+ if (sid)
89
+ cmd += ` resume ${sid}`;
90
+ }
91
+ return cmd;
92
+ }
93
+ /** The daemon's persisted session id (written from getSessionId()), for resume. */
94
+ storedSessionId() {
95
+ try {
96
+ const sid = readFileSync(join(this.instanceDir, "session-id"), "utf-8").trim();
97
+ return SESSION_ID_RE.test(sid) ? sid : null;
98
+ }
99
+ catch {
100
+ return null;
101
+ }
102
+ }
103
+ /**
104
+ * Per-instance MCP key. Instance names can be CJK (persona channels), and a
105
+ * settings file shared by every instance needs keys that cannot collide, so a
106
+ * non-ASCII name becomes an ASCII slug plus a hash of the original.
107
+ */
108
+ mcpKey(mcpName, instanceName) {
109
+ const ascii = instanceName.replace(/[^\x20-\x7E]/g, "");
110
+ if (ascii === instanceName)
111
+ return `agend-${mcpName}-${instanceName}`;
112
+ const slug = ascii.replace(/[^A-Za-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
113
+ const hash = createHash("md5").update(instanceName).digest("hex").slice(0, 8);
114
+ return slug ? `agend-${mcpName}-${slug}-${hash}` : `agend-${mcpName}-${hash}`;
115
+ }
116
+ /** `$XDG_CONFIG_HOME/muse/settings.json`, else `~/.config/muse/settings.json`. */
117
+ settingsPath() {
118
+ const base = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
119
+ return join(base, "muse", "settings.json");
120
+ }
121
+ writeConfig(config) {
122
+ this.workingDirectory = config.workingDirectory;
123
+ // Muse reads MCP servers from ONE file — the user-level settings.json. It
124
+ // has no project-level equivalent (checked: `muse init` scaffolds AGENTS.md
125
+ // and nothing else, and the binary documents a single `$CONFIG_DIR` path).
126
+ // So this writes into the user's own settings, which means two rules:
127
+ // every key we did not put there is preserved, and ours are namespaced per
128
+ // instance so instances sharing a machine cannot overwrite each other.
129
+ //
130
+ // Isolating this per instance would mean relocating XDG_CONFIG_HOME, which
131
+ // also moves auth.json — the user's login. Not worth doing blind; left as a
132
+ // follow-up for whoever needs per-instance muse credentials.
133
+ const settingsPath = this.settingsPath();
134
+ let root = {};
135
+ try {
136
+ root = JSON.parse(readFileSync(settingsPath, "utf-8"));
137
+ }
138
+ catch { /* new file */ }
139
+ if (typeof root.schema_version !== "number")
140
+ root.schema_version = 1;
141
+ const servers = (root.mcpServers ?? {});
142
+ // Drop our own stale entries whose wrapper script is gone (deleted instance,
143
+ // cleared instance dir). Never touch a key we did not write.
144
+ for (const [key, val] of Object.entries(servers)) {
145
+ if (!key.startsWith("agend-"))
146
+ continue;
147
+ const cmd = val?.command;
148
+ if (typeof cmd === "string" && !existsSync(cmd))
149
+ delete servers[key];
150
+ }
151
+ for (const [name, entry] of Object.entries(config.mcpServers)) {
152
+ const allEnv = { ...entry.env, AGEND_INSTANCE_NAME: config.instanceName };
153
+ // Same wrapper as grok/kiro. Two jobs: export the env explicitly rather
154
+ // than trusting the CLI to forward the entry's `env` block, and wait for
155
+ // the IPC socket to exist — a server that starts first would fail to
156
+ // connect and every fleet tool (reply/react/…) would be dead for the run.
157
+ const wrapperPath = join(this.instanceDir, `mcp-wrapper-${name}.sh`);
158
+ const envExports = Object.entries(allEnv)
159
+ .map(([k, v]) => `export ${k}='${String(v).replace(/'/g, "'\\''")}'`)
160
+ .join("\n");
161
+ // 0o700: the wrapper inlines sensitive env (tokens, socket paths).
162
+ writeFileSync(wrapperPath, `#!/bin/bash\n${envExports}\n# Wait for IPC socket to be ready (up to 10s)\nfor i in $(seq 1 20); do [ -S "$AGEND_SOCKET_PATH" ] && break; sleep 0.5; done\nexec ${entry.command} ${entry.args.map((a) => JSON.stringify(a)).join(" ")}\n`, { mode: 0o700 });
163
+ chmodSync(wrapperPath, 0o700);
164
+ // Entry shape per muse's own documentation: type/command/args/env/mode.
165
+ // "optional" so a server that fails to start degrades the session instead
166
+ // of stopping it.
167
+ servers[this.mcpKey(name, config.instanceName)] = {
168
+ type: "stdio",
169
+ command: wrapperPath,
170
+ args: [],
171
+ mode: "optional",
172
+ };
173
+ }
174
+ root.mcpServers = servers;
175
+ try {
176
+ mkdirSync(join(settingsPath, ".."), { recursive: true });
177
+ writeFileSync(settingsPath, JSON.stringify(root, null, 2));
178
+ }
179
+ catch { /* best effort — a muse without MCP still starts */ }
180
+ // `muse init` scaffolds AGENTS.md and the binary reads it as project rules,
181
+ // the same convention as codex and grok. Additive + idempotent via marker.
182
+ if (config.instructions) {
183
+ try {
184
+ appendWithMarker(join(config.workingDirectory, "AGENTS.md"), config.instanceName, config.instructions);
185
+ }
186
+ catch { /* best effort */ }
187
+ }
188
+ }
189
+ requiresDeliveryEnterRetry() {
190
+ // Measured, not inferred. An Enter that arrives in the same keystroke burst
191
+ // as the text is taken as a NEWLINE: `tmux send-keys "probe N" Enter`
192
+ // failed to submit three times out of three, and the drafts stacked up in
193
+ // the input box —
194
+ //
195
+ // ❯ probe 1
196
+ // probe 2
197
+ // probe 3
198
+ //
199
+ // The damage is not a lost message but a merged one: the next Enter submits
200
+ // the whole draft as a single turn. The daemon's waitForPasteSettle already
201
+ // opens the gap muse needs (a paste followed by Enter a second later
202
+ // submitted every time, including mid-turn), so this is insurance against
203
+ // the case where the settle wait is blind and falls back to a fixed delay.
204
+ //
205
+ // Safe on every delivery, both preconditions verified live: a bare Enter is
206
+ // a no-op at an empty idle prompt, and a no-op mid-turn with empty input.
207
+ return true;
208
+ }
209
+ getReadyPattern() {
210
+ // The ready screen carries the `Muse Code <version>` header and an empty
211
+ // `❯` input row. Both survive scrollback, which is fine — this pattern only
212
+ // has to say "the TUI is up"; getBusyPattern() is what says "not now".
213
+ return /❯|Muse Code \d/m;
214
+ }
215
+ /**
216
+ * The working line, which is on screen only while muse is generating.
217
+ *
218
+ * Required for the same reason grok and claude-code needed one: the input box
219
+ * (and therefore `❯`) stays visible the whole time muse works, so the ready
220
+ * pattern is effectively constant-true and the instance would never be seen
221
+ * as busy — no hang detection, and a frozen CLI reported as idle.
222
+ *
223
+ * Sampled from a live run. The phase word changes (`Thinking`, `Working`,
224
+ * `Double checking`) and the leading glyph cycles (◇ ◆ ◈), so neither is the
225
+ * anchor. What every working frame has, and no idle frame does, is the
226
+ * interrupt hint muse prints beside the elapsed timer:
227
+ *
228
+ * ◇ Thinking (2s · esc to interrupt)
229
+ * ◆ Double checking (4s · esc to interrupt)
230
+ *
231
+ * Anchoring on the glyph would be wrong in a way that matters: completed
232
+ * output lines start with `◆ ` too (`◆ Panes split the dark screen`), so a
233
+ * glyph-anchored pattern would pin a finished instance in `working` forever.
234
+ */
235
+ getBusyPattern() {
236
+ return /\(\s*\d+(?:\.\d+)?s\s*·\s*esc to interrupt\s*\)/;
237
+ }
238
+ getErrorPatterns() {
239
+ // NOTE: an Escape-interrupted run prints "interrupting run" in the status
240
+ // bar. That is normal user-initiated behaviour, not an error — nothing here
241
+ // matches it, and nothing that does should be added.
242
+ return [
243
+ { pattern: /rate.?limit|too many requests|\b429\b/i, type: "rate_limit", action: "failover", message: "Muse rate limit reached" },
244
+ { pattern: /unauthorized|authentication (failed|error)|\b401\b|muse login/i, type: "auth_error", action: "pause", message: "Muse authentication error" },
245
+ { pattern: /quota|usage limit|out of credits/i, type: "quota", action: "notify", message: "Muse quota exhausted" },
246
+ ];
247
+ }
248
+ getStartupDialogs() {
249
+ return [
250
+ // Workspace trust. `--trust-workspace` normally prevents this from ever
251
+ // appearing; it is still handled because an instance configured with
252
+ // skip_permissions: false gets neither flag and would otherwise hang
253
+ // here forever. Verified layout: a two-row menu, option 1 preselected,
254
+ // "Use Up/Down or 1/2, then Enter."
255
+ {
256
+ pattern: /Do you trust this workspace\?/,
257
+ keys: ["1", "Enter"],
258
+ description: "Muse workspace trust — choose 'Trust and continue'",
259
+ },
260
+ // Login is BLOCKING and cannot be auto-dismissed — the user has to
261
+ // complete it. Empty keys mean the daemon sends nothing but keeps
262
+ // treating the screen as not-ready, so a login page is never mistaken
263
+ // for the idle prompt.
264
+ {
265
+ pattern: /muse login|Log in to (Meta|continue)|device code/i,
266
+ keys: [],
267
+ description: "Muse login — wait for the user to authenticate (no auto-dismiss)",
268
+ },
269
+ ];
270
+ }
271
+ getRuntimeDialogs() {
272
+ return [
273
+ // Net for a tool-approval prompt arriving despite --disable-approval (an
274
+ // enterprise policy can pin approval on). Muse's menus are numbered with
275
+ // the first option preselected, same shape as the trust dialog.
276
+ {
277
+ pattern: /Allow this (tool|command)|Approve this (tool|command)|1\s+(Allow|Approve)/i,
278
+ keys: ["1", "Enter"],
279
+ description: "Muse tool approval — allow",
280
+ },
281
+ ];
282
+ }
283
+ getContextUsage() {
284
+ // Muse reports context only inside `/status` ("98% left · 23.8K used /
285
+ // 1008K"), not on the persistent status bar, so there is nothing a passive
286
+ // reader can see between turns. Returning a stale or invented number would
287
+ // be worse than none.
288
+ return null;
289
+ }
290
+ // Muse usage is collected by the daemon-owned localhost relay in
291
+ // muse-usage-relay.ts. Keeping this backend free of direct Meta requests is
292
+ // deliberate: the relay observes only response.subscription_usage frames and
293
+ // the model conversation remains byte-for-byte transparent.
294
+ getSessionId() {
295
+ // Sessions live at ~/.local/share/muse/sessions/<YYYY>/<MM>/<DD>/<uuid>/,
296
+ // filed by date rather than by workspace, so the workspace has to be read
297
+ // out of each session's own log (`route_facts` names the cwd near the top).
298
+ // Returns the most recently ACTIVE session started in this instance's
299
+ // directory, which is what the daemon persists for resume.
300
+ if (!this.workingDirectory)
301
+ return null;
302
+ try {
303
+ const root = join(homedir(), ".local", "share", "muse", "sessions");
304
+ let newestId = null;
305
+ let newestMtime = -1;
306
+ for (const sessionDir of museSessionDirs(root)) {
307
+ const name = sessionDir.slice(sessionDir.lastIndexOf("/") + 1);
308
+ if (!SESSION_ID_RE.test(name))
309
+ continue;
310
+ let head;
311
+ try {
312
+ const fd = readFileSync(join(sessionDir, "session.jsonl"), { encoding: "utf-8", flag: "r" });
313
+ head = fd.slice(0, SESSION_HEAD_BYTES);
314
+ }
315
+ catch {
316
+ continue;
317
+ }
318
+ if (museSessionCwd(head) !== this.workingDirectory)
319
+ continue;
320
+ // Activity = latest inner-file mtime. The directory's own mtime does not
321
+ // move when a log is appended, and is misleadingly recent for a session
322
+ // that was only just created — it must not outrank a resumed older
323
+ // session whose log was written to seconds ago.
324
+ let activity = -1;
325
+ try {
326
+ for (const f of readdirSync(sessionDir)) {
327
+ try {
328
+ const m = statSync(join(sessionDir, f)).mtimeMs;
329
+ if (m > activity)
330
+ activity = m;
331
+ }
332
+ catch { /* skip */ }
333
+ }
334
+ }
335
+ catch { /* unreadable */ }
336
+ if (activity > newestMtime) {
337
+ newestMtime = activity;
338
+ newestId = name;
339
+ }
340
+ }
341
+ return newestId;
342
+ }
343
+ catch {
344
+ return null;
345
+ }
346
+ }
347
+ // `/quit` is muse's own "quit when idle". The key chord is Ctrl+C pressed
348
+ // TWICE ("Press Ctrl-C again to quit") — kept as the fallback, with the count
349
+ // the TUI actually requires.
350
+ getQuitCommand() { return "/quit"; }
351
+ getQuitKey() { return "C-c"; }
352
+ getQuitKeyPresses() { return 2; }
353
+ getCompactCommand() { return "/compact"; }
354
+ getClearCommand() { return "/clear"; }
355
+ /**
356
+ * Escape, not Ctrl+C. Verified both ways on a live session: Escape mid-run
357
+ * put "interrupting run" in the status bar and returned the prompt with the
358
+ * partial answer kept, while Ctrl+C armed the quit confirmation ("Press
359
+ * Ctrl-C again to quit"). Cancelling with C-c would leave every instance one
360
+ * stray keypress from exiting.
361
+ */
362
+ getCancelKey() { return "Escape"; }
363
+ // `/effort` is in the TUI command list, so a level change needs no restart.
364
+ getEffortStrategy() { return "runtime"; }
365
+ // muse also accepts none|minimal|ultra, which AgEnD has no level for; the
366
+ // canonical five map straight through.
367
+ getEffortLevels() { return ["low", "medium", "high", "xhigh", "max"]; }
368
+ // `/model` opens an arrow-key picker, not a one-shot command → restart.
369
+ getModelSwitchStrategy() { return "restart"; }
370
+ async listModels() {
371
+ // muse has no models subcommand (the command table is: resume, exec,
372
+ // config, export, trace, skills, plugins, sandbox, schema, serve,
373
+ // session-message, mcp, auth, login, logout, init). This set was read off
374
+ // the live `/model` picker; the `-contributor` variants are the same models
375
+ // with content sharing enabled, which the picker spells out.
376
+ return [
377
+ { id: "muse-spark-1.3", label: "muse-spark-1.3" },
378
+ { id: "muse-spark-1.3-contributor", label: "muse-spark-1.3-contributor (shares content)" },
379
+ { id: "muse-spark-1.2", label: "muse-spark-1.2" },
380
+ { id: "muse-spark-1.2-contributor", label: "muse-spark-1.2-contributor (shares content)" },
381
+ ];
382
+ }
383
+ async probeCLIEnv() {
384
+ const { probeCliVersion } = await import("./types.js");
385
+ // The selected model is the one thing muse persists where we can read it.
386
+ let currentModel;
387
+ try {
388
+ const settings = JSON.parse(readFileSync(this.settingsPath(), "utf-8"));
389
+ if (typeof settings.model === "string")
390
+ currentModel = settings.model;
391
+ }
392
+ catch { /* best effort */ }
393
+ return { version: probeCliVersion(this.binaryPath), models: await this.listModels(), currentModel };
394
+ }
395
+ cleanup(config) {
396
+ try {
397
+ const settingsPath = this.settingsPath();
398
+ const root = JSON.parse(readFileSync(settingsPath, "utf-8"));
399
+ if (root.mcpServers) {
400
+ for (const name of Object.keys(config.mcpServers)) {
401
+ delete root.mcpServers[this.mcpKey(name, config.instanceName)];
402
+ }
403
+ writeFileSync(settingsPath, JSON.stringify(root, null, 2));
404
+ }
405
+ }
406
+ catch { /* best effort */ }
407
+ try {
408
+ removeMarker(join(config.workingDirectory, "AGENTS.md"), config.instanceName);
409
+ }
410
+ catch { /* best effort */ }
411
+ }
412
+ }
413
+ /** Every `<year>/<month>/<day>/<uuid>` directory under the session store. */
414
+ export function museSessionDirs(root) {
415
+ const out = [];
416
+ const children = (dir) => {
417
+ try {
418
+ return readdirSync(dir);
419
+ }
420
+ catch {
421
+ return [];
422
+ }
423
+ };
424
+ for (const year of children(root)) {
425
+ if (!/^\d{4}$/.test(year))
426
+ continue;
427
+ for (const month of children(join(root, year))) {
428
+ for (const day of children(join(root, year, month))) {
429
+ for (const session of children(join(root, year, month, day))) {
430
+ out.push(join(root, year, month, day, session));
431
+ }
432
+ }
433
+ }
434
+ }
435
+ return out;
436
+ }
437
+ //# sourceMappingURL=muse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"muse.js","sourceRoot":"","sources":["../../src/backend/muse.ts"],"names":[],"mappings":"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"}
@@ -36,6 +36,8 @@ export interface CliBackendConfig {
36
36
  agentPort?: number;
37
37
  /** Per-backend options merged from fleet defaults + instance config (e.g. { provider: "glm" }). */
38
38
  backendOptions?: Record<string, unknown>;
39
+ /** Daemon-owned localhost Muse usage relay, prepared before spawn. */
40
+ museBaseUrl?: string;
39
41
  }
40
42
  /** Action to take when an error pattern is detected in PTY output. */
41
43
  export type ErrorActionType = "notify" | "failover" | "restart" | "pause";
@@ -52,6 +54,8 @@ export interface ErrorPattern {
52
54
  * when the match can't be re-derived. Receives the LAST match in the pane,
53
55
  * i.e. the most recent occurrence. */
54
56
  formatMessage?: (match: RegExpMatchArray) => string;
57
+ /** Run the backend's live quota check before surfacing a quota notice. */
58
+ verifyQuota?: boolean;
55
59
  /** Skip the 5-min per-type notification cooldown so every occurrence notifies
56
60
  * (e.g. Kiro "Response timed out" — each timeout should reach the user). */
57
61
  skipCooldown?: boolean;
@@ -150,6 +154,33 @@ export interface RuntimeDialog {
150
154
  * ignored.
151
155
  */
152
156
  holdOnly?: boolean;
157
+ /**
158
+ * This dialog owns stdin while it is visible. Unlike a generic runtime
159
+ * dialog, the daemon exposes the state separately so the pane monitor can
160
+ * suppress false stuck/auto-pause decisions while a CLI is waiting for a
161
+ * human choice.
162
+ */
163
+ inputBlocked?: boolean;
164
+ /**
165
+ * The daemon may re-read the pane under the write lock after sending these
166
+ * keys. This is intentionally opt-in: most dialogs are fire-and-forget,
167
+ * while safety-critical dialogs must prove that the prompt disappeared
168
+ * before any follow-up system message is submitted.
169
+ */
170
+ verifyAfterKeys?: boolean;
171
+ /**
172
+ * Send the notice only after {@link verifyAfterKeys} observes this dialog
173
+ * gone. The text is code-owned and must never include command arguments.
174
+ */
175
+ postDismissNotice?: {
176
+ text: string;
177
+ label: string;
178
+ };
179
+ /**
180
+ * A key used only for the daemon's generation fence. Implementations must
181
+ * return a stable, non-secret value; never include pane contents or tokens.
182
+ */
183
+ autoResolutionKey?: string;
153
184
  }
154
185
  /**
155
186
  * A self-clearing TUI phase during which an input row may be visible but Enter
@@ -284,6 +315,19 @@ export interface CliBackend {
284
315
  * false.
285
316
  */
286
317
  hasPeriodicPaneRedraw?(): boolean;
318
+ /**
319
+ * Positive, structural proof that a periodically-redrawing TUI is parked at
320
+ * its live input prompt. This is deliberately stronger than
321
+ * `getReadyPattern()`: many TUIs leave their header, context meter and even
322
+ * input chrome visible while a turn is still running. The daemon may use
323
+ * two consecutive positive captures to recover working -> idle even when
324
+ * cosmetic animation prevents the ordinary silence debounce from firing.
325
+ *
326
+ * Return false for an unfamiliar layout. False negatives merely retain the
327
+ * existing working state; false positives can retire Cancel and admit a new
328
+ * delivery into a busy CLI.
329
+ */
330
+ isPeriodicRedrawIdlePane?(pane: string): boolean;
287
331
  /** Build the shell command string to launch the CLI in a tmux window. */
288
332
  buildCommand(config: CliBackendConfig): string;
289
333
  /** Write all config files the CLI needs before launch. */
@@ -432,6 +476,16 @@ export interface CliBackend {
432
476
  currentModel?: string;
433
477
  models: ModelOption[];
434
478
  }>;
479
+ /**
480
+ * Ask the CLI to refresh its OWN model catalog before the next probe reads it.
481
+ *
482
+ * For a backend whose probe only reads a file the CLI maintains (codex's
483
+ * models_cache.json), re-reading that file is not a refresh: the list is as
484
+ * old as the last time the CLI itself fetched it. This makes the CLI fetch.
485
+ * Called only by an explicit refresh — never by the startup or /model probe —
486
+ * and it may throw; the caller reports a failed refresh and keeps the old list.
487
+ */
488
+ refreshModelCatalog?(): Promise<void>;
435
489
  }
436
490
  export declare function resolveBinary(name: string, fallbackDirs?: readonly string[]): string;
437
491
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/backend/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/backend/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AA0G1C,mEAAmE;AACnE,MAAM,CAAC,MAAM,4BAA4B,GAAG,KAAK,CAAC;AAElD;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,KAAK,CAAC;AAE/C;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,4BAA4B,GAAG,yBAAyB,CAAC;AAEnG,4EAA4E;AAC5E,MAAM,UAAU,eAAe,CAAC,UAAkB;IAChD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,4BAA4B,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;QACvJ,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,SAAS,CAAC;IAC7D,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,SAAS,CAAC;IAAC,CAAC;AAC/B,CAAC;AAgZD;;;;GAIG;AACH,SAAS,gBAAgB;IACvB,MAAM,IAAI,GAAG;QACX,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC;QACzB,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC;QAChC,IAAI,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,KAAK,CAAC;QACrC,gBAAgB;QAChB,UAAU;QACV,MAAM;KACP,CAAC;IAEF,yEAAyE;IACzE,0EAA0E;IAC1E,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;QAChE,KAAK,MAAM,OAAO,IAAI,WAAW,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC;YAChE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IAAC,MAAM,CAAC,CAAC,qBAAqB,CAAC,CAAC;IAEjC,wDAAwD;IACxD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE;YACnD,QAAQ,EAAE,OAAO;YACjB,OAAO,EAAE,IAAI;YACb,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;SACpC,CAAC,CAAC,IAAI,EAAE,CAAC;QACV,IAAI,MAAM;YAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC,CAAC,2CAA2C,CAAC,CAAC;IAEvD,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,YAAgC;IAC1E,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7E,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC,CAAC,4CAA4C,CAAC,CAAC;IAExD,KAAK,MAAM,GAAG,IAAI,YAAY,IAAI,gBAAgB,EAAE,EAAE,CAAC;QACrD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAClC,IAAI,CAAC;YACH,UAAU,CAAC,SAAS,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;YACtC,IAAI,QAAQ,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE;gBAAE,OAAO,SAAS,CAAC;QACrD,CAAC;QAAC,MAAM,CAAC,CAAC,wBAAwB,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,IAAI,CAAC,CAAC,wDAAwD;AACvE,CAAC;AAED;;;;;;GAMG;AACH,6EAA6E;AAC7E,2EAA2E;AAC3E,0EAA0E;AAC1E,yEAAyE;AACzE,MAAM,aAAa,GAAG,wBAAwB,CAAC;AAC/C;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC1C,IAAI,CAAC,+BAA+B,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,yBAAyB,MAAM,EAAE,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,uBAAuB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,iBAAiB,aAAa,EAAE,CAAC,CAAC;IAChG,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CAAC,2BAA2B,QAAQ,mDAAmD,CAAC,CAAC;IAC1G,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,kFAAkF;AAClF,MAAM,sBAAsB,GAA2B;IACrD,aAAa,EAAE,kDAAkD;IACjE,UAAU,EAAE,iEAAiE;IAC7E,OAAO,EAAE,wBAAwB;IACjC,YAAY,EAAE,UAAU;IACxB,UAAU,EAAE,GAAG,EAAG,iDAAiD;IACnE,0EAA0E;IAC1E,8DAA8D;IAC9D,aAAa,EAAE,2BAA2B;IAC1C,MAAM,EAAE,QAAQ,EAAG,gDAAgD;CACpE,CAAC;AAEF,kEAAkE;AAClE,MAAM,UAAU,iBAAiB,CAAC,WAAmB,EAAE,KAAa;IAClE,MAAM,OAAO,GAAG,sBAAsB,CAAC,WAAW,CAAC,CAAC;IACpD,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC,CAAC,iCAAiC;IAC5D,OAAO,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC7B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,WAAmB,EAAE,KAAa;IACpE,IAAI,CAAC,iBAAiB,CAAC,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC;QAC3C,OAAO,CAAC,IAAI,CAAC,kBAAkB,KAAK,uCAAuC,WAAW,0BAA0B,CAAC,CAAC;IACpH,CAAC;AACH,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,UAAU,CAAC,CAAS;IAClC,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;AACzC,CAAC"}
@@ -4,6 +4,12 @@ export declare class AccessManager {
4
4
  private statePath;
5
5
  private state;
6
6
  private failedAttempts;
7
+ /**
8
+ * The mode that came out of the state file, or undefined when the file had
9
+ * none. Kept separately because the constructor fills `state.mode` in from
10
+ * the config when the file is silent, after which the two are indistinguishable.
11
+ */
12
+ private persistedMode?;
7
13
  constructor(config: AccessConfig, statePath: string);
8
14
  private persist;
9
15
  private pruneExpired;
@@ -13,6 +19,20 @@ export declare class AccessManager {
13
19
  confirmCode(code: string, callerUserId?: string): boolean;
14
20
  setMode(mode: "pairing" | "locked" | "open"): void;
15
21
  getMode(): "pairing" | "locked" | "open";
22
+ /**
23
+ * The configured mode that the state file is overriding, or null when they
24
+ * agree or nothing was persisted.
25
+ *
26
+ * State wins on purpose — a pairing that happened at runtime must survive a
27
+ * fleet restart — but the first `persist()` freezes whatever the mode was at
28
+ * the time, and from then on editing `access.mode` in fleet.yaml changes
29
+ * nothing. Without this, that reads as "my config edit did nothing" with no
30
+ * way to find out why.
31
+ *
32
+ * Reported rather than logged from here: the CLI also builds an AccessManager
33
+ * with a synthetic config, where a mismatch means nothing.
34
+ */
35
+ overriddenConfigMode(): "pairing" | "locked" | "open" | null;
16
36
  getAllowedUsers(): (number | string)[];
17
37
  removeUser(userId: number | string): boolean;
18
38
  }
@@ -5,6 +5,12 @@ export class AccessManager {
5
5
  statePath;
6
6
  state;
7
7
  failedAttempts = new Map();
8
+ /**
9
+ * The mode that came out of the state file, or undefined when the file had
10
+ * none. Kept separately because the constructor fills `state.mode` in from
11
+ * the config when the file is silent, after which the two are indistinguishable.
12
+ */
13
+ persistedMode;
8
14
  constructor(config, statePath) {
9
15
  this.config = config;
10
16
  this.statePath = statePath;
@@ -13,6 +19,7 @@ export class AccessManager {
13
19
  try {
14
20
  const raw = readFileSync(statePath, "utf8");
15
21
  const saved = JSON.parse(raw);
22
+ this.persistedMode = saved.mode;
16
23
  this.state = {
17
24
  mode: saved.mode,
18
25
  allowed_users: saved.allowed_users ?? [],
@@ -138,6 +145,24 @@ export class AccessManager {
138
145
  getMode() {
139
146
  return this.state.mode ?? this.config.mode;
140
147
  }
148
+ /**
149
+ * The configured mode that the state file is overriding, or null when they
150
+ * agree or nothing was persisted.
151
+ *
152
+ * State wins on purpose — a pairing that happened at runtime must survive a
153
+ * fleet restart — but the first `persist()` freezes whatever the mode was at
154
+ * the time, and from then on editing `access.mode` in fleet.yaml changes
155
+ * nothing. Without this, that reads as "my config edit did nothing" with no
156
+ * way to find out why.
157
+ *
158
+ * Reported rather than logged from here: the CLI also builds an AccessManager
159
+ * with a synthetic config, where a mismatch means nothing.
160
+ */
161
+ overriddenConfigMode() {
162
+ if (this.persistedMode === undefined)
163
+ return null;
164
+ return this.persistedMode === this.config.mode ? null : this.config.mode;
165
+ }
141
166
  getAllowedUsers() {
142
167
  return [...this.state.allowed_users];
143
168
  }