@songsid/agend 2.3.0-beta.1 → 2.3.0-beta.11

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 (357) hide show
  1. package/dist/agent-cli-instructions.md +5 -2
  2. package/dist/agent-cli.js +43 -7
  3. package/dist/agent-cli.js.map +1 -1
  4. package/dist/agent-endpoint.js +4 -0
  5. package/dist/agent-endpoint.js.map +1 -1
  6. package/dist/agent-file-read.d.ts +14 -6
  7. package/dist/agent-file-read.js +207 -19
  8. package/dist/agent-file-read.js.map +1 -1
  9. package/dist/agent-whats-new.d.ts +11 -0
  10. package/dist/agent-whats-new.js +29 -15
  11. package/dist/agent-whats-new.js.map +1 -1
  12. package/dist/auth-api.d.ts +30 -1
  13. package/dist/auth-api.js +45 -13
  14. package/dist/auth-api.js.map +1 -1
  15. package/dist/authority/authority-state.d.ts +38 -0
  16. package/dist/authority/authority-state.js +114 -0
  17. package/dist/authority/authority-state.js.map +1 -0
  18. package/dist/authority/session-authorizations.d.ts +43 -0
  19. package/dist/authority/session-authorizations.js +102 -0
  20. package/dist/authority/session-authorizations.js.map +1 -0
  21. package/dist/authority/web-authority.d.ts +120 -0
  22. package/dist/authority/web-authority.js +157 -0
  23. package/dist/authority/web-authority.js.map +1 -0
  24. package/dist/backend/claude-code.d.ts +2 -2
  25. package/dist/backend/claude-code.js +10 -5
  26. package/dist/backend/claude-code.js.map +1 -1
  27. package/dist/backend/types.d.ts +14 -0
  28. package/dist/backend/types.js +25 -0
  29. package/dist/backend/types.js.map +1 -1
  30. package/dist/backend-availability.d.ts +120 -0
  31. package/dist/backend-availability.js +396 -0
  32. package/dist/backend-availability.js.map +1 -0
  33. package/dist/backend-command.d.ts +21 -3
  34. package/dist/backend-command.js +23 -4
  35. package/dist/backend-command.js.map +1 -1
  36. package/dist/bundled-skills.d.ts +14 -0
  37. package/dist/bundled-skills.js +29 -0
  38. package/dist/bundled-skills.js.map +1 -0
  39. package/dist/cache-analysis.d.ts +47 -1
  40. package/dist/cache-analysis.js +68 -8
  41. package/dist/cache-analysis.js.map +1 -1
  42. package/dist/cache-ledger.d.ts +16 -3
  43. package/dist/cache-ledger.js +33 -13
  44. package/dist/cache-ledger.js.map +1 -1
  45. package/dist/cache-report-tool.d.ts +17 -0
  46. package/dist/cache-report-tool.js +40 -0
  47. package/dist/cache-report-tool.js.map +1 -0
  48. package/dist/cache-service.d.ts +70 -3
  49. package/dist/cache-service.js +178 -17
  50. package/dist/cache-service.js.map +1 -1
  51. package/dist/channel/adapters/discord.d.ts +7 -0
  52. package/dist/channel/adapters/discord.js +35 -0
  53. package/dist/channel/adapters/discord.js.map +1 -1
  54. package/dist/channel/mcp-tools.js +22 -10
  55. package/dist/channel/mcp-tools.js.map +1 -1
  56. package/dist/channel/types.d.ts +6 -0
  57. package/dist/classic-channel-manager.d.ts +10 -5
  58. package/dist/classic-channel-manager.js +12 -9
  59. package/dist/classic-channel-manager.js.map +1 -1
  60. package/dist/cli.js +130 -31
  61. package/dist/cli.js.map +1 -1
  62. package/dist/config-validator.js +103 -4
  63. package/dist/config-validator.js.map +1 -1
  64. package/dist/daemon.d.ts +7 -0
  65. package/dist/daemon.js +63 -16
  66. package/dist/daemon.js.map +1 -1
  67. package/dist/decision-list.d.ts +25 -0
  68. package/dist/decision-list.js +30 -0
  69. package/dist/decision-list.js.map +1 -0
  70. package/dist/delivery-outbox.d.ts +10 -0
  71. package/dist/delivery-outbox.js +12 -1
  72. package/dist/delivery-outbox.js.map +1 -1
  73. package/dist/fleet-context.d.ts +10 -0
  74. package/dist/fleet-manager.d.ts +417 -11
  75. package/dist/fleet-manager.js +1387 -109
  76. package/dist/fleet-manager.js.map +1 -1
  77. package/dist/fleet-traffic.d.ts +74 -0
  78. package/dist/fleet-traffic.js +196 -0
  79. package/dist/fleet-traffic.js.map +1 -0
  80. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +20 -5
  81. package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +6 -1
  82. package/dist/general-knowledge/skills/multi-channel/SKILL.md +3 -2
  83. package/dist/general-knowledge/skills/persona-emoji/SKILL.md +1 -1
  84. package/dist/general-knowledge/skills/web-appearance/SKILL.md +257 -23
  85. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +478 -0
  86. package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +1 -1
  87. package/dist/human-delivery-receipts.d.ts +24 -1
  88. package/dist/human-delivery-receipts.js +64 -11
  89. package/dist/human-delivery-receipts.js.map +1 -1
  90. package/dist/instance-config-impact.js +3 -1
  91. package/dist/instance-config-impact.js.map +1 -1
  92. package/dist/instance-names.d.ts +4 -0
  93. package/dist/instance-names.js +12 -0
  94. package/dist/instance-names.js.map +1 -0
  95. package/dist/instructions.d.ts +12 -1
  96. package/dist/instructions.js +13 -2
  97. package/dist/instructions.js.map +1 -1
  98. package/dist/locale.js +100 -8
  99. package/dist/locale.js.map +1 -1
  100. package/dist/ls-attach-resolve.d.ts +95 -0
  101. package/dist/ls-attach-resolve.js +174 -0
  102. package/dist/ls-attach-resolve.js.map +1 -0
  103. package/dist/memory-hogs.d.ts +27 -0
  104. package/dist/memory-hogs.js +124 -0
  105. package/dist/memory-hogs.js.map +1 -0
  106. package/dist/outbound-handlers.d.ts +10 -0
  107. package/dist/outbound-handlers.js +122 -2
  108. package/dist/outbound-handlers.js.map +1 -1
  109. package/dist/outbound-schemas.d.ts +164 -4
  110. package/dist/outbound-schemas.js +99 -3
  111. package/dist/outbound-schemas.js.map +1 -1
  112. package/dist/public-web-gateway.js +8 -2
  113. package/dist/public-web-gateway.js.map +1 -1
  114. package/dist/public-web-link.d.ts +9 -0
  115. package/dist/public-web-link.js +8 -0
  116. package/dist/public-web-link.js.map +1 -1
  117. package/dist/quickstart-api.d.ts +10 -1
  118. package/dist/quickstart-api.js +12 -4
  119. package/dist/quickstart-api.js.map +1 -1
  120. package/dist/reply-buttons-controller.d.ts +4 -0
  121. package/dist/reply-buttons-controller.js +2 -2
  122. package/dist/reply-buttons-controller.js.map +1 -1
  123. package/dist/restart-progress.d.ts +65 -1
  124. package/dist/restart-progress.js +236 -10
  125. package/dist/restart-progress.js.map +1 -1
  126. package/dist/rollout-index.d.ts +5 -0
  127. package/dist/rollout-index.js +26 -5
  128. package/dist/rollout-index.js.map +1 -1
  129. package/dist/scheduler/scheduler.d.ts +12 -0
  130. package/dist/scheduler/scheduler.js +83 -10
  131. package/dist/scheduler/scheduler.js.map +1 -1
  132. package/dist/service-installer.d.ts +2 -1
  133. package/dist/service-installer.js +18 -3
  134. package/dist/service-installer.js.map +1 -1
  135. package/dist/settings-api.d.ts +19 -0
  136. package/dist/settings-api.js +137 -2
  137. package/dist/settings-api.js.map +1 -1
  138. package/dist/settings-change.js +104 -0
  139. package/dist/settings-change.js.map +1 -1
  140. package/dist/settings-effect.js +17 -1
  141. package/dist/settings-effect.js.map +1 -1
  142. package/dist/tmux-manager.d.ts +5 -0
  143. package/dist/tmux-manager.js +16 -0
  144. package/dist/tmux-manager.js.map +1 -1
  145. package/dist/tool-permissions.d.ts +4 -6
  146. package/dist/tool-permissions.js +53 -5
  147. package/dist/tool-permissions.js.map +1 -1
  148. package/dist/topic-commands.d.ts +7 -1
  149. package/dist/topic-commands.js +18 -4
  150. package/dist/topic-commands.js.map +1 -1
  151. package/dist/types.d.ts +48 -1
  152. package/dist/ui/app-effects.js +77 -31
  153. package/dist/ui/chat-ambient.js +307 -0
  154. package/dist/ui/chat-effect-posters.js +8 -8
  155. package/dist/ui/chat-effects.js +101 -13
  156. package/dist/ui/chat-render.js +21 -3
  157. package/dist/ui/chat-strings.js +59 -6
  158. package/dist/ui/chat-thread.js +159 -21
  159. package/dist/ui/effect-trial-controller.js +13 -8
  160. package/dist/ui/effect-trial-panel.js +19 -16
  161. package/dist/ui/fleet-cache.js +23 -1
  162. package/dist/ui/fleet-canvas-layout.js +111 -0
  163. package/dist/ui/fleet-canvas.js +525 -0
  164. package/dist/ui/fleet-org.js +27 -12
  165. package/dist/ui/fleet-traffic.js +343 -0
  166. package/dist/ui/fleet-usage.js +401 -0
  167. package/dist/ui/panel-chat.js +154 -49
  168. package/dist/ui/panel-details.js +2 -1
  169. package/dist/ui/panel-fleet.js +43 -17
  170. package/dist/ui/panel-settings.js +26 -8
  171. package/dist/ui/preview.js +3 -2
  172. package/dist/ui/settings-appearance.js +42 -18
  173. package/dist/ui/settings-catalog.js +92 -0
  174. package/dist/ui/settings-dialogs.js +40 -12
  175. package/dist/ui/settings-effects.js +4 -3
  176. package/dist/ui/settings-guests.js +117 -0
  177. package/dist/ui/settings-learn.js +25 -0
  178. package/dist/ui/settings-model.js +15 -6
  179. package/dist/ui/settings-mods.js +23 -9
  180. package/dist/ui/settings-owner-effects.js +9 -9
  181. package/dist/ui/settings-strings.js +120 -42
  182. package/dist/ui/settings-web-authority.js +91 -0
  183. package/dist/ui/shared/agend-auth.js +1 -1
  184. package/dist/ui/shared/app-i18n.js +4 -2
  185. package/dist/ui/shared/app-prefs.js +5 -4
  186. package/dist/ui/shared/app-route.js +19 -1
  187. package/dist/ui/shared/app-session.js +2 -0
  188. package/dist/ui/shared/app-shell.js +92 -27
  189. package/dist/ui/shared/app-store.js +26 -1
  190. package/dist/ui/shared/app-stream.js +3 -1
  191. package/dist/ui/shared/app-themes.js +24 -6
  192. package/dist/ui/shared/app.css +365 -17
  193. package/dist/ui/shared/app.js +21 -14
  194. package/dist/ui/shared/card-strings.js +4 -0
  195. package/dist/ui/shared/effect-app-runtime.js +68 -19
  196. package/dist/ui/shared/effect-chat-runtime.js +16 -3
  197. package/dist/ui/shared/effect-frame.js +26 -7
  198. package/dist/ui/shared/effect-geometry.js +24 -9
  199. package/dist/ui/shared/effect-policy.js +21 -7
  200. package/dist/ui/shared/effect-profiler.js +31 -9
  201. package/dist/ui/shared/effect-registry.js +87 -48
  202. package/dist/ui/shared/effect-stock-snapshot.js +9 -0
  203. package/dist/ui/shared/effect-stock-trust.js +62 -10
  204. package/dist/ui/shared/effect-trial-shadow.js +62 -0
  205. package/dist/ui/shared/effect-trial-source.js +1 -1
  206. package/dist/ui/shared/effect-trial-stage.js +54 -31
  207. package/dist/ui/shared/effect-trial.css +40 -0
  208. package/dist/ui/shared/fx-motion.js +67 -0
  209. package/dist/ui/shared/identity-card.js +75 -4
  210. package/dist/ui/shared/identity-color.js +3 -3
  211. package/dist/ui/shared/instance-nav.js +194 -28
  212. package/dist/ui/shared/panel-view.js +24 -4
  213. package/dist/ui/shared/tokens.css +9 -3
  214. package/dist/ui/shared/ui-icons.js +1 -0
  215. package/dist/ui/shared/usage-dialog.js +22 -2
  216. package/dist/ui/shared/view-strings.js +68 -2
  217. package/dist/ui/shared/web-authorize.js +151 -0
  218. package/dist/ui/signin.html +1 -1
  219. package/dist/ui/web-terminal/terminal.css +4 -4
  220. package/dist/usage/providers.d.ts +28 -0
  221. package/dist/usage/providers.js +126 -36
  222. package/dist/usage/providers.js.map +1 -1
  223. package/dist/usage-report.d.ts +158 -0
  224. package/dist/usage-report.js +226 -0
  225. package/dist/usage-report.js.map +1 -0
  226. package/dist/usage-rollup.d.ts +51 -0
  227. package/dist/usage-rollup.js +168 -0
  228. package/dist/usage-rollup.js.map +1 -0
  229. package/dist/view-api.d.ts +39 -0
  230. package/dist/view-api.js +65 -4
  231. package/dist/view-api.js.map +1 -1
  232. package/dist/web-ambient.d.ts +72 -0
  233. package/dist/web-ambient.js +161 -0
  234. package/dist/web-ambient.js.map +1 -0
  235. package/dist/web-api.d.ts +69 -5
  236. package/dist/web-api.js +362 -45
  237. package/dist/web-api.js.map +1 -1
  238. package/dist/web-appearance-policy.d.ts +4 -6
  239. package/dist/web-appearance-policy.js +5 -12
  240. package/dist/web-appearance-policy.js.map +1 -1
  241. package/dist/web-appearance-tools.d.ts +3 -0
  242. package/dist/web-appearance-tools.js +22 -3
  243. package/dist/web-appearance-tools.js.map +1 -1
  244. package/dist/web-appearance-view.d.ts +27 -2
  245. package/dist/web-appearance-view.js +129 -14
  246. package/dist/web-appearance-view.js.map +1 -1
  247. package/dist/web-appearance.d.ts +17 -3
  248. package/dist/web-appearance.js +82 -7
  249. package/dist/web-appearance.js.map +1 -1
  250. package/dist/web-asset-parts.d.ts +5 -10
  251. package/dist/web-asset-parts.js +3 -3
  252. package/dist/web-asset-parts.js.map +1 -1
  253. package/dist/web-auth.js +3 -1
  254. package/dist/web-auth.js.map +1 -1
  255. package/dist/web-card.d.ts +14 -0
  256. package/dist/web-card.js +40 -6
  257. package/dist/web-card.js.map +1 -1
  258. package/dist/web-channel-echo.d.ts +7 -1
  259. package/dist/web-channel-echo.js +6 -2
  260. package/dist/web-channel-echo.js.map +1 -1
  261. package/dist/web-chat-history.d.ts +50 -0
  262. package/dist/web-chat-history.js +87 -5
  263. package/dist/web-chat-history.js.map +1 -1
  264. package/dist/web-commands.d.ts +1 -0
  265. package/dist/web-effect-bootstrap.d.ts +12 -0
  266. package/dist/web-effect-bootstrap.js +49 -0
  267. package/dist/web-effect-bootstrap.js.map +1 -0
  268. package/dist/web-effect-bundle.js +46 -1
  269. package/dist/web-effect-bundle.js.map +1 -1
  270. package/dist/web-effect-playback.d.ts +30 -0
  271. package/dist/web-effect-playback.js +71 -0
  272. package/dist/web-effect-playback.js.map +1 -0
  273. package/dist/web-effect-profiles.d.ts +4 -4
  274. package/dist/web-effect-service.d.ts +11 -4
  275. package/dist/web-effect-service.js +28 -5
  276. package/dist/web-effect-service.js.map +1 -1
  277. package/dist/web-effect-tools.d.ts +1 -0
  278. package/dist/web-effect-tools.js +8 -5
  279. package/dist/web-effect-tools.js.map +1 -1
  280. package/dist/web-effect-trials.d.ts +4 -4
  281. package/dist/web-effect-trials.js +6 -6
  282. package/dist/web-effect-trials.js.map +1 -1
  283. package/dist/web-effect-upload.d.ts +2 -4
  284. package/dist/web-effect-upload.js +3 -8
  285. package/dist/web-effect-upload.js.map +1 -1
  286. package/dist/web-effect-worker.d.ts +1 -1
  287. package/dist/web-effect-worker.js +2 -2
  288. package/dist/web-effect-worker.js.map +1 -1
  289. package/dist/web-effect.d.ts +14 -0
  290. package/dist/web-effect.js +21 -0
  291. package/dist/web-effect.js.map +1 -1
  292. package/dist/web-guest-access.d.ts +125 -0
  293. package/dist/web-guest-access.js +234 -0
  294. package/dist/web-guest-access.js.map +1 -0
  295. package/dist/web-guest-rooms.d.ts +82 -0
  296. package/dist/web-guest-rooms.js +135 -0
  297. package/dist/web-guest-rooms.js.map +1 -0
  298. package/dist/web-identity-color.d.ts +1 -1
  299. package/dist/web-identity-color.js +2 -2
  300. package/dist/web-identity-color.js.map +1 -1
  301. package/dist/web-identity-palette.d.ts +1 -1
  302. package/dist/web-identity-palette.js +2 -2
  303. package/dist/web-identity-palette.js.map +1 -1
  304. package/dist/web-image-meta.d.ts +13 -0
  305. package/dist/web-image-meta.js +62 -0
  306. package/dist/web-image-meta.js.map +1 -1
  307. package/dist/web-login.d.ts +47 -0
  308. package/dist/web-login.js +115 -0
  309. package/dist/web-login.js.map +1 -1
  310. package/dist/web-mod-agent.d.ts +1 -1
  311. package/dist/web-mod-agent.js +12 -8
  312. package/dist/web-mod-agent.js.map +1 -1
  313. package/dist/web-mod-bundle.d.ts +14 -1
  314. package/dist/web-mod-bundle.js +68 -3
  315. package/dist/web-mod-bundle.js.map +1 -1
  316. package/dist/web-mod-export.d.ts +9 -0
  317. package/dist/web-mod-export.js +21 -0
  318. package/dist/web-mod-export.js.map +1 -1
  319. package/dist/web-mod-store.d.ts +7 -1
  320. package/dist/web-mod-store.js +21 -7
  321. package/dist/web-mod-store.js.map +1 -1
  322. package/dist/web-prefs.d.ts +14 -0
  323. package/dist/web-prefs.js +24 -4
  324. package/dist/web-prefs.js.map +1 -1
  325. package/dist/web-preview.d.ts +6 -2
  326. package/dist/web-preview.js +4 -2
  327. package/dist/web-preview.js.map +1 -1
  328. package/dist/web-returning-device.d.ts +41 -0
  329. package/dist/web-returning-device.js +57 -5
  330. package/dist/web-returning-device.js.map +1 -1
  331. package/dist/web-session-authorization.d.ts +132 -0
  332. package/dist/web-session-authorization.js +193 -0
  333. package/dist/web-session-authorization.js.map +1 -0
  334. package/dist/web-session.d.ts +70 -10
  335. package/dist/web-session.js +137 -22
  336. package/dist/web-session.js.map +1 -1
  337. package/dist/web-settings-patch.d.ts +49 -2
  338. package/dist/web-settings-patch.js +145 -1
  339. package/dist/web-settings-patch.js.map +1 -1
  340. package/dist/web-settings-tools.d.ts +89 -0
  341. package/dist/web-settings-tools.js +270 -0
  342. package/dist/web-settings-tools.js.map +1 -0
  343. package/dist/web-shell-routes.d.ts +1 -1
  344. package/dist/web-shell-routes.js +1 -1
  345. package/dist/web-shell-routes.js.map +1 -1
  346. package/dist/web-theme-store.d.ts +39 -0
  347. package/dist/web-theme-store.js +122 -11
  348. package/dist/web-theme-store.js.map +1 -1
  349. package/dist/web-theme.d.ts +2 -0
  350. package/dist/web-theme.js +10 -1
  351. package/dist/web-theme.js.map +1 -1
  352. package/dist/web-upload.d.ts +13 -0
  353. package/dist/web-upload.js +39 -3
  354. package/dist/web-upload.js.map +1 -1
  355. package/dist/workflow-templates/default.md +1 -1
  356. package/package.json +1 -1
  357. package/templates/systemd.service.ejs +8 -0
@@ -12,6 +12,7 @@
12
12
  * the web chat only present it (fleet-manager.ts, web-commands.ts).
13
13
  */
14
14
  import type { ModelOption } from "./backend/types.js";
15
+ import type { AvailabilityState } from "./backend-availability.js";
15
16
  /** The word that picks the inherited value of a model or an effort, in the typed form and in the menus. */
16
17
  export declare const BACKEND_DEFAULT = "default";
17
18
  export interface BackendCommandDeps {
@@ -19,8 +20,15 @@ export interface BackendCommandDeps {
19
20
  currentBackend(instance: string): string;
20
21
  /** What the instance runs on now, as a reply shows it: "claude-code · opus". */
21
22
  currentDisplay(instance: string): string;
22
- /** Backends whose CLI is installed on this host, found the way the launch finds it; never removed or test-only ones. */
23
- installedBackends(): string[];
23
+ /**
24
+ * #2072: every backend of the catalog (never removed or test-only ones) with what this host's published snapshot says
25
+ * about it — installed, signed in, new enough. Read only; never probes.
26
+ */
27
+ availability(): Array<{
28
+ backend: string;
29
+ state: AvailabilityState;
30
+ minVersion?: string | null;
31
+ }>;
24
32
  /** The models `/model` would offer on that backend; empty when none are known. */
25
33
  models(backend: string): Promise<ModelOption[]>;
26
34
  /** A name the backend accepts beyond its list (claude-code's aliases and account catalog). */
@@ -45,11 +53,21 @@ export interface BackendPlan {
45
53
  model: string | null;
46
54
  effort: string | null;
47
55
  }
48
- /** One choice of a step. `token` is the argument it adds; `label` what the button says. */
56
+ /**
57
+ * One choice of a step. `token` is the argument it adds; `label` what the button says. `disabled`: why it cannot be
58
+ * chosen here (shown, not hidden — a surface that cannot disable an option shows the reason and the step refuses it).
59
+ */
49
60
  export interface BackendChoice {
50
61
  token: string;
51
62
  label: string;
63
+ disabled?: string;
52
64
  }
65
+ /** Why a backend cannot be chosen, or null when it can (usable, or unknown: checked again when applied). */
66
+ export declare function backendUnusable(t: BackendCommandDeps["t"], row: {
67
+ backend: string;
68
+ state: AvailabilityState;
69
+ minVersion?: string | null;
70
+ }): string | null;
53
71
  export type BackendStep = {
54
72
  kind: "choose";
55
73
  step: "backend" | "model" | "effort";
@@ -2,6 +2,15 @@
2
2
  export const BACKEND_DEFAULT = "default";
3
3
  /** The most choices one step offers: a Discord select menu's 25, less "default". */
4
4
  const MAX_MODEL_CHOICES = 24;
5
+ /** Why a backend cannot be chosen, or null when it can (usable, or unknown: checked again when applied). */
6
+ export function backendUnusable(t, row) {
7
+ switch (row.state) {
8
+ case "not_installed": return t("backend.reason_not_installed");
9
+ case "not_signed_in": return t("backend.reason_not_signed_in");
10
+ case "too_old": return t("backend.reason_too_old", row.minVersion ?? "?");
11
+ default: return null;
12
+ }
13
+ }
5
14
  /** A chosen model or effort as a reply says it; `null` is the inherited one, named. */
6
15
  function shown(deps, key, value) {
7
16
  if (value !== null)
@@ -40,18 +49,28 @@ export async function backendStep(deps, instance, args) {
40
49
  if (args.length > 3)
41
50
  return { kind: "refuse", text: t("backend.usage") };
42
51
  const from = deps.currentBackend(instance);
43
- const installed = deps.installedBackends();
52
+ const rows = deps.availability();
53
+ // The instance's own backend is never shown as unusable: a failed or stale probe must not disable it (fail open).
54
+ const why = (row) => (row.backend === from ? null : backendUnusable(t, row));
44
55
  if (args.length === 0) {
45
56
  return {
46
57
  kind: "choose", step: "backend", args: [], current: from,
47
58
  text: t("backend.menu", deps.currentDisplay(instance)),
48
- choices: installed.map(b => ({ token: b, label: b === from ? `✓ ${b}` : b })),
59
+ choices: rows.map(row => {
60
+ const reason = why(row);
61
+ const label = row.backend === from ? `✓ ${row.backend}` : row.state === "unknown" ? `${row.backend} — ${t("backend.reason_unchecked")}` : row.backend;
62
+ return reason ? { token: row.backend, label: `${row.backend} — ${reason}`, disabled: reason } : { token: row.backend, label };
63
+ }),
49
64
  };
50
65
  }
51
66
  const backend = args[0].toLowerCase();
52
- if (!installed.includes(backend)) {
53
- return { kind: "refuse", text: t("backend.not_installed", args[0], installed.join(", ") || "—") };
67
+ const row = rows.find(r => r.backend === backend);
68
+ if (!row) {
69
+ return { kind: "refuse", text: t("backend.unknown_backend", args[0], rows.map(r => r.backend).join(", ") || "—") };
54
70
  }
71
+ const reason = why(row);
72
+ if (reason)
73
+ return { kind: "refuse", text: t("backend.unusable", backend, reason) };
55
74
  // The same backend is not a switch: nothing to restart for. A model or effort on it is /model's and /effort's job.
56
75
  if (backend === from)
57
76
  return { kind: "refuse", text: t("backend.same", instance, backend), noop: true };
@@ -1 +1 @@
1
- {"version":3,"file":"backend-command.js","sourceRoot":"","sources":["../src/backend-command.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"backend-command.js","sourceRoot":"","sources":["../src/backend-command.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export declare const BUNDLED_SKILLS_DIR: string;
2
+ /** The bundled skills: name and the description from its frontmatter. */
3
+ export declare function listBundledSkills(dir?: string): Array<{
4
+ name: string;
5
+ description: string;
6
+ }>;
7
+ /** One bundled skill's SKILL.md, whole; or why not (a name that is not one of them). */
8
+ export declare function readBundledSkill(name: string, dir?: string): {
9
+ ok: true;
10
+ text: string;
11
+ } | {
12
+ ok: false;
13
+ error: string;
14
+ };
@@ -0,0 +1,29 @@
1
+ /**
2
+ * #2163: the skills AgEnD ships (general-knowledge/skills/<name>/SKILL.md, next to this file in src/ and dist/), read
3
+ * on demand. Where a CLI has no skill folder, or a workspace AgEnD does not manage gets none published, an agent still
4
+ * reads one with `agend-agent skill <name>`. Read-only and local: no fleet call, nothing written. A skill is
5
+ * documentation shipped in the package, so any instance may read any of them (no role gate: nothing to protect).
6
+ */
7
+ import { existsSync, readdirSync, readFileSync } from "node:fs";
8
+ import { dirname, join } from "node:path";
9
+ import { fileURLToPath } from "node:url";
10
+ export const BUNDLED_SKILLS_DIR = join(dirname(fileURLToPath(import.meta.url)), "general-knowledge", "skills");
11
+ const NAME = /^[a-z0-9][a-z0-9-]{0,63}$/;
12
+ /** The bundled skills: name and the description from its frontmatter. */
13
+ export function listBundledSkills(dir = BUNDLED_SKILLS_DIR) {
14
+ if (!existsSync(dir))
15
+ return [];
16
+ return readdirSync(dir).filter(n => NAME.test(n) && existsSync(join(dir, n, "SKILL.md"))).sort().map(name => {
17
+ const head = readFileSync(join(dir, name, "SKILL.md"), "utf-8").match(/^---[ \t]*\r?\n([\s\S]*?)\r?\n---/)?.[1] ?? "";
18
+ const description = head.match(/^description:[ \t]*(.*)$/m)?.[1]?.trim().replace(/^["']|["']$/g, "") ?? "";
19
+ return { name, description };
20
+ });
21
+ }
22
+ /** One bundled skill's SKILL.md, whole; or why not (a name that is not one of them). */
23
+ export function readBundledSkill(name, dir = BUNDLED_SKILLS_DIR) {
24
+ const known = listBundledSkills(dir).map(s => s.name);
25
+ if (!NAME.test(name) || !known.includes(name))
26
+ return { ok: false, error: `no bundled skill "${name.slice(0, 64)}" — one of: ${known.join(", ")}` };
27
+ return { ok: true, text: readFileSync(join(dir, name, "SKILL.md"), "utf-8") };
28
+ }
29
+ //# sourceMappingURL=bundled-skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundled-skills.js","sourceRoot":"","sources":["../src/bundled-skills.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,mBAAmB,EAAE,QAAQ,CAAC,CAAC;AAC/G,MAAM,IAAI,GAAG,2BAA2B,CAAC;AAEzC,yEAAyE;AACzE,MAAM,UAAU,iBAAiB,CAAC,MAAc,kBAAkB;IAChE,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAChC,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;QAC1G,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,UAAU,CAAC,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,mCAAmC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACtH,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,2BAA2B,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC;QAC3G,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,MAAc,kBAAkB;IAC7E,MAAM,KAAK,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACtD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,qBAAqB,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;IACpJ,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,UAAU,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC;AAChF,CAAC"}
@@ -13,6 +13,10 @@
13
13
  * window saves its expiry cost; any other gap only pays for its pings. After a session's last request the pings
14
14
  * are pure loss, up to the moment the next session of the instance starts, or the window ends.
15
15
  * - Recommendation: on when the simulated pings cost less than the expiries they prevent (by a margin), else off.
16
+ * - #2010: the TTL a 5-minute label really behaves as (effectiveTtl, agreed with #1469's keep-warm design): since
17
+ * 2026-10-15 Claude's "5m" writes often survive an hour. Measured over the last 7 days of 5–60 minute gaps: rarely
18
+ * rewritten → the simulation treats it as 1 hour; mostly rewritten → recommend the 1-hour setting
19
+ * (backend_options.claude-code.prompt_cache_ttl), not keep-warm; too few gaps → the label, marked as an estimate.
16
20
  *
17
21
  * Money is list price (cache-prices.ts). If any model the window touches — requests, pinged contexts, idle tails —
18
22
  * is missing from the table, the whole instance is weighed in input-price units instead (write 1.25x, 1-hour write
@@ -27,6 +31,8 @@ export interface SimOptions {
27
31
  to: number;
28
32
  /** Codex: use each event's measured write (the instance records real writes) rather than the estimate. */
29
33
  measured: boolean;
34
+ /** #2010: the TTL a labelled cache behaves as (ping interval and expiry); writes stay priced at the label. Default: the label. */
35
+ ttlFor?: (labelSec: number) => number;
30
36
  }
31
37
  export interface SimTail {
32
38
  t: number;
@@ -61,12 +67,52 @@ export declare function simulate(gaps: readonly GapEvent[], tails: readonly SimT
61
67
  * that starts at or after it — one that starts at the same instant leaves no idle time), or `to`.
62
68
  */
63
69
  export declare function sessionTails(ledger: Ledger, to: number): SimTail[];
70
+ /**
71
+ * The TTL the instance's latest session writes with (each gap keeps its own): the latest session end's, else the
72
+ * backend's default (Claude 1 hour, Codex 30 minutes). effectiveTtl's `latestLabelSec` (Fable, #1469's executor).
73
+ */
74
+ export declare function latestLabelSec(ledger: Ledger, backend: Backend, to: number): number;
75
+ /** #2010: the evidence window and thresholds of effectiveTtl (one definition for the report and #1469's keep-warm). */
76
+ export declare const EFFECTIVE_TTL_WINDOW_MS: number;
77
+ export declare const EFFECTIVE_TTL_MIN_SAMPLES = 10;
78
+ /** At most this share of 5–60 minute gaps rewritten: a 5-minute label behaves as 1 hour. */
79
+ export declare const EFFECTIVE_TTL_HIT_MAX = 0.1;
80
+ /** At least this share rewritten: it really is 5 minutes — switch the instance to the 1-hour setting. */
81
+ export declare const EFFECTIVE_TTL_MISS_MIN = 0.5;
82
+ export interface EffectiveTtl {
83
+ /** Seconds the cache behaves as now (what #1469's keep-warm would ping by); null: not enough evidence. */
84
+ ttlSec: number | null;
85
+ /**
86
+ * What a 5-minute label measured as over the evidence window, whatever the latest label (Fable, #1469): the
87
+ * simulation judges every 5-minute gap by it — a later switch back to 1 hour must not recast them. null: too few.
88
+ */
89
+ fiveMinute: 3600 | 300 | null;
90
+ basis: "label_1h" | "measured" | "insufficient" | "codex" | "label";
91
+ /** The gap-miss signal: 5–60 minute gaps after a 5-minute write in the last 7 days, and how many were rewritten. */
92
+ sample: number;
93
+ misses: number;
94
+ rate: number | null;
95
+ }
96
+ /**
97
+ * #2010 / #1469: the TTL an instance's cache behaves as. Pure. `gaps`: the ledger's gap events (real requests only —
98
+ * keep-warm pings, once there are any, are not requests). `latestLabelSec`: the TTL the latest session wrote with.
99
+ * A sample is a gap of 300 s < gap ≤ 3600 s after a 5-minute write, ending in (to − 7 days, to]; a miss is the same
100
+ * expiry test as simulate: the write after the gap is at least half the context cached before it.
101
+ */
102
+ export declare function effectiveTtl(gaps: readonly GapEvent[], latestLabelSec: number, backend: Backend, to: number): EffectiveTtl;
64
103
  /** Codex GPT-5.6 and later bill cache writes and keep a prefix 30 minutes. */
65
104
  export declare const isOpenAiTtlModel: (model: string) => boolean;
66
105
  export interface InstanceAnalysis {
67
106
  requests: number;
68
107
  /** The TTL the instance's latest session uses (each gap is judged by its own session's TTL). */
69
108
  ttlSec: number;
109
+ /** #2010: what that TTL behaves as, and the gap-miss signal it is judged by. */
110
+ effectiveTtl: EffectiveTtl;
111
+ /** #2001: cache-write tokens in the window by the TTL they were written with (Claude's split; Codex: none). */
112
+ writeMix: {
113
+ "5m": number;
114
+ "1h": number;
115
+ };
70
116
  /** Writes (and so expiries) are estimated: Codex records none. Also true for a Codex model whose TTL is assumed. */
71
117
  estimate: boolean;
72
118
  priced: boolean;
@@ -77,7 +123,7 @@ export interface InstanceAnalysis {
77
123
  share: number | null;
78
124
  recommendation: {
79
125
  on: boolean;
80
- reason: "quiet" | "never_expired" | "saves" | "costs_more";
126
+ reason: "quiet" | "never_expired" | "saves" | "costs_more" | "switch_to_1h" | "insufficient_evidence";
81
127
  pingsPerExpiry?: number;
82
128
  };
83
129
  }
@@ -13,6 +13,10 @@
13
13
  * window saves its expiry cost; any other gap only pays for its pings. After a session's last request the pings
14
14
  * are pure loss, up to the moment the next session of the instance starts, or the window ends.
15
15
  * - Recommendation: on when the simulated pings cost less than the expiries they prevent (by a margin), else off.
16
+ * - #2010: the TTL a 5-minute label really behaves as (effectiveTtl, agreed with #1469's keep-warm design): since
17
+ * 2026-10-15 Claude's "5m" writes often survive an hour. Measured over the last 7 days of 5–60 minute gaps: rarely
18
+ * rewritten → the simulation treats it as 1 hour; mostly rewritten → recommend the 1-hour setting
19
+ * (backend_options.claude-code.prompt_cache_ttl), not keep-warm; too few gaps → the label, marked as an estimate.
16
20
  *
17
21
  * Money is list price (cache-prices.ts). If any model the window touches — requests, pinged contexts, idle tails —
18
22
  * is missing from the table, the whole instance is weighed in input-price units instead (write 1.25x, 1-hour write
@@ -36,9 +40,11 @@ export function pingsBetween(t, end, intervalMs, from, to) {
36
40
  export function simulate(gaps, tails, o) {
37
41
  const res = { pastTtl: 0, expired: 0, rewriteTokens: 0, expiryCost: 0, pings: 0, pingCost: 0, tailPings: 0, tailCost: 0, net: 0, estimated: false };
38
42
  let saved = 0;
39
- for (const [tEnd, gap, ctx, ctxModel, ttl, model, prompt, measured, estimated] of gaps) {
43
+ const live = o.ttlFor ?? ((label) => label);
44
+ for (const [tEnd, gap, ctx, ctxModel, label, model, prompt, measured, estimated] of gaps) {
40
45
  if (tEnd < o.from)
41
46
  continue;
47
+ const ttl = live(label);
42
48
  const start = tEnd - Math.round(gap * 1000);
43
49
  const pings = pingsBetween(start, tEnd, pingIntervalMs(ttl), o.from, o.to);
44
50
  if (pings) {
@@ -55,7 +61,7 @@ export function simulate(gaps, tails, o) {
55
61
  const lost = Math.min(rewrite, ctx);
56
62
  if (ctx > 0 && lost >= ctx / 2) {
57
63
  const r = o.rates(model, prompt);
58
- const cost = lost * (writeRate(r, ttl) - r.read) / M;
64
+ const cost = lost * (writeRate(r, label) - r.read) / M;
59
65
  res.expired++;
60
66
  res.rewriteTokens += lost;
61
67
  res.expiryCost += cost;
@@ -63,7 +69,7 @@ export function simulate(gaps, tails, o) {
63
69
  }
64
70
  }
65
71
  for (const tail of tails) {
66
- const n = pingsBetween(tail.t, tail.until, pingIntervalMs(tail.ttl), o.from, o.to);
72
+ const n = pingsBetween(tail.t, tail.until, pingIntervalMs(live(tail.ttl)), o.from, o.to);
67
73
  if (!n)
68
74
  continue;
69
75
  res.tailPings += n;
@@ -86,6 +92,47 @@ export function sessionTails(ledger, to) {
86
92
  return { t: s.last.t, ctx: s.last.ctx, model: s.last.model, ttl: s.last.ttl, until };
87
93
  });
88
94
  }
95
+ /**
96
+ * The TTL the instance's latest session writes with (each gap keeps its own): the latest session end's, else the
97
+ * backend's default (Claude 1 hour, Codex 30 minutes). effectiveTtl's `latestLabelSec` (Fable, #1469's executor).
98
+ */
99
+ export function latestLabelSec(ledger, backend, to) {
100
+ const latest = sessionTails(ledger, to).reduce((a, t) => (!a || t.t > a.t ? t : a), null);
101
+ return latest ? latest.ttl : backend === "codex" ? 1800 : 3600;
102
+ }
103
+ /** #2010: the evidence window and thresholds of effectiveTtl (one definition for the report and #1469's keep-warm). */
104
+ export const EFFECTIVE_TTL_WINDOW_MS = 7 * 86_400_000;
105
+ export const EFFECTIVE_TTL_MIN_SAMPLES = 10;
106
+ /** At most this share of 5–60 minute gaps rewritten: a 5-minute label behaves as 1 hour. */
107
+ export const EFFECTIVE_TTL_HIT_MAX = 0.1;
108
+ /** At least this share rewritten: it really is 5 minutes — switch the instance to the 1-hour setting. */
109
+ export const EFFECTIVE_TTL_MISS_MIN = 0.5;
110
+ /**
111
+ * #2010 / #1469: the TTL an instance's cache behaves as. Pure. `gaps`: the ledger's gap events (real requests only —
112
+ * keep-warm pings, once there are any, are not requests). `latestLabelSec`: the TTL the latest session wrote with.
113
+ * A sample is a gap of 300 s < gap ≤ 3600 s after a 5-minute write, ending in (to − 7 days, to]; a miss is the same
114
+ * expiry test as simulate: the write after the gap is at least half the context cached before it.
115
+ */
116
+ export function effectiveTtl(gaps, latestLabelSec, backend, to) {
117
+ let sample = 0, misses = 0;
118
+ for (const [tEnd, gap, ctx, , label, , , measured, estimated] of gaps) {
119
+ if (tEnd <= to - EFFECTIVE_TTL_WINDOW_MS || tEnd > to || label !== 300 || !(gap > 300 && gap <= 3600) || !(ctx > 0))
120
+ continue;
121
+ sample++;
122
+ if (Math.min(measured ?? estimated, ctx) >= ctx / 2)
123
+ misses++;
124
+ }
125
+ const rate = sample ? misses / sample : null;
126
+ const fiveMinute = sample < EFFECTIVE_TTL_MIN_SAMPLES ? null : rate <= EFFECTIVE_TTL_HIT_MAX ? 3600 : rate >= EFFECTIVE_TTL_MISS_MIN ? 300 : null;
127
+ const out = (ttlSec, basis) => ({ ttlSec, fiveMinute, basis, sample, misses, rate });
128
+ if (backend === "codex")
129
+ return out(1800, "codex");
130
+ if (latestLabelSec >= 3600)
131
+ return out(3600, "label_1h");
132
+ if (latestLabelSec !== 300)
133
+ return out(latestLabelSec, "label");
134
+ return fiveMinute === null ? out(null, "insufficient") : out(fiveMinute, "measured");
135
+ }
89
136
  /** Codex GPT-5.6 and later bill cache writes and keep a prefix 30 minutes. */
90
137
  export const isOpenAiTtlModel = (model) => /^gpt-(5\.(6|[7-9])|[6-9])/.test(model);
91
138
  /** Requests in a window below this are too few to say anything. */
@@ -95,6 +142,11 @@ export function analyzeLedger(ledger, o) {
95
142
  const inWindow = (h) => h + 3_600_000 > o.from && h <= o.to;
96
143
  const tails = sessionTails(ledger, o.to);
97
144
  const estimatedTotals = o.backend === "codex" && !ledger.writesSeen;
145
+ const ttlSec = latestLabelSec(ledger, o.backend, o.to);
146
+ const effective = effectiveTtl(ledger.gaps, ttlSec, o.backend, o.to);
147
+ // Each gap by its own label: a 5-minute one by what 5 minutes measured as (even after a switch back to 1 hour);
148
+ // without evidence, as labelled. Codex keeps its own.
149
+ const ttlFor = (label) => (o.backend === "claude" && label === 300 && effective.fiveMinute !== null ? effective.fiveMinute : label);
98
150
  // One unit for the whole instance: dollars when every model that contributes to this window is priced — the
99
151
  // window's requests, and whatever the simulation itself prices (a pinged context, an expired request, an idle tail).
100
152
  // A probe run records exactly the models the simulation asks a rate for.
@@ -106,11 +158,12 @@ export function analyzeLedger(ledger, o) {
106
158
  requestModels.add(mk.slice(0, mk.lastIndexOf("|")));
107
159
  }
108
160
  const touched = new Set(requestModels);
109
- simulate(ledger.gaps, tails, { rates: (model) => { touched.add(model); return UNITS; }, from: o.from, to: o.to, measured: !estimatedTotals });
161
+ simulate(ledger.gaps, tails, { rates: (model) => { touched.add(model); return UNITS; }, from: o.from, to: o.to, measured: !estimatedTotals, ttlFor });
110
162
  const priced = [...touched].every((m) => listed(m, 0) !== null);
111
163
  const rates = (model, prompt) => (priced ? listed(model, prompt) : null) ?? UNITS;
112
164
  const gapBuckets = new Array(GAP_BUCKETS).fill(0);
113
165
  let requests = 0, totalCost = 0;
166
+ const writeMix = { "5m": 0, "1h": 0 };
114
167
  for (const [hk, hour] of Object.entries(ledger.hours)) {
115
168
  if (!inWindow(Number(hk)))
116
169
  continue;
@@ -119,28 +172,35 @@ export function analyzeLedger(ledger, o) {
119
172
  const bar = mk.lastIndexOf("|");
120
173
  const model = mk.slice(0, bar), long = mk.slice(bar + 1) === "1";
121
174
  requests += n;
175
+ writeMix["5m"] += write5m;
176
+ writeMix["1h"] += write1h;
122
177
  const r = rates(model, long ? Number.MAX_SAFE_INTEGER : 0);
123
178
  // Codex on GPT-5.6+ with no recorded writes: its uncached input is what got written (the estimate).
124
179
  const uncachedRate = estimatedTotals && isOpenAiTtlModel(model) ? r.write : r.input;
125
180
  totalCost += (uncached * uncachedRate + read * r.read + write5m * r.write5m + write1h * r.write1h + write * r.write + output * r.output) / M;
126
181
  }
127
182
  }
128
- const sim = simulate(ledger.gaps, tails, { rates, from: o.from, to: o.to, measured: !estimatedTotals });
129
- const latest = tails.reduce((a, t) => (!a || t.t > a.t ? t : a), null);
130
- const ttlSec = latest ? latest.ttl : o.backend === "codex" ? 1800 : 3600;
183
+ const sim = simulate(ledger.gaps, tails, { rates, from: o.from, to: o.to, measured: !estimatedTotals, ttlFor });
184
+ const unproven = effective.basis === "insufficient";
185
+ // A 5-minute gap in this window simulated by its label, for want of evidence: what is shown is an estimate.
186
+ const labelled5m = o.backend === "claude" && effective.fiveMinute === null && ledger.gaps.some(([t, , , , label]) => label === 300 && t >= o.from && t <= o.to);
131
187
  const assumedTtl = o.backend === "codex" && [...requestModels].some((m) => !isOpenAiTtlModel(m));
132
188
  let recommendation;
133
189
  if (requests < MIN_REQUESTS)
134
190
  recommendation = { on: false, reason: "quiet" };
191
+ else if (effective.basis === "measured" && effective.ttlSec === 300)
192
+ recommendation = { on: false, reason: "switch_to_1h" };
135
193
  else if (!sim.expired)
136
194
  recommendation = { on: false, reason: "never_expired" };
195
+ else if (unproven)
196
+ recommendation = { on: false, reason: "insufficient_evidence" };
137
197
  else if (sim.net > 0 && sim.net >= sim.expiryCost * 0.1)
138
198
  recommendation = { on: true, reason: "saves" };
139
199
  else
140
200
  recommendation = { on: false, reason: "costs_more", pingsPerExpiry: Math.round((sim.pings + sim.tailPings) / sim.expired) };
141
201
  return {
142
202
  // An estimate when anything shown used one: the totals (Codex with no recorded write), a gap's rewrite, a TTL.
143
- requests, ttlSec, estimate: (estimatedTotals && requests > 0) || sim.estimated || assumedTtl, priced, models: [...requestModels].sort(), gapBuckets, sim,
203
+ requests, ttlSec, effectiveTtl: effective, writeMix, estimate: (estimatedTotals && requests > 0) || sim.estimated || assumedTtl || (unproven && requests > 0) || labelled5m, priced, models: [...requestModels].sort(), gapBuckets, sim,
144
204
  totalCost, share: totalCost > 0 ? sim.expiryCost / totalCost : null, recommendation,
145
205
  };
146
206
  }
@@ -1 +1 @@
1
- {"version":3,"file":"cache-analysis.js","sourceRoot":"","sources":["../src/cache-analysis.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cache-analysis.js","sourceRoot":"","sources":["../src/cache-analysis.ts"],"names":[],"mappings":"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"}
@@ -41,10 +41,20 @@ export declare const GAP_EVENT_SEC = 240;
41
41
  export declare const KEEP_DAYS = 31;
42
42
  /** [requests, uncached, read, write5m, write1h, write, output] */
43
43
  export type HourTotals = [number, number, number, number, number, number, number];
44
+ /**
45
+ * `src` (#2122): the same totals split by where they were read from — `sourceKey(reader, profile)`: the transcript reader
46
+ * (claude, codex) and the credential profile (claude: its config dir's profile, "default" without one; codex:
47
+ * "unrecorded", since a rollout does not say which login wrote it). Each source keeps its own exact totals. What `m`
48
+ * holds beyond the sum of `src` was counted before #2122 and reads as unknown (hourSources) — never relabelled with
49
+ * today's backend or profile.
50
+ */
44
51
  export interface HourAgg {
45
52
  m: Record<string, HourTotals>;
46
53
  g: number[];
54
+ src?: Record<string, Record<string, HourTotals>>;
47
55
  }
56
+ /** A source of an hour's totals: the reader that read them and the profile it read them under. */
57
+ export declare const sourceKey: (reader: TranscriptKind, profile: string) => string;
48
58
  /**
49
59
  * One long gap: [tEnd, gapSec, contextCached, contextModel, ttlSec, model, promptAfter, measuredWrite, estimatedWrite].
50
60
  * - `contextCached`/`contextModel`: what the previous request left cached, and its model — what a ping would read.
@@ -99,9 +109,12 @@ export declare function claudeTtlAfter(turn: Turn, current: number | undefined):
99
109
  * Fold one turn into the ledger, in file order. Turns older than `cutoff` only move the session's last point (the
100
110
  * next gap needs it); everything else is counted. Pure apart from mutating `ledger`.
101
111
  */
102
- export declare function addTurn(ledger: Ledger, file: FileCursor, turn: Turn, cutoff: number): void;
103
- /** Drop what is older than `cutoff` (hours and gap events). */
104
- export declare function pruneLedger(ledger: Ledger, cutoff: number): void;
112
+ export declare function addTurn(ledger: Ledger, file: FileCursor, turn: Turn, cutoff: number, profile?: string): void;
113
+ /**
114
+ * Drop what is older than `cutoff` (hours and gap events). `foldedThrough` (#2122): an hour is dropped only once the
115
+ * usage rollup holds it (usage-rollup.ts: fold, then prune) — never one after the rollup's durable checkpoint.
116
+ */
117
+ export declare function pruneLedger(ledger: Ledger, cutoff: number, foldedThrough?: number): void;
105
118
  /** The turn a Claude Code transcript line records, or null; a message already counted (`file.ids`) is null too. */
106
119
  export declare function claudeLine(line: ScanLine, file: FileCursor): Turn | null;
107
120
  /** The turn a Codex rollout line records, or null. A `turn_context` line updates the file's model. */
@@ -25,6 +25,8 @@ export const GAP_BUCKETS = GAP_EDGES.length + 1;
25
25
  /** Gaps at least this long are kept one by one (the shortest keep-warm interval is a 5-minute TTL's 270 s). */
26
26
  export const GAP_EVENT_SEC = 240;
27
27
  export const KEEP_DAYS = 31;
28
+ /** A source of an hour's totals: the reader that read them and the profile it read them under. */
29
+ export const sourceKey = (reader, profile) => `${reader}:${profile}`;
28
30
  /** A dictionary keyed by names from outside (paths, model ids): every key an own property (#1467 lesson). */
29
31
  const dict = () => Object.create(null);
30
32
  export function emptyLedger() { return { v: 2, files: dict(), hours: dict(), gaps: [] }; }
@@ -44,7 +46,17 @@ export function reviveLedger(raw) {
44
46
  for (const [mk, tot] of Object.entries(v.m ?? {}))
45
47
  if (Array.isArray(tot) && tot.length === 7)
46
48
  m[mk] = tot;
47
- l.hours[k] = { m, g: v.g };
49
+ const src = dict();
50
+ for (const [sk, sm] of Object.entries(v.src ?? {})) {
51
+ if (!/^(?:claude|codex):.{1,120}$/s.test(sk) || !sm || typeof sm !== "object")
52
+ continue;
53
+ const into = dict();
54
+ for (const [mk, tot] of Object.entries(sm))
55
+ if (Array.isArray(tot) && tot.length === 7 && tot.every(n => Number.isFinite(n)))
56
+ into[mk] = tot;
57
+ src[sk] = into;
58
+ }
59
+ l.hours[k] = { m, g: v.g, ...(Object.keys(src).length ? { src } : {}) };
48
60
  }
49
61
  if (Array.isArray(r.gaps))
50
62
  l.gaps = r.gaps.filter((g) => Array.isArray(g) && g.length === 9);
@@ -71,7 +83,7 @@ export function claudeTtlAfter(turn, current) {
71
83
  * Fold one turn into the ledger, in file order. Turns older than `cutoff` only move the session's last point (the
72
84
  * next gap needs it); everything else is counted. Pure apart from mutating `ledger`.
73
85
  */
74
- export function addTurn(ledger, file, turn, cutoff) {
86
+ export function addTurn(ledger, file, turn, cutoff, profile) {
75
87
  const prev = file.last;
76
88
  const ttlBefore = file.kind === "claude" ? (file.ttl ?? CLAUDE_DEFAULT_TTL_SEC) : CODEX_TTL_SEC;
77
89
  if (file.kind === "claude")
@@ -85,14 +97,19 @@ export function addTurn(ledger, file, turn, cutoff) {
85
97
  const hk = String(hourOf(turn.t));
86
98
  const hour = ledger.hours[hk] ??= { m: dict(), g: new Array(GAP_BUCKETS).fill(0) };
87
99
  const mk = modelKey(turn.model, turn.prompt);
88
- const tot = hour.m[mk] ??= [0, 0, 0, 0, 0, 0, 0];
89
- tot[0] += 1;
90
- tot[1] += turn.uncached;
91
- tot[2] += turn.read;
92
- tot[3] += turn.write5m;
93
- tot[4] += turn.write1h;
94
- tot[5] += turn.write ?? 0;
95
- tot[6] += turn.output;
100
+ const bump = (tot) => {
101
+ tot[0] += 1;
102
+ tot[1] += turn.uncached;
103
+ tot[2] += turn.read;
104
+ tot[3] += turn.write5m;
105
+ tot[4] += turn.write1h;
106
+ tot[5] += turn.write ?? 0;
107
+ tot[6] += turn.output;
108
+ };
109
+ bump(hour.m[mk] ??= [0, 0, 0, 0, 0, 0, 0]);
110
+ // #2122: and under its source — the reader that read it (this file's kind) and the profile it was read under.
111
+ const src = (hour.src ??= dict())[sourceKey(file.kind, profile ?? "unknown")] ??= dict();
112
+ bump(src[mk] ??= [0, 0, 0, 0, 0, 0, 0]);
96
113
  if (!prev)
97
114
  return;
98
115
  const gap = (turn.t - prev.t) / 1000;
@@ -105,10 +122,13 @@ export function addTurn(ledger, file, turn, cutoff) {
105
122
  const estimated = file.kind === "claude" ? turn.write5m + turn.write1h : turn.uncached + (turn.write ?? 0);
106
123
  ledger.gaps.push([turn.t, gap, prev.ctx, prev.model, ttlBefore, turn.model, turn.prompt, measured, estimated]);
107
124
  }
108
- /** Drop what is older than `cutoff` (hours and gap events). */
109
- export function pruneLedger(ledger, cutoff) {
125
+ /**
126
+ * Drop what is older than `cutoff` (hours and gap events). `foldedThrough` (#2122): an hour is dropped only once the
127
+ * usage rollup holds it (usage-rollup.ts: fold, then prune) — never one after the rollup's durable checkpoint.
128
+ */
129
+ export function pruneLedger(ledger, cutoff, foldedThrough = Number.POSITIVE_INFINITY) {
110
130
  for (const k of Object.keys(ledger.hours))
111
- if (Number(k) + HOUR <= cutoff)
131
+ if (Number(k) + HOUR <= cutoff && Number(k) <= foldedThrough)
112
132
  delete ledger.hours[k];
113
133
  if (ledger.gaps.length && ledger.gaps[0][0] < cutoff)
114
134
  ledger.gaps = ledger.gaps.filter((g) => g[0] >= cutoff);