aicodeman 1.29.1 → 1.30.0

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 (117) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/dist/reboot-restore.d.ts +146 -0
  4. package/dist/reboot-restore.d.ts.map +1 -0
  5. package/dist/reboot-restore.js +205 -0
  6. package/dist/reboot-restore.js.map +1 -0
  7. package/dist/session-env-clamp.d.ts +80 -0
  8. package/dist/session-env-clamp.d.ts.map +1 -0
  9. package/dist/session-env-clamp.js +96 -0
  10. package/dist/session-env-clamp.js.map +1 -0
  11. package/dist/session.d.ts +9 -0
  12. package/dist/session.d.ts.map +1 -1
  13. package/dist/session.js +12 -0
  14. package/dist/session.js.map +1 -1
  15. package/dist/web/ports/session-port.d.ts +31 -0
  16. package/dist/web/ports/session-port.d.ts.map +1 -1
  17. package/dist/web/public/admin-ui.js.gz +0 -0
  18. package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
  19. package/dist/web/public/{app.556be563.js → app.6d2dc4e8.js} +2 -2
  20. package/dist/web/public/app.6d2dc4e8.js.br +0 -0
  21. package/dist/web/public/app.6d2dc4e8.js.gz +0 -0
  22. package/dist/web/public/approvals-ui.js.gz +0 -0
  23. package/dist/web/public/constants.258b140f.js.gz +0 -0
  24. package/dist/web/public/cron-ui.js.gz +0 -0
  25. package/dist/web/public/entrance-animations.js.gz +0 -0
  26. package/dist/web/public/home-sessions.js.gz +0 -0
  27. package/dist/web/public/i18n.5f897ed5.js.gz +0 -0
  28. package/dist/web/public/image-input.cd4b97c4.js.gz +0 -0
  29. package/dist/web/public/index.html +25 -6
  30. package/dist/web/public/index.html.br +0 -0
  31. package/dist/web/public/index.html.gz +0 -0
  32. package/dist/web/public/input-cjk.8bc46081.js.gz +0 -0
  33. package/dist/web/public/keyboard-accessory.2cf04f17.js.gz +0 -0
  34. package/dist/web/public/mobile-handlers.6f354a87.js.gz +0 -0
  35. package/dist/web/public/mobile-overview.js.gz +0 -0
  36. package/dist/web/public/{mobile.e9d0b53e.css → mobile.6caaa28a.css} +1 -1
  37. package/dist/web/public/mobile.6caaa28a.css.br +0 -0
  38. package/dist/web/public/mobile.6caaa28a.css.gz +0 -0
  39. package/dist/web/public/notification-manager.36ea4624.js.gz +0 -0
  40. package/dist/web/public/orchestrator-panel.js.gz +0 -0
  41. package/dist/web/public/panels-ui.5b07ad14.js.gz +0 -0
  42. package/dist/web/public/ralph-panel.6de2d0f8.js.gz +0 -0
  43. package/dist/web/public/ralph-wizard.13a1831e.js.gz +0 -0
  44. package/dist/web/public/readmymind-ui.js.gz +0 -0
  45. package/dist/web/public/reboot-restore-ui.js +142 -0
  46. package/dist/web/public/reboot-restore-ui.js.br +0 -0
  47. package/dist/web/public/reboot-restore-ui.js.gz +0 -0
  48. package/dist/web/public/respawn-ui.ff0dae4c.js.gz +0 -0
  49. package/dist/web/public/sanitize-html.bc7078d6.js.gz +0 -0
  50. package/dist/web/public/session-lineage.js.gz +0 -0
  51. package/dist/web/public/session-ui.42b81477.js.gz +0 -0
  52. package/dist/web/public/settings-ui.58f1d756.js.gz +0 -0
  53. package/dist/web/public/styles.e6edfb0b.css +1 -0
  54. package/dist/web/public/styles.e6edfb0b.css.br +0 -0
  55. package/dist/web/public/styles.e6edfb0b.css.gz +0 -0
  56. package/dist/web/public/subagent-windows.e6ca799f.js.gz +0 -0
  57. package/dist/web/public/sw.js.gz +0 -0
  58. package/dist/web/public/tab-rail-resize.42c24949.js.gz +0 -0
  59. package/dist/web/public/terminal-keycode229-recovery.fb91b25b.js +1 -0
  60. package/dist/web/public/terminal-keycode229-recovery.fb91b25b.js.br +0 -0
  61. package/dist/web/public/terminal-keycode229-recovery.fb91b25b.js.gz +0 -0
  62. package/dist/web/public/{terminal-ui.38c49244.js → terminal-ui.4f8d5820.js} +2 -2
  63. package/dist/web/public/terminal-ui.4f8d5820.js.br +0 -0
  64. package/dist/web/public/terminal-ui.4f8d5820.js.gz +0 -0
  65. package/dist/web/public/ultracode-panel.js.gz +0 -0
  66. package/dist/web/public/ultracode-windows.js.gz +0 -0
  67. package/dist/web/public/upload.html.gz +0 -0
  68. package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
  69. package/dist/web/public/vendor/marked.min.js.gz +0 -0
  70. package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
  71. package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
  72. package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
  73. package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
  74. package/dist/web/public/vendor/xterm-predictive-echo.bd6882b8.js.gz +0 -0
  75. package/dist/web/public/vendor/xterm-zerolag-input.6fee72f2.js.gz +0 -0
  76. package/dist/web/public/vendor/xterm.css.gz +0 -0
  77. package/dist/web/public/vendor/xterm.min.js.gz +0 -0
  78. package/dist/web/public/voice-input.c4b51eb6.js.gz +0 -0
  79. package/dist/web/public/voice-pcm-worklet.js.gz +0 -0
  80. package/dist/web/public/webview-tabs.js.gz +0 -0
  81. package/dist/web/reboot-restore-registry.d.ts +107 -0
  82. package/dist/web/reboot-restore-registry.d.ts.map +1 -0
  83. package/dist/web/reboot-restore-registry.js +189 -0
  84. package/dist/web/reboot-restore-registry.js.map +1 -0
  85. package/dist/web/routes/index.d.ts +1 -0
  86. package/dist/web/routes/index.d.ts.map +1 -1
  87. package/dist/web/routes/index.js +1 -0
  88. package/dist/web/routes/index.js.map +1 -1
  89. package/dist/web/routes/reboot-restore-routes.d.ts +30 -0
  90. package/dist/web/routes/reboot-restore-routes.d.ts.map +1 -0
  91. package/dist/web/routes/reboot-restore-routes.js +273 -0
  92. package/dist/web/routes/reboot-restore-routes.js.map +1 -0
  93. package/dist/web/routes/session-routes.d.ts +1 -18
  94. package/dist/web/routes/session-routes.d.ts.map +1 -1
  95. package/dist/web/routes/session-routes.js +1 -65
  96. package/dist/web/routes/session-routes.js.map +1 -1
  97. package/dist/web/schemas.d.ts +11 -0
  98. package/dist/web/schemas.d.ts.map +1 -1
  99. package/dist/web/schemas.js +13 -0
  100. package/dist/web/schemas.js.map +1 -1
  101. package/dist/web/server.d.ts +74 -0
  102. package/dist/web/server.d.ts.map +1 -1
  103. package/dist/web/server.js +238 -2
  104. package/dist/web/server.js.map +1 -1
  105. package/package.json +1 -1
  106. package/dist/web/public/app.556be563.js.br +0 -0
  107. package/dist/web/public/app.556be563.js.gz +0 -0
  108. package/dist/web/public/mobile.e9d0b53e.css.br +0 -0
  109. package/dist/web/public/mobile.e9d0b53e.css.gz +0 -0
  110. package/dist/web/public/styles.6add175d.css +0 -1
  111. package/dist/web/public/styles.6add175d.css.br +0 -0
  112. package/dist/web/public/styles.6add175d.css.gz +0 -0
  113. package/dist/web/public/terminal-keycode229-recovery.6ea8fe37.js +0 -1
  114. package/dist/web/public/terminal-keycode229-recovery.6ea8fe37.js.br +0 -0
  115. package/dist/web/public/terminal-keycode229-recovery.6ea8fe37.js.gz +0 -0
  116. package/dist/web/public/terminal-ui.38c49244.js.br +0 -0
  117. package/dist/web/public/terminal-ui.38c49244.js.gz +0 -0
@@ -0,0 +1,107 @@
1
+ /**
2
+ * @fileoverview The pending restore plan: what a host reboot destroyed, waiting on a click.
3
+ *
4
+ * The boot pass builds this plan inside `restoreMuxSessions()`, in the window
5
+ * where reconciliation has reported the dead sessions and `cleanupStaleSessions()`
6
+ * has not pruned their records yet. The board then offers "restore N sessions
7
+ * from before the reboot", and `web/routes/reboot-restore-routes` spends the plan
8
+ * when the user clicks.
9
+ *
10
+ * Invariants:
11
+ * - Entries are in-memory only. A server restart drops the plan, and nothing
12
+ * re-builds it, because the records it was built from are pruned by then.
13
+ * That costs the convenience this feature adds and never the conversation:
14
+ * the conversation IS the transcript under `~/.claude/projects`, which
15
+ * `services/unified-session-service.ts` reads for the Welcome screen's Resume
16
+ * list and the Session Manager, and `resumeHistorySession()` in
17
+ * `web/public/terminal-ui.js` resumes from a row there with no persisted
18
+ * session record involved. A dropped plan therefore returns the user to
19
+ * resuming by hand, one at a time, which is where they are without this
20
+ * feature. What the plan held that a transcript does not is the owner, the
21
+ * name, the env overrides, the effort and the lineage.
22
+ * - Module-level singleton in the style of `web/approval-inbox.ts`: no `Session`
23
+ * import and no IO, which keeps it unit-testable and cycle-free.
24
+ * - Spending is take-then-build: `take()` removes entries synchronously, before
25
+ * the route's first `await`, so a double-click or two devices cannot both
26
+ * reach the same entry and put two panes on one conversation.
27
+ * - One restore runs at a time per owner. `beginSpending()` single-flights the
28
+ * route, so two concurrent clicks cannot interleave pane creation for the same
29
+ * user, while two different users never block each other.
30
+ *
31
+ * @dependencies reboot-restore (RebootRestoreEntry)
32
+ * @consumedby web/server (plan build at boot), web/routes/reboot-restore-routes
33
+ *
34
+ * @module web/reboot-restore-registry
35
+ */
36
+ import type { RebootRestoreEntry } from '../reboot-restore.js';
37
+ export declare class RebootRestoreRegistry {
38
+ /** Keyed by session id, in the order the boot pass found them. */
39
+ private entries;
40
+ /** When the boot pass built the plan, in ms since the epoch. */
41
+ private builtAt;
42
+ /**
43
+ * Entries handed to a restore that has not finished, by session id, each
44
+ * remembering which caller is spending it.
45
+ *
46
+ * A taken entry is still part of the offer until its restore resolves it, so
47
+ * it has to stay reachable by everything that can invalidate an offer. Holding
48
+ * the entries themselves — rather than a counter to compare against later —
49
+ * means `clear()` filters them by the SAME `canAccess(entry.owner)` predicate
50
+ * it already applies to the plan. A counter cannot do that, because the caller
51
+ * spending an entry need not be its owner: an admin may restore another user's
52
+ * sessions, and then the spender and the owner are different keys.
53
+ */
54
+ private parked;
55
+ /**
56
+ * Owners with a restore in flight, between its take and its last pane.
57
+ * Keyed by owner so one user's restore does not turn another user's click into
58
+ * a conflict; `take()` already guarantees no two callers get the same entry.
59
+ * Single-user mode has one key, `undefined`, so it behaves as one global flight.
60
+ */
61
+ private spending;
62
+ /** Replace the plan with what the boot pass found. An empty list clears it. */
63
+ set(entries: readonly RebootRestoreEntry[]): void;
64
+ /**
65
+ * The entries a viewer may see, newest plan first-come order preserved.
66
+ *
67
+ * @param canAccess Ownership predicate, so a user sees their own entries and
68
+ * an admin sees all. Applied here rather than in the route so the count the
69
+ * banner shows and the entries a click spends come from one filter.
70
+ */
71
+ list(canAccess: (owner: string | undefined) => boolean): RebootRestoreEntry[];
72
+ /**
73
+ * Remove and return the entries a click is about to spend.
74
+ *
75
+ * Synchronous and total: an entry leaves the plan here, before any pane is
76
+ * created, so a second click finds nothing to spend. Entries a caller may not
77
+ * access are left in place, and unknown ids are ignored.
78
+ *
79
+ * @param sessionIds The ids to spend, or undefined for every visible entry.
80
+ */
81
+ take(canAccess: (owner: string | undefined) => boolean, sessionIds: readonly string[] | undefined, spender: string | undefined): RebootRestoreEntry[];
82
+ /**
83
+ * Put entries back after a rebuild never got as far as creating a pane.
84
+ *
85
+ * Used for the click-time rejections that may resolve themselves: a workspace
86
+ * that comes back, a capacity limit the user makes room under, a CLI that
87
+ * starts once its binary is on the PATH. A conversation the user resumed by
88
+ * hand is NOT put back, because that one cannot stop being true, and an entry
89
+ * the banner keeps re-offering forever is noise only Dismiss can clear.
90
+ */
91
+ releaseFlight(spender: string | undefined, keep: readonly RebootRestoreEntry[]): void;
92
+ /** Drop the entries a viewer can see. Returns how many went. */
93
+ clear(canAccess: (owner: string | undefined) => boolean): number;
94
+ /**
95
+ * Claim the right to run a restore for one owner, or report that owner already
96
+ * has one running. Callers that get `true` must call `endSpending()` in a
97
+ * `finally` with the same owner.
98
+ */
99
+ beginSpending(owner?: string): boolean;
100
+ endSpending(owner?: string): void;
101
+ /** Test hook: forget everything, including the single-flight claim. */
102
+ reset(): void;
103
+ private dropIfExpired;
104
+ }
105
+ /** Process-wide singleton, mirroring `approvalInbox`. */
106
+ export declare const rebootRestoreRegistry: RebootRestoreRegistry;
107
+ //# sourceMappingURL=reboot-restore-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reboot-restore-registry.d.ts","sourceRoot":"","sources":["../../src/web/reboot-restore-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAQ/D,qBAAa,qBAAqB;IAChC,kEAAkE;IAClE,OAAO,CAAC,OAAO,CAAyC;IACxD,gEAAgE;IAChE,OAAO,CAAC,OAAO,CAAK;IACpB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,MAAM,CAAiF;IAC/F;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAiC;IAEjD,+EAA+E;IAC/E,GAAG,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE,GAAG,IAAI;IAOjD;;;;;;OAMG;IACH,IAAI,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,KAAK,OAAO,GAAG,kBAAkB,EAAE;IAK7E;;;;;;;;OAQG;IACH,IAAI,CACF,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,KAAK,OAAO,EACjD,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EACzC,OAAO,EAAE,MAAM,GAAG,SAAS,GAC1B,kBAAkB,EAAE;IAgBvB;;;;;;;;OAQG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,SAAS,kBAAkB,EAAE,GAAG,IAAI;IAiBrF,gEAAgE;IAChE,KAAK,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,KAAK,OAAO,GAAG,MAAM;IAgBhE;;;;OAIG;IACH,aAAa,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO;IAMtC,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;IAIjC,uEAAuE;IACvE,KAAK,IAAI,IAAI;IAOb,OAAO,CAAC,aAAa;CAStB;AAED,yDAAyD;AACzD,eAAO,MAAM,qBAAqB,uBAA8B,CAAC"}
@@ -0,0 +1,189 @@
1
+ /**
2
+ * @fileoverview The pending restore plan: what a host reboot destroyed, waiting on a click.
3
+ *
4
+ * The boot pass builds this plan inside `restoreMuxSessions()`, in the window
5
+ * where reconciliation has reported the dead sessions and `cleanupStaleSessions()`
6
+ * has not pruned their records yet. The board then offers "restore N sessions
7
+ * from before the reboot", and `web/routes/reboot-restore-routes` spends the plan
8
+ * when the user clicks.
9
+ *
10
+ * Invariants:
11
+ * - Entries are in-memory only. A server restart drops the plan, and nothing
12
+ * re-builds it, because the records it was built from are pruned by then.
13
+ * That costs the convenience this feature adds and never the conversation:
14
+ * the conversation IS the transcript under `~/.claude/projects`, which
15
+ * `services/unified-session-service.ts` reads for the Welcome screen's Resume
16
+ * list and the Session Manager, and `resumeHistorySession()` in
17
+ * `web/public/terminal-ui.js` resumes from a row there with no persisted
18
+ * session record involved. A dropped plan therefore returns the user to
19
+ * resuming by hand, one at a time, which is where they are without this
20
+ * feature. What the plan held that a transcript does not is the owner, the
21
+ * name, the env overrides, the effort and the lineage.
22
+ * - Module-level singleton in the style of `web/approval-inbox.ts`: no `Session`
23
+ * import and no IO, which keeps it unit-testable and cycle-free.
24
+ * - Spending is take-then-build: `take()` removes entries synchronously, before
25
+ * the route's first `await`, so a double-click or two devices cannot both
26
+ * reach the same entry and put two panes on one conversation.
27
+ * - One restore runs at a time per owner. `beginSpending()` single-flights the
28
+ * route, so two concurrent clicks cannot interleave pane creation for the same
29
+ * user, while two different users never block each other.
30
+ *
31
+ * @dependencies reboot-restore (RebootRestoreEntry)
32
+ * @consumedby web/server (plan build at boot), web/routes/reboot-restore-routes
33
+ *
34
+ * @module web/reboot-restore-registry
35
+ */
36
+ /**
37
+ * A plan older than this is dropped on read. A machine that rebooted yesterday
38
+ * has moved on, and an offer nobody took by then is noise rather than a rescue.
39
+ */
40
+ const PLAN_TTL_MS = 24 * 60 * 60 * 1000;
41
+ export class RebootRestoreRegistry {
42
+ /** Keyed by session id, in the order the boot pass found them. */
43
+ entries = new Map();
44
+ /** When the boot pass built the plan, in ms since the epoch. */
45
+ builtAt = 0;
46
+ /**
47
+ * Entries handed to a restore that has not finished, by session id, each
48
+ * remembering which caller is spending it.
49
+ *
50
+ * A taken entry is still part of the offer until its restore resolves it, so
51
+ * it has to stay reachable by everything that can invalidate an offer. Holding
52
+ * the entries themselves — rather than a counter to compare against later —
53
+ * means `clear()` filters them by the SAME `canAccess(entry.owner)` predicate
54
+ * it already applies to the plan. A counter cannot do that, because the caller
55
+ * spending an entry need not be its owner: an admin may restore another user's
56
+ * sessions, and then the spender and the owner are different keys.
57
+ */
58
+ parked = new Map();
59
+ /**
60
+ * Owners with a restore in flight, between its take and its last pane.
61
+ * Keyed by owner so one user's restore does not turn another user's click into
62
+ * a conflict; `take()` already guarantees no two callers get the same entry.
63
+ * Single-user mode has one key, `undefined`, so it behaves as one global flight.
64
+ */
65
+ spending = new Set();
66
+ /** Replace the plan with what the boot pass found. An empty list clears it. */
67
+ set(entries) {
68
+ this.entries = new Map(entries.map((entry) => [entry.sessionId, entry]));
69
+ this.builtAt = entries.length > 0 ? Date.now() : 0;
70
+ // A fresh boot plan supersedes anything an in-flight restore still holds.
71
+ this.parked.clear();
72
+ }
73
+ /**
74
+ * The entries a viewer may see, newest plan first-come order preserved.
75
+ *
76
+ * @param canAccess Ownership predicate, so a user sees their own entries and
77
+ * an admin sees all. Applied here rather than in the route so the count the
78
+ * banner shows and the entries a click spends come from one filter.
79
+ */
80
+ list(canAccess) {
81
+ this.dropIfExpired();
82
+ return [...this.entries.values()].filter((entry) => canAccess(entry.owner));
83
+ }
84
+ /**
85
+ * Remove and return the entries a click is about to spend.
86
+ *
87
+ * Synchronous and total: an entry leaves the plan here, before any pane is
88
+ * created, so a second click finds nothing to spend. Entries a caller may not
89
+ * access are left in place, and unknown ids are ignored.
90
+ *
91
+ * @param sessionIds The ids to spend, or undefined for every visible entry.
92
+ */
93
+ take(canAccess, sessionIds, spender) {
94
+ this.dropIfExpired();
95
+ const wanted = sessionIds ? new Set(sessionIds) : undefined;
96
+ const taken = [];
97
+ for (const entry of [...this.entries.values()]) {
98
+ if (wanted && !wanted.has(entry.sessionId))
99
+ continue;
100
+ if (!canAccess(entry.owner))
101
+ continue;
102
+ this.entries.delete(entry.sessionId);
103
+ // Parked rather than forgotten: until this restore resolves the entry, a
104
+ // dismiss still has to be able to reach and cancel it.
105
+ this.parked.set(entry.sessionId, { entry, spender });
106
+ taken.push(entry);
107
+ }
108
+ return taken;
109
+ }
110
+ /**
111
+ * Put entries back after a rebuild never got as far as creating a pane.
112
+ *
113
+ * Used for the click-time rejections that may resolve themselves: a workspace
114
+ * that comes back, a capacity limit the user makes room under, a CLI that
115
+ * starts once its binary is on the PATH. A conversation the user resumed by
116
+ * hand is NOT put back, because that one cannot stop being true, and an entry
117
+ * the banner keeps re-offering forever is noise only Dismiss can clear.
118
+ */
119
+ releaseFlight(spender, keep) {
120
+ const wanted = new Set(keep.map((entry) => entry.sessionId));
121
+ let added = 0;
122
+ for (const [sessionId, held] of [...this.parked]) {
123
+ if (held.spender !== spender)
124
+ continue;
125
+ this.parked.delete(sessionId);
126
+ // Still parked means nothing cancelled it while the restore ran. A dismiss,
127
+ // an expiry or a fresh boot plan removes it from `parked`, and then it does
128
+ // not come back however the restore ended.
129
+ if (wanted.has(sessionId)) {
130
+ this.entries.set(sessionId, held.entry);
131
+ added += 1;
132
+ }
133
+ }
134
+ if (added > 0 && this.builtAt === 0)
135
+ this.builtAt = Date.now();
136
+ }
137
+ /** Drop the entries a viewer can see. Returns how many went. */
138
+ clear(canAccess) {
139
+ const removable = [...this.entries.values()].filter((entry) => canAccess(entry.owner));
140
+ for (const entry of removable)
141
+ this.entries.delete(entry.sessionId);
142
+ // Entries a restore is holding are dismissed by the same rule, so a dismiss
143
+ // that lands mid-restore wins. Judged on the ENTRY's owner, exactly as above,
144
+ // rather than on who happens to be restoring it.
145
+ let parkedRemoved = 0;
146
+ for (const [sessionId, held] of [...this.parked]) {
147
+ if (!canAccess(held.entry.owner))
148
+ continue;
149
+ this.parked.delete(sessionId);
150
+ parkedRemoved += 1;
151
+ }
152
+ if (this.entries.size === 0)
153
+ this.builtAt = 0;
154
+ return removable.length + parkedRemoved;
155
+ }
156
+ /**
157
+ * Claim the right to run a restore for one owner, or report that owner already
158
+ * has one running. Callers that get `true` must call `endSpending()` in a
159
+ * `finally` with the same owner.
160
+ */
161
+ beginSpending(owner) {
162
+ if (this.spending.has(owner))
163
+ return false;
164
+ this.spending.add(owner);
165
+ return true;
166
+ }
167
+ endSpending(owner) {
168
+ this.spending.delete(owner);
169
+ }
170
+ /** Test hook: forget everything, including the single-flight claim. */
171
+ reset() {
172
+ this.entries.clear();
173
+ this.parked.clear();
174
+ this.builtAt = 0;
175
+ this.spending.clear();
176
+ }
177
+ dropIfExpired() {
178
+ if (this.builtAt > 0 && Date.now() - this.builtAt > PLAN_TTL_MS) {
179
+ // A restore that took entries just before the expiry must not hand them
180
+ // back afterwards and give an expired plan another full day of life.
181
+ this.parked.clear();
182
+ this.entries.clear();
183
+ this.builtAt = 0;
184
+ }
185
+ }
186
+ }
187
+ /** Process-wide singleton, mirroring `approvalInbox`. */
188
+ export const rebootRestoreRegistry = new RebootRestoreRegistry();
189
+ //# sourceMappingURL=reboot-restore-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reboot-restore-registry.js","sourceRoot":"","sources":["../../src/web/reboot-restore-registry.ts"],"names":[],"mappings":"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"}
@@ -10,6 +10,7 @@ export { registerCronRoutes } from './cron-routes.js';
10
10
  export { registerSystemRoutes } from './system-routes.js';
11
11
  export { registerHookEventRoutes } from './hook-event-routes.js';
12
12
  export { registerApprovalRoutes } from './approval-routes.js';
13
+ export { registerRebootRestoreRoutes } from './reboot-restore-routes.js';
13
14
  export { registerReadMyMindRoutes } from './readmymind-routes.js';
14
15
  export { registerStatusTelemetryRoutes } from './status-telemetry-routes.js';
15
16
  export { registerCaseRoutes } from './case-routes.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/web/routes/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,6BAA6B,EAAE,MAAM,8BAA8B,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AACvF,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/web/routes/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,6BAA6B,EAAE,MAAM,8BAA8B,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AACvF,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC"}
@@ -10,6 +10,7 @@ export { registerCronRoutes } from './cron-routes.js';
10
10
  export { registerSystemRoutes } from './system-routes.js';
11
11
  export { registerHookEventRoutes } from './hook-event-routes.js';
12
12
  export { registerApprovalRoutes } from './approval-routes.js';
13
+ export { registerRebootRestoreRoutes } from './reboot-restore-routes.js';
13
14
  export { registerReadMyMindRoutes } from './readmymind-routes.js';
14
15
  export { registerStatusTelemetryRoutes } from './status-telemetry-routes.js';
15
16
  export { registerCaseRoutes } from './case-routes.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/web/routes/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,6BAA6B,EAAE,MAAM,8BAA8B,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AACvF,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/web/routes/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,6BAA6B,EAAE,MAAM,8BAA8B,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AACvF,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @fileoverview Reboot-restore routes: offer back the sessions a host reboot destroyed.
3
+ *
4
+ * The boot pass leaves a plan in `web/reboot-restore-registry` when the machine
5
+ * plausibly rebooted. The board reads it, shows a banner, and the user decides:
6
+ * - `GET /api/reboot-restore`: what is on offer, ownership-scoped
7
+ * - `POST /api/reboot-restore/restore`: rebuild some or all of it
8
+ * - `POST /api/reboot-restore/dismiss`: drop the offer
9
+ *
10
+ * A click, not the heuristic, is what creates panes. The heuristic only decides
11
+ * whether the banner appears, so a wrong yes costs a line of text the user
12
+ * dismisses rather than N CLI processes nobody asked for.
13
+ *
14
+ * Rebuilding is take-then-build: entries leave the plan synchronously at the top
15
+ * of the route, before the first `await`, and the whole route is single-flighted,
16
+ * so a double-click or two devices cannot put two panes on one conversation.
17
+ * Three things are re-checked at click time rather than trusted from boot: the
18
+ * owner's privilege grant, the workspace still being on disk, and the
19
+ * conversation not already being live because the user resumed it by hand.
20
+ *
21
+ * A rebuilt session comes back attached, idle and disarmed. Respawn controllers
22
+ * and Ralph loops are deliberately not re-armed, and its terminal scrollback is
23
+ * gone, because the pane is new. The banner says so.
24
+ */
25
+ import { FastifyInstance } from 'fastify';
26
+ import type { SessionPort, EventPort, ConfigPort, InfraPort } from '../ports/index.js';
27
+ type RebootRestoreCtx = SessionPort & EventPort & ConfigPort & InfraPort;
28
+ export declare function registerRebootRestoreRoutes(app: FastifyInstance, ctx: RebootRestoreCtx): void;
29
+ export {};
30
+ //# sourceMappingURL=reboot-restore-routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reboot-restore-routes.d.ts","sourceRoot":"","sources":["../../../src/web/routes/reboot-restore-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAuB1C,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEvF,KAAK,gBAAgB,GAAG,WAAW,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;AAazE,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,gBAAgB,GAAG,IAAI,CAyP7F"}