@cydm/happy-elves 0.1.0-beta.35 → 0.1.0-beta.37

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 (246) hide show
  1. package/apps/cli/dist/commands/lib/bootstrap-daemon.d.ts +2 -2
  2. package/apps/cli/dist/commands/lib/index.d.ts +2 -2
  3. package/apps/cli/dist/commands/lib/json.d.ts +1 -1
  4. package/apps/cli/dist/commands/lib/relay-http.d.ts +1 -1
  5. package/apps/cli/dist/commands/lib/scope.d.ts +1 -1
  6. package/apps/cli/dist/commands/lib/session-output.d.ts +2 -1
  7. package/apps/cli/dist/commands/lib/session-output.js +3 -0
  8. package/apps/cli/dist/commands/lib/session-view.d.ts +2 -2
  9. package/apps/cli/dist/commands/lib/types.d.ts +2 -2
  10. package/apps/cli/dist/commands/lib/workspace.d.ts +2 -2
  11. package/apps/cli/dist/commands/session.js +37 -1
  12. package/apps/daemon/dist/relay/devtools.d.ts +1 -1
  13. package/apps/daemon/dist/relay/send.d.ts +2 -2
  14. package/apps/daemon/dist/relay/send.js +1 -0
  15. package/apps/daemon/dist/relay-http.d.ts +1 -1
  16. package/apps/daemon/dist/runtime/external-provider.d.ts +1 -1
  17. package/apps/daemon/dist/runtime.d.ts +1 -2
  18. package/apps/daemon/dist/runtime.js +0 -3
  19. package/apps/daemon/dist/session/create-session.d.ts +1 -1
  20. package/apps/daemon/dist/session/directory.d.ts +1 -1
  21. package/apps/daemon/dist/session/events.d.ts +15 -2
  22. package/apps/daemon/dist/session/events.js +45 -2
  23. package/apps/daemon/dist/session/file-preview.d.ts +1 -1
  24. package/apps/daemon/dist/session/lifecycle.d.ts +5 -1
  25. package/apps/daemon/dist/session/lifecycle.js +51 -7
  26. package/apps/daemon/dist/session/metadata.d.ts +1 -1
  27. package/apps/daemon/dist/session/metadata.js +28 -0
  28. package/apps/daemon/dist/session/primitives.d.ts +1 -1
  29. package/apps/daemon/dist/session/primitives.js +22 -3
  30. package/apps/daemon/dist/session/prompt.d.ts +1 -1
  31. package/apps/daemon/dist/session/prompt.js +2 -0
  32. package/apps/daemon/dist/session/runtime-handle.d.ts +1 -1
  33. package/apps/daemon/dist/state.d.ts +2 -2
  34. package/apps/daemon/dist/types.d.ts +9 -1
  35. package/apps/relay/dist/connections.d.ts +2 -0
  36. package/apps/relay/dist/controller-handlers.d.ts +7 -2
  37. package/apps/relay/dist/controller-handlers.js +45 -4
  38. package/apps/relay/dist/db.js +39 -0
  39. package/apps/relay/dist/index.js +2 -0
  40. package/apps/relay/dist/machine-handlers.d.ts +2 -1
  41. package/apps/relay/dist/machine-handlers.js +235 -9
  42. package/apps/relay/dist/projections.d.ts +1 -1
  43. package/apps/relay/dist/projections.js +13 -0
  44. package/apps/relay/dist/relay-context.d.ts +7 -2
  45. package/apps/relay/dist/relay-context.js +68 -18
  46. package/apps/relay/dist/repositories.d.ts +2 -2
  47. package/apps/relay/dist/scope.d.ts +1 -1
  48. package/apps/relay/dist/types.d.ts +5 -1
  49. package/package.json +2 -11
  50. package/packages/client/dist/account.d.ts +1 -1
  51. package/packages/client/dist/client.d.ts +2 -2
  52. package/packages/client/dist/parsers.d.ts +1 -1
  53. package/packages/client/dist/transport.d.ts +1 -1
  54. package/packages/client/dist/types.d.ts +1 -1
  55. package/packages/client/dist/validation.d.ts +1 -1
  56. package/packages/runtime-acpx/dist/index.d.ts +1 -1
  57. package/packages/runtime-cli/dist/claude-history.d.ts +1 -2
  58. package/packages/runtime-cli/dist/claude-history.js +0 -3
  59. package/packages/runtime-cli/dist/claude-session-store.d.ts +0 -1
  60. package/packages/runtime-cli/dist/claude-session-store.js +1 -1
  61. package/packages/runtime-cli/dist/claude-turn.d.ts +1 -1
  62. package/packages/runtime-cli/dist/codex-app-server.d.ts +1 -1
  63. package/packages/runtime-cli/dist/codex-history.d.ts +1 -2
  64. package/packages/runtime-cli/dist/codex-history.js +11 -5
  65. package/packages/runtime-cli/dist/history-merge.d.ts +1 -1
  66. package/packages/runtime-cli/dist/index.d.ts +1 -1
  67. package/packages/runtime-cli/dist/permissions.d.ts +1 -1
  68. package/packages/runtime-cli/dist/session-store.d.ts +1 -1
  69. package/packages/shared/dist/protocol-schemas.d.ts +6 -0
  70. package/packages/shared/dist/protocol-schemas.js +6 -0
  71. package/packages/shared/dist/protocol-types.d.ts +11 -3
  72. package/packages/shared/dist/protocol.d.ts +14 -2
  73. package/packages/shared/dist/protocol.js +23 -0
  74. package/apps/cli/dist/commands/account.js.map +0 -1
  75. package/apps/cli/dist/commands/app.js.map +0 -1
  76. package/apps/cli/dist/commands/collect.js.map +0 -1
  77. package/apps/cli/dist/commands/command.js.map +0 -1
  78. package/apps/cli/dist/commands/config.js.map +0 -1
  79. package/apps/cli/dist/commands/daemon.js.map +0 -1
  80. package/apps/cli/dist/commands/lib/args.js.map +0 -1
  81. package/apps/cli/dist/commands/lib/audit.js.map +0 -1
  82. package/apps/cli/dist/commands/lib/bootstrap-config.js.map +0 -1
  83. package/apps/cli/dist/commands/lib/bootstrap-daemon.js.map +0 -1
  84. package/apps/cli/dist/commands/lib/bootstrap-output.js.map +0 -1
  85. package/apps/cli/dist/commands/lib/bootstrap.js.map +0 -1
  86. package/apps/cli/dist/commands/lib/config.js.map +0 -1
  87. package/apps/cli/dist/commands/lib/doctor.js.map +0 -1
  88. package/apps/cli/dist/commands/lib/exit.js.map +0 -1
  89. package/apps/cli/dist/commands/lib/index.js.map +0 -1
  90. package/apps/cli/dist/commands/lib/json.js.map +0 -1
  91. package/apps/cli/dist/commands/lib/local-daemon.js.map +0 -1
  92. package/apps/cli/dist/commands/lib/loop-store.js.map +0 -1
  93. package/apps/cli/dist/commands/lib/paths.js.map +0 -1
  94. package/apps/cli/dist/commands/lib/relay-http.js.map +0 -1
  95. package/apps/cli/dist/commands/lib/scope.js.map +0 -1
  96. package/apps/cli/dist/commands/lib/session-output.js.map +0 -1
  97. package/apps/cli/dist/commands/lib/session-view.js.map +0 -1
  98. package/apps/cli/dist/commands/lib/status.js.map +0 -1
  99. package/apps/cli/dist/commands/lib/types.js.map +0 -1
  100. package/apps/cli/dist/commands/lib/usage.js.map +0 -1
  101. package/apps/cli/dist/commands/lib/workspace.js.map +0 -1
  102. package/apps/cli/dist/commands/loop.js.map +0 -1
  103. package/apps/cli/dist/commands/machine.js.map +0 -1
  104. package/apps/cli/dist/commands/relay.js.map +0 -1
  105. package/apps/cli/dist/commands/remote.js.map +0 -1
  106. package/apps/cli/dist/commands/session.js.map +0 -1
  107. package/apps/cli/dist/commands/token.js.map +0 -1
  108. package/apps/cli/dist/commands/turn.js.map +0 -1
  109. package/apps/cli/dist/errors.js.map +0 -1
  110. package/apps/cli/dist/index.js.map +0 -1
  111. package/apps/daemon/dist/app.js.map +0 -1
  112. package/apps/daemon/dist/args.js.map +0 -1
  113. package/apps/daemon/dist/audit.js.map +0 -1
  114. package/apps/daemon/dist/cli.js.map +0 -1
  115. package/apps/daemon/dist/config.js.map +0 -1
  116. package/apps/daemon/dist/errors.js.map +0 -1
  117. package/apps/daemon/dist/loop/runner.js.map +0 -1
  118. package/apps/daemon/dist/loop/store.js.map +0 -1
  119. package/apps/daemon/dist/pair.js.map +0 -1
  120. package/apps/daemon/dist/paths.js.map +0 -1
  121. package/apps/daemon/dist/process.js.map +0 -1
  122. package/apps/daemon/dist/relay/connection.js.map +0 -1
  123. package/apps/daemon/dist/relay/devtools.js.map +0 -1
  124. package/apps/daemon/dist/relay/register.js.map +0 -1
  125. package/apps/daemon/dist/relay/send.js.map +0 -1
  126. package/apps/daemon/dist/relay-http.js.map +0 -1
  127. package/apps/daemon/dist/runtime/external-provider.js.map +0 -1
  128. package/apps/daemon/dist/runtime.js.map +0 -1
  129. package/apps/daemon/dist/session/create-session.js.map +0 -1
  130. package/apps/daemon/dist/session/directory.js.map +0 -1
  131. package/apps/daemon/dist/session/events.js.map +0 -1
  132. package/apps/daemon/dist/session/file-preview.js.map +0 -1
  133. package/apps/daemon/dist/session/lifecycle.js.map +0 -1
  134. package/apps/daemon/dist/session/metadata.js.map +0 -1
  135. package/apps/daemon/dist/session/primitives.js.map +0 -1
  136. package/apps/daemon/dist/session/prompt.js.map +0 -1
  137. package/apps/daemon/dist/session/runtime-handle.js.map +0 -1
  138. package/apps/daemon/dist/start.js.map +0 -1
  139. package/apps/daemon/dist/state.js.map +0 -1
  140. package/apps/daemon/dist/turn-coordinator.js.map +0 -1
  141. package/apps/daemon/dist/types.js.map +0 -1
  142. package/apps/daemon/dist/utils.js.map +0 -1
  143. package/apps/daemon/package.json +0 -28
  144. package/apps/relay/dist/auth.js.map +0 -1
  145. package/apps/relay/dist/connections.js.map +0 -1
  146. package/apps/relay/dist/controller-handlers.js.map +0 -1
  147. package/apps/relay/dist/db.js.map +0 -1
  148. package/apps/relay/dist/errors.js.map +0 -1
  149. package/apps/relay/dist/http-routes.js.map +0 -1
  150. package/apps/relay/dist/http-schemas.js.map +0 -1
  151. package/apps/relay/dist/index.js.map +0 -1
  152. package/apps/relay/dist/machine-handlers.js.map +0 -1
  153. package/apps/relay/dist/projections.js.map +0 -1
  154. package/apps/relay/dist/relay-context.js.map +0 -1
  155. package/apps/relay/dist/repositories.js.map +0 -1
  156. package/apps/relay/dist/retention.js.map +0 -1
  157. package/apps/relay/dist/scope.js.map +0 -1
  158. package/apps/relay/dist/security.js.map +0 -1
  159. package/apps/relay/dist/types.js.map +0 -1
  160. package/apps/relay/dist/websocket.js.map +0 -1
  161. package/apps/relay/package.json +0 -29
  162. package/packages/agent-sdk/dist/index.d.ts.map +0 -1
  163. package/packages/agent-sdk/dist/index.js.map +0 -1
  164. package/packages/agent-sdk/package.json +0 -20
  165. package/packages/client/dist/account.d.ts.map +0 -1
  166. package/packages/client/dist/account.js.map +0 -1
  167. package/packages/client/dist/client.d.ts.map +0 -1
  168. package/packages/client/dist/client.js.map +0 -1
  169. package/packages/client/dist/errors.d.ts.map +0 -1
  170. package/packages/client/dist/errors.js.map +0 -1
  171. package/packages/client/dist/http.d.ts.map +0 -1
  172. package/packages/client/dist/http.js.map +0 -1
  173. package/packages/client/dist/index.d.ts.map +0 -1
  174. package/packages/client/dist/index.js.map +0 -1
  175. package/packages/client/dist/parsers.d.ts.map +0 -1
  176. package/packages/client/dist/parsers.js.map +0 -1
  177. package/packages/client/dist/transport.d.ts.map +0 -1
  178. package/packages/client/dist/transport.js.map +0 -1
  179. package/packages/client/dist/types.d.ts.map +0 -1
  180. package/packages/client/dist/types.js.map +0 -1
  181. package/packages/client/dist/validation.d.ts.map +0 -1
  182. package/packages/client/dist/validation.js.map +0 -1
  183. package/packages/client/package.json +0 -22
  184. package/packages/pie-provider/dist/index.d.ts.map +0 -1
  185. package/packages/pie-provider/dist/index.js.map +0 -1
  186. package/packages/pie-provider/package.json +0 -26
  187. package/packages/runtime/dist/index.d.ts.map +0 -1
  188. package/packages/runtime/dist/index.js.map +0 -1
  189. package/packages/runtime/package.json +0 -19
  190. package/packages/runtime-acpx/dist/index.d.ts.map +0 -1
  191. package/packages/runtime-acpx/dist/index.js.map +0 -1
  192. package/packages/runtime-acpx/package.json +0 -23
  193. package/packages/runtime-cli/dist/async-queue.d.ts.map +0 -1
  194. package/packages/runtime-cli/dist/async-queue.js.map +0 -1
  195. package/packages/runtime-cli/dist/claude-history.d.ts.map +0 -1
  196. package/packages/runtime-cli/dist/claude-history.js.map +0 -1
  197. package/packages/runtime-cli/dist/claude-json.d.ts.map +0 -1
  198. package/packages/runtime-cli/dist/claude-json.js.map +0 -1
  199. package/packages/runtime-cli/dist/claude-rename.d.ts.map +0 -1
  200. package/packages/runtime-cli/dist/claude-rename.js.map +0 -1
  201. package/packages/runtime-cli/dist/claude-session-store.d.ts.map +0 -1
  202. package/packages/runtime-cli/dist/claude-session-store.js.map +0 -1
  203. package/packages/runtime-cli/dist/claude-turn.d.ts.map +0 -1
  204. package/packages/runtime-cli/dist/claude-turn.js.map +0 -1
  205. package/packages/runtime-cli/dist/codex-app-server.d.ts.map +0 -1
  206. package/packages/runtime-cli/dist/codex-app-server.js.map +0 -1
  207. package/packages/runtime-cli/dist/codex-approvals.d.ts.map +0 -1
  208. package/packages/runtime-cli/dist/codex-approvals.js.map +0 -1
  209. package/packages/runtime-cli/dist/codex-history.d.ts.map +0 -1
  210. package/packages/runtime-cli/dist/codex-history.js.map +0 -1
  211. package/packages/runtime-cli/dist/codex-json-rpc.d.ts.map +0 -1
  212. package/packages/runtime-cli/dist/codex-json-rpc.js.map +0 -1
  213. package/packages/runtime-cli/dist/codex-lifecycle.d.ts.map +0 -1
  214. package/packages/runtime-cli/dist/codex-lifecycle.js.map +0 -1
  215. package/packages/runtime-cli/dist/codex-protocol.d.ts.map +0 -1
  216. package/packages/runtime-cli/dist/codex-protocol.js.map +0 -1
  217. package/packages/runtime-cli/dist/command-resolver.d.ts.map +0 -1
  218. package/packages/runtime-cli/dist/command-resolver.js.map +0 -1
  219. package/packages/runtime-cli/dist/history-merge.d.ts.map +0 -1
  220. package/packages/runtime-cli/dist/history-merge.js.map +0 -1
  221. package/packages/runtime-cli/dist/index.d.ts.map +0 -1
  222. package/packages/runtime-cli/dist/index.js.map +0 -1
  223. package/packages/runtime-cli/dist/permissions.d.ts.map +0 -1
  224. package/packages/runtime-cli/dist/permissions.js.map +0 -1
  225. package/packages/runtime-cli/dist/session-store.d.ts.map +0 -1
  226. package/packages/runtime-cli/dist/session-store.js.map +0 -1
  227. package/packages/runtime-cli/package.json +0 -22
  228. package/packages/shared/dist/args.d.ts.map +0 -1
  229. package/packages/shared/dist/args.js.map +0 -1
  230. package/packages/shared/dist/crypto.d.ts.map +0 -1
  231. package/packages/shared/dist/crypto.js.map +0 -1
  232. package/packages/shared/dist/ids.d.ts.map +0 -1
  233. package/packages/shared/dist/ids.js.map +0 -1
  234. package/packages/shared/dist/index.d.ts.map +0 -1
  235. package/packages/shared/dist/index.js.map +0 -1
  236. package/packages/shared/dist/protocol-schemas.d.ts.map +0 -1
  237. package/packages/shared/dist/protocol-schemas.js.map +0 -1
  238. package/packages/shared/dist/protocol-types.d.ts.map +0 -1
  239. package/packages/shared/dist/protocol-types.js.map +0 -1
  240. package/packages/shared/dist/protocol.d.ts.map +0 -1
  241. package/packages/shared/dist/protocol.js.map +0 -1
  242. package/packages/shared/dist/session-name.d.ts.map +0 -1
  243. package/packages/shared/dist/session-name.js.map +0 -1
  244. package/packages/shared/dist/session-state.d.ts.map +0 -1
  245. package/packages/shared/dist/session-state.js.map +0 -1
  246. package/packages/shared/package.json +0 -24
@@ -1,5 +1,5 @@
1
- import type { ControllerClient } from "@happy-elves/client";
2
- import type { MachineSnapshot } from "@happy-elves/shared";
1
+ import type { ControllerClient } from "../../../../../packages/client/dist/index.js";
2
+ import type { MachineSnapshot } from "../../../../../packages/shared/dist/index.js";
3
3
  import { localDaemonStatus, stopLocalDaemon } from "./local-daemon.js";
4
4
  export declare function ensureDaemonRunning(relayUrl: string, cwd?: string): Promise<{
5
5
  local: Awaited<ReturnType<typeof localDaemonStatus>>;
@@ -1,5 +1,5 @@
1
- export { ControllerClient, type ScopedTokenScope } from "@happy-elves/client";
2
- export { generateAccountSecret, randomId } from "@happy-elves/shared";
1
+ export { ControllerClient, type ScopedTokenScope } from "../../../../../packages/client/dist/index.js";
2
+ export { generateAccountSecret, randomId } from "../../../../../packages/shared/dist/index.js";
3
3
  export { CliError } from "../../errors.js";
4
4
  export * from "./args.js";
5
5
  export * from "./audit.js";
@@ -1,4 +1,4 @@
1
- import type { JsonEnvelope } from "@happy-elves/shared";
1
+ import type { JsonEnvelope } from "../../../../../packages/shared/dist/index.js";
2
2
  export declare function ok<T>(type: string, data: T, meta?: JsonEnvelope["meta"]): void;
3
3
  export declare function writeError(code: string, message: string, meta?: JsonEnvelope["meta"], capability?: string): void;
4
4
  export declare function wantsJson(flags: Record<string, string | boolean>): boolean;
@@ -1,4 +1,4 @@
1
- import type { PairingClaimResponse, PairingStartResponse } from "@happy-elves/shared";
1
+ import type { PairingClaimResponse, PairingStartResponse } from "../../../../../packages/shared/dist/index.js";
2
2
  import { CliError } from "../../errors.js";
3
3
  import type { CliConfig, DaemonConfig } from "./types.js";
4
4
  export declare function relayHealth(relayUrl: string): Promise<{
@@ -1,4 +1,4 @@
1
- import type { ControllerClient, ScopedTokenScope } from "@happy-elves/client";
1
+ import type { ControllerClient, ScopedTokenScope } from "../../../../../packages/client/dist/index.js";
2
2
  import type { LoopRecord, PermissionMode } from "./types.js";
3
3
  export declare const DEFAULT_COMMAND_TIMEOUT_MS: number;
4
4
  export declare function parseDurationMs(value: string | boolean | undefined, fallbackMs: number): number;
@@ -1,4 +1,4 @@
1
- import type { ControllerClient, DecodedSessionEvent } from "@happy-elves/client";
1
+ import type { ControllerClient, DecodedSessionEvent } from "../../../../../packages/client/dist/index.js";
2
2
  export declare function compactText(value: string, max?: number): string;
3
3
  export declare function lastAssistantOutput(events: DecodedSessionEvent[]): string;
4
4
  export declare function displayPath(filePath: string): string;
@@ -18,6 +18,7 @@ export type TurnSummary = {
18
18
  turnId: string;
19
19
  checkpointId?: string;
20
20
  runtimeTurnId?: string;
21
+ turnSeq?: number;
21
22
  status: "running" | "completed" | "failed" | "cancelled";
22
23
  prompt: string;
23
24
  output: string;
@@ -160,6 +160,8 @@ export function summarizeTurns(events) {
160
160
  current.updatedAt = event.createdAt;
161
161
  current.lastEventId = event.id;
162
162
  current.eventCount += 1;
163
+ if (event.turnSeq !== undefined)
164
+ current.turnSeq = event.turnSeq;
163
165
  const payload = event.decoded;
164
166
  if (payload?.type === "user_prompt" && payload.text.trim()) {
165
167
  current.promptChunks.push(payload.text.trim());
@@ -181,6 +183,7 @@ export function summarizeTurns(events) {
181
183
  turnId: turn.turnId,
182
184
  checkpointId: turn.checkpointId,
183
185
  runtimeTurnId: turn.runtimeTurnId,
186
+ turnSeq: turn.turnSeq,
184
187
  status: turn.status,
185
188
  prompt: turn.promptChunks.join("\n").trim(),
186
189
  output: turn.outputChunks.join("").trim() || turn.terminalText,
@@ -1,5 +1,5 @@
1
- import type { ControllerClient, DecodedSessionEvent } from "@happy-elves/client";
2
- import type { MachineSnapshot, SessionSnapshot } from "@happy-elves/shared";
1
+ import type { ControllerClient, DecodedSessionEvent } from "../../../../../packages/client/dist/index.js";
2
+ import type { MachineSnapshot, SessionSnapshot } from "../../../../../packages/shared/dist/index.js";
3
3
  import { type MachineMetadata, type OrchestrationSummary, type OrchestrationState } from "./types.js";
4
4
  export declare function showMachine(client: ControllerClient, machine: MachineSnapshot): Promise<MachineSnapshot & {
5
5
  defaultCwd?: string;
@@ -1,5 +1,5 @@
1
- import type { ScopedTokenScope } from "@happy-elves/client";
2
- import type { SessionSnapshot } from "@happy-elves/shared";
1
+ import type { ScopedTokenScope } from "../../../../../packages/client/dist/index.js";
2
+ import type { SessionSnapshot } from "../../../../../packages/shared/dist/index.js";
3
3
  export type CliConfig = {
4
4
  relayUrl: string;
5
5
  controllerToken: string;
@@ -1,5 +1,5 @@
1
- import type { ControllerClient } from "@happy-elves/client";
2
- import type { HistoricalSessionSnapshot } from "@happy-elves/shared";
1
+ import type { ControllerClient } from "../../../../../packages/client/dist/index.js";
2
+ import type { HistoricalSessionSnapshot } from "../../../../../packages/shared/dist/index.js";
3
3
  export type WorkspaceHistoricalSession = HistoricalSessionSnapshot & {
4
4
  machineId: string;
5
5
  machineName: string;
@@ -53,6 +53,7 @@ function compactTurnRef(turn) {
53
53
  status: turn.status,
54
54
  ...(turn.prompt ? { promptPreview: compactText(turn.prompt, 180) } : {}),
55
55
  time: turn.completedAt ?? turn.updatedAt,
56
+ ...(turn.turnSeq !== undefined ? { turnSeq: turn.turnSeq } : {}),
56
57
  };
57
58
  }
58
59
  function countBy(values) {
@@ -114,6 +115,38 @@ function eventCollectionDiagnostics(events) {
114
115
  visiblePayloads: events.filter(isVisibleTranscriptPayloadEvent).length,
115
116
  };
116
117
  }
118
+ function headMatchesTurn(session, turn) {
119
+ if (!turn)
120
+ return false;
121
+ const turnHeads = new Set([
122
+ turn.checkpointId,
123
+ turn.runtimeTurnId,
124
+ turn.turnId,
125
+ ].filter((value) => typeof value === "string" && value.length > 0));
126
+ if (session.currentHead?.startsWith("event:")) {
127
+ const eventId = Number(/^event:(\d+)$/.exec(session.currentHead)?.[1]);
128
+ if (Number.isFinite(eventId) && eventId >= turn.firstEventId && eventId <= turn.lastEventId)
129
+ return true;
130
+ }
131
+ return (session.currentHead !== undefined && turnHeads.has(session.currentHead)) ||
132
+ (session.lastTurnId !== undefined && turnHeads.has(session.lastTurnId));
133
+ }
134
+ function staleHeadSuspected(session, latestCompletedTurn) {
135
+ if (!latestCompletedTurn)
136
+ return false;
137
+ if (headMatchesTurn(session, latestCompletedTurn))
138
+ return false;
139
+ const basisTime = session.headBasis?.logicalTime;
140
+ const latestTime = latestCompletedTurn.completedAt ?? latestCompletedTurn.updatedAt;
141
+ if (basisTime !== undefined) {
142
+ if (latestTime !== basisTime)
143
+ return latestTime > basisTime;
144
+ if (session.headBasis?.turnSeq !== undefined && latestCompletedTurn.turnSeq !== undefined) {
145
+ return latestCompletedTurn.turnSeq > session.headBasis.turnSeq;
146
+ }
147
+ }
148
+ return Boolean(session.currentHead || session.lastTurnId);
149
+ }
117
150
  function stringMetadata(metadata, key) {
118
151
  const value = metadata[key];
119
152
  return typeof value === "string" ? value : undefined;
@@ -318,6 +351,7 @@ export async function handleSession({ domain, action, positional, flags }) {
318
351
  historyModel: session.historyModel ?? "append-only",
319
352
  currentHead: session.currentHead,
320
353
  lastTurnId: session.lastTurnId,
354
+ headBasis: session.headBasis,
321
355
  sourceSessionId: session.sourceSessionId,
322
356
  sourceCheckpointId: session.sourceCheckpointId,
323
357
  updatedAt: session.updatedAt,
@@ -358,6 +392,8 @@ export async function handleSession({ domain, action, positional, flags }) {
358
392
  backfillAvailableEvents: numberMetadata(metadata, "availableHistoricalEvents"),
359
393
  backfillEmittedEvents: numberMetadata(metadata, "backfilledEvents"),
360
394
  backfillStatus: stringMetadata(metadata, "historicalBackfillStatus") ?? stringMetadata(metadata, "historicalBackfill"),
395
+ staleHeadSuspected: staleHeadSuspected(session, latestCompletedTurn),
396
+ headMatchesLatestCompletedTurn: headMatchesTurn(session, latestCompletedTurn),
361
397
  },
362
398
  };
363
399
  if (wantsJson(flags) || wantsVerbose(flags)) {
@@ -369,8 +405,8 @@ export async function handleSession({ domain, action, positional, flags }) {
369
405
  const runtime = isRecord(metadata.runtime) ? metadata.runtime : {};
370
406
  console.log(`Runtime: ${stringMetadata(metadata, "importedFromRuntimeSessionId") ?? stringMetadata(runtime, "backendSessionId") ?? stringMetadata(runtime, "agentSessionId") ?? "-"}`);
371
407
  console.log(`Backfill: ${data.diagnosis.backfillStatus ?? "-"} available=${data.diagnosis.backfillAvailableEvents ?? "-"} emitted=${data.diagnosis.backfillEmittedEvents ?? "-"}`);
408
+ console.log(`Head: ${session.currentHead ?? "-"} lastTurn=${session.lastTurnId ?? "-"} stale=${data.diagnosis.staleHeadSuspected ? "yes" : "no"}`);
372
409
  console.log(`Latest page: ${latestPage.events.length} events, visible=${latestPage.events.filter(isVisibleTranscriptPayloadEvent).length}, hasMore=${latestPage.hasMoreBefore}`);
373
- console.log(`Head: ${session.currentHead ?? "-"} lastTurn: ${session.lastTurnId ?? "-"}`);
374
410
  }
375
411
  return true;
376
412
  }
@@ -1,4 +1,4 @@
1
- import type { MachineCommand } from "@happy-elves/shared";
1
+ import type { MachineCommand } from "../../../../packages/shared/dist/index.js";
2
2
  import type { DaemonConfig } from "../types.js";
3
3
  export declare function handleDiagnose(ws: WebSocket, config: DaemonConfig, command: MachineCommand): Promise<void>;
4
4
  export declare function handleDevExec(ws: WebSocket, config: DaemonConfig, command: MachineCommand): Promise<void>;
@@ -1,5 +1,5 @@
1
- import type { MachineClientMessage } from "@happy-elves/shared";
2
- import type { RuntimeTurn } from "@happy-elves/runtime";
1
+ import type { MachineClientMessage } from "../../../../packages/shared/dist/index.js";
2
+ import type { RuntimeTurn } from "../../../../packages/runtime/dist/index.js";
3
3
  import type { DaemonConfig } from "../types.js";
4
4
  export declare function send(ws: WebSocket, message: unknown): void;
5
5
  export declare function configureRelaySender(config: DaemonConfig): void;
@@ -8,6 +8,7 @@ const criticalMessageTypes = new Set([
8
8
  "machine:event",
9
9
  "machine:sessionTranscriptReplaced",
10
10
  "machine:sessionTranscriptPrepended",
11
+ "machine:sessionHeadAdvanced",
11
12
  "machine:turnDone",
12
13
  "machine:sessionResumed",
13
14
  "machine:sessionRewound",
@@ -1,4 +1,4 @@
1
- import { type PairingClaimResponse, type ServerMessage } from "@happy-elves/shared";
1
+ import { type PairingClaimResponse, type ServerMessage } from "../../../packages/shared/dist/index.js";
2
2
  import { DaemonCliError } from "./errors.js";
3
3
  export declare function relayHttpError(response: Response, fallback: string): Promise<DaemonCliError>;
4
4
  export declare function readRelayJson(response: Response, fallback: string): Promise<unknown>;
@@ -1,4 +1,4 @@
1
- import type { HappyElvesRuntime } from "@happy-elves/runtime";
1
+ import type { HappyElvesRuntime } from "../../../../packages/runtime/dist/index.js";
2
2
  export type ExternalProviderConfig = {
3
3
  id: string;
4
4
  command: string;
@@ -1,8 +1,7 @@
1
- import type { HappyElvesRuntime } from "@happy-elves/runtime";
1
+ import type { HappyElvesRuntime } from "../../../packages/runtime/dist/index.js";
2
2
  import type { PrimitiveSupport } from "./types.js";
3
3
  export declare function getRuntime(defaultCwd: string): HappyElvesRuntime;
4
4
  export declare function initializeRuntime(defaultCwd: string): Promise<void>;
5
- export declare function runtimeDiagnostics(): Array<Record<string, unknown>>;
6
5
  export declare function disposeRuntime(): void;
7
6
  export declare function setRuntimeForTests(runtimeOverride: HappyElvesRuntime | null): void;
8
7
  export declare function runtimePrimitiveSupport(runtimeInstance: HappyElvesRuntime): {
@@ -57,9 +57,6 @@ export async function initializeRuntime(defaultCwd) {
57
57
  await runtimeInstance.initialize();
58
58
  }
59
59
  }
60
- export function runtimeDiagnostics() {
61
- return runtime?.diagnostics?.() ?? [];
62
- }
63
60
  export function disposeRuntime() {
64
61
  runtime?.dispose?.();
65
62
  runtime = null;
@@ -1,4 +1,4 @@
1
- import type { MachineClientMessage, MachineCommand } from "@happy-elves/shared";
1
+ import type { MachineClientMessage, MachineCommand } from "../../../../packages/shared/dist/index.js";
2
2
  type CreateSessionCommand = Extract<MachineCommand, {
3
3
  type: "machine:createSession";
4
4
  }>;
@@ -1,3 +1,3 @@
1
- import type { MachineCommand } from "@happy-elves/shared";
1
+ import type { MachineCommand } from "../../../../packages/shared/dist/index.js";
2
2
  import type { DaemonConfig } from "../types.js";
3
3
  export declare function handleListDirectory(ws: WebSocket, config: DaemonConfig, command: MachineCommand): Promise<void>;
@@ -1,12 +1,15 @@
1
- import { type EncryptedEnvelope, type SessionEventPayload } from "@happy-elves/shared";
2
- import type { RuntimeEvent, RuntimeHistoricalEvent } from "@happy-elves/runtime";
1
+ import { type EncryptedEnvelope, type SessionEventPayload, type SessionHeadAdvanceBasis } from "../../../../packages/shared/dist/index.js";
2
+ import type { RuntimeEvent, RuntimeHistoricalEvent } from "../../../../packages/runtime/dist/index.js";
3
3
  import type { DaemonConfig } from "../types.js";
4
4
  export declare function emitEvent(ws: WebSocket, config: DaemonConfig, sessionId: string, turnId: string, payload: SessionEventPayload): Promise<void>;
5
5
  export declare function emitHistoricalEvents(ws: WebSocket, config: DaemonConfig, sessionId: string, events: RuntimeHistoricalEvent[], startIndex?: number): Promise<void>;
6
6
  export declare function emitRuntimeTailEvents(ws: WebSocket, config: DaemonConfig, sessionId: string, events: RuntimeHistoricalEvent[], startIndex?: number): Promise<void>;
7
+ export declare function emitSessionHeadAdvanced(ws: WebSocket, sessionId: string, head: HistoricalSessionHead, encryptedMetadata?: EncryptedEnvelope): Promise<void>;
7
8
  export declare function emitTranscriptReplacement(ws: WebSocket, config: DaemonConfig, sessionId: string, events: RuntimeHistoricalEvent[], input?: {
9
+ requestId?: string;
8
10
  currentHead?: string;
9
11
  lastTurnId?: string;
12
+ replacementKind?: "command" | "sync";
10
13
  status?: "completed" | "cancelled" | "failed";
11
14
  encryptedMetadata?: EncryptedEnvelope;
12
15
  hasMoreBefore?: boolean;
@@ -17,4 +20,14 @@ export declare function emitTranscriptPrepended(ws: WebSocket, config: DaemonCon
17
20
  hasMoreBefore?: boolean;
18
21
  nextBefore?: string;
19
22
  }): Promise<void>;
23
+ export type HistoricalSessionHead = {
24
+ currentHead: string;
25
+ lastTurnId: string;
26
+ basis: SessionHeadAdvanceBasis;
27
+ };
28
+ export declare function latestCompletedHistoricalHead(sessionId: string, events: RuntimeHistoricalEvent[], input?: {
29
+ preferTailBasisForExistingEvents?: boolean;
30
+ previousTotalEvents?: number;
31
+ tailStartIndex?: number;
32
+ }): HistoricalSessionHead | undefined;
20
33
  export declare function runtimeEventToPayload(event: RuntimeEvent): SessionEventPayload;
@@ -32,12 +32,27 @@ export async function emitRuntimeTailEvents(ws, config, sessionId, events, start
32
32
  }, ws);
33
33
  }
34
34
  }
35
+ export async function emitSessionHeadAdvanced(ws, sessionId, head, encryptedMetadata) {
36
+ await sendReliable({
37
+ type: "machine:sessionHeadAdvanced",
38
+ sessionId,
39
+ currentHead: head.currentHead,
40
+ lastTurnId: head.lastTurnId,
41
+ basis: head.basis,
42
+ encryptedMetadata,
43
+ }, ws);
44
+ }
35
45
  export async function emitTranscriptReplacement(ws, config, sessionId, events, input = {}) {
46
+ const head = latestCompletedHistoricalHead(sessionId, events);
47
+ const fallbackHead = transcriptHead(events);
36
48
  await sendReliable({
37
49
  type: "machine:sessionTranscriptReplaced",
38
50
  sessionId,
39
- currentHead: input.currentHead ?? transcriptHead(events).currentHead,
40
- lastTurnId: input.lastTurnId ?? transcriptHead(events).lastTurnId,
51
+ requestId: input.requestId,
52
+ currentHead: input.currentHead ?? head?.currentHead ?? fallbackHead.currentHead,
53
+ lastTurnId: input.lastTurnId ?? head?.lastTurnId ?? fallbackHead.lastTurnId,
54
+ basis: head?.basis,
55
+ replacementKind: input.replacementKind,
41
56
  status: input.status,
42
57
  hasMoreBefore: input.hasMoreBefore,
43
58
  nextBefore: input.nextBefore,
@@ -79,6 +94,7 @@ async function encryptedRuntimeTailEvents(config, sessionId, events, startIndex
79
94
  turnId: event.turnId,
80
95
  seq: stableTailSeq,
81
96
  messageId: runtimeTailEventMessageId(sessionId, event, stableTailSeq),
97
+ occurredAt: event.occurredAt,
82
98
  payload: await encryptJson(config.accountSecret, `event:${sessionId}:${event.turnId}:${stableTailSeq}`, event.payload),
83
99
  });
84
100
  }
@@ -98,6 +114,33 @@ function transcriptHead(events) {
98
114
  }
99
115
  return events.at(-1)?.turnId ? { currentHead: events.at(-1)?.turnId, lastTurnId: events.at(-1)?.turnId } : {};
100
116
  }
117
+ export function latestCompletedHistoricalHead(sessionId, events, input = {}) {
118
+ for (let index = events.length - 1; index >= 0; index -= 1) {
119
+ const event = events[index];
120
+ if (!event || event.payload.type !== "done" || event.payload.status !== "completed")
121
+ continue;
122
+ const seq = event.seq ?? index + 1;
123
+ const hasRuntimeTailMessageId = (input.tailStartIndex !== undefined && index >= input.tailStartIndex)
124
+ || (input.previousTotalEvents !== undefined && index >= input.previousTotalEvents)
125
+ || input.preferTailBasisForExistingEvents === true;
126
+ const eventMessageId = hasRuntimeTailMessageId
127
+ ? runtimeTailEventMessageId(sessionId, event, seq)
128
+ : historicalEventMessageId(sessionId, event, seq);
129
+ const currentHead = event.payload.currentHead ?? event.payload.lastTurnId ?? event.turnId;
130
+ const lastTurnId = event.payload.lastTurnId ?? event.payload.currentHead ?? event.turnId;
131
+ return {
132
+ currentHead,
133
+ lastTurnId,
134
+ basis: {
135
+ turnId: event.turnId,
136
+ eventMessageId,
137
+ turnSeq: seq,
138
+ ...(event.occurredAt !== undefined ? { occurredAt: event.occurredAt } : {}),
139
+ },
140
+ };
141
+ }
142
+ return undefined;
143
+ }
101
144
  function historicalEventMessageId(sessionId, event, seq) {
102
145
  const digest = createHash("sha256")
103
146
  .update(JSON.stringify({ occurredAt: event.occurredAt, payload: event.payload, seq }))
@@ -1,4 +1,4 @@
1
- import type { FilePreviewMode, FilePreviewResult, MachineCommand } from "@happy-elves/shared";
1
+ import type { FilePreviewMode, FilePreviewResult, MachineCommand } from "../../../../packages/shared/dist/index.js";
2
2
  import type { DaemonConfig } from "../types.js";
3
3
  export declare function handlePreviewFile(ws: WebSocket, config: DaemonConfig, command: MachineCommand): Promise<void>;
4
4
  export declare function buildFilePreview(config: DaemonConfig, rootPath: string, requestedPath: string, mode?: FilePreviewMode): Promise<FilePreviewResult>;
@@ -1,5 +1,6 @@
1
- import { type MachineCommand } from "@happy-elves/shared";
1
+ import { type MachineCommand } from "../../../../packages/shared/dist/index.js";
2
2
  import type { DaemonConfig, HistoricalBackfillStatus, SessionFallback, SessionState } from "../types.js";
3
+ import { type HistoricalSessionHead } from "./events.js";
3
4
  export type HistoricalBackfillResult = {
4
5
  availableEvents: number;
5
6
  cursor: number;
@@ -10,6 +11,7 @@ export type HistoricalBackfillResult = {
10
11
  tailRepairedEvents: number;
11
12
  totalEvents: number;
12
13
  truncated: boolean;
14
+ head?: HistoricalSessionHead;
13
15
  };
14
16
  export declare function handleCreateSession(ws: WebSocket, config: DaemonConfig, command: MachineCommand): Promise<void>;
15
17
  export declare function handleImportHistoricalSession(ws: WebSocket, config: DaemonConfig, command: MachineCommand): Promise<void>;
@@ -19,6 +21,8 @@ export declare function usesAuthoritativeTranscript(session: SessionState): bool
19
21
  export declare function replaceAuthoritativeTranscript(ws: WebSocket, config: DaemonConfig, session: SessionState, runtimeSessionId?: string | undefined, input?: {
20
22
  currentHead?: string;
21
23
  lastTurnId?: string;
24
+ replacementKind?: "command" | "sync";
25
+ requestId?: string;
22
26
  status?: "completed" | "cancelled" | "failed";
23
27
  strict?: boolean;
24
28
  }): Promise<HistoricalBackfillResult>;
@@ -4,7 +4,7 @@ import { getRuntime } from "../runtime.js";
4
4
  import { sessions } from "../state.js";
5
5
  import { claimCommandRequest, sendCommandResponse } from "../relay/send.js";
6
6
  import { createSessionFailureAuditEvent, createSessionFailureResponse } from "./create-session.js";
7
- import { emitHistoricalEvents, emitRuntimeTailEvents, emitTranscriptPrepended, emitTranscriptReplacement } from "./events.js";
7
+ import { emitHistoricalEvents, emitRuntimeTailEvents, emitSessionHeadAdvanced, emitTranscriptPrepended, emitTranscriptReplacement, latestCompletedHistoricalHead, } from "./events.js";
8
8
  import { commandSessionMetadata, encryptedSessionMetadata, sessionFallbackFromCommand } from "./metadata.js";
9
9
  const historicalBackfillEventLimit = 200;
10
10
  export async function handleCreateSession(ws, config, command) {
@@ -461,8 +461,10 @@ export async function replaceAuthoritativeTranscript(ws, config, session, runtim
461
461
  }
462
462
  const result = authoritativeBackfillResult(page);
463
463
  await emitTranscriptReplacement(ws, config, session.sessionId, page.events, {
464
+ requestId: input.requestId,
464
465
  currentHead: input.currentHead ?? page.currentHead,
465
466
  lastTurnId: input.lastTurnId ?? page.lastTurnId,
467
+ replacementKind: input.replacementKind,
466
468
  status: input.status,
467
469
  hasMoreBefore: page.hasMoreBefore,
468
470
  nextBefore: page.nextBefore,
@@ -579,7 +581,15 @@ async function backfillHistoricalEvents(ws, config, session, runtimeSessionId =
579
581
  await emitHistoricalEvents(ws, config, session.sessionId, olderWindow.events, olderWindow.startIndex);
580
582
  }
581
583
  const status = olderWindow.nextCursor > 0 ? "partial" : "completed";
582
- return {
584
+ const computedHead = latestCompletedHistoricalHead(session.sessionId, historicalEvents, {
585
+ ...(previousBackfill?.totalEvents !== undefined && previousBackfill.head === undefined
586
+ ? { preferTailBasisForExistingEvents: true }
587
+ : {}),
588
+ ...(previousBackfill?.totalEvents !== undefined ? { previousTotalEvents: previousBackfill.totalEvents } : {}),
589
+ ...(tailWindow.events.length > 0 ? { tailStartIndex: tailWindow.startIndex } : {}),
590
+ });
591
+ const head = preferPersistedHistoricalHeadBasis(computedHead, previousBackfill?.head);
592
+ const result = {
583
593
  emittedEvents: tailWindow.events.length + olderWindow.events.length,
584
594
  availableEvents: historicalEvents.length,
585
595
  cursor: olderWindow.nextCursor,
@@ -588,7 +598,27 @@ async function backfillHistoricalEvents(ws, config, session, runtimeSessionId =
588
598
  tailRepairedEvents: tailWindow.events.length,
589
599
  totalEvents: historicalEvents.length,
590
600
  truncated: status === "partial",
601
+ ...(head ? { head } : {}),
591
602
  };
603
+ if (head) {
604
+ const backfilledSession = withHistoricalBackfill(session, result);
605
+ await emitSessionHeadAdvanced(ws, session.sessionId, head, await encryptedSessionMetadata(config, session.sessionId, backfilledSession, {
606
+ ...historicalBackfillMetadata(result),
607
+ historicalBackfilledAt: new Date().toISOString(),
608
+ }));
609
+ }
610
+ return result;
611
+ }
612
+ function preferPersistedHistoricalHeadBasis(computed, persisted) {
613
+ if (!computed || !persisted)
614
+ return computed;
615
+ if (computed.currentHead === persisted.currentHead &&
616
+ computed.lastTurnId === persisted.lastTurnId &&
617
+ computed.basis.turnId === persisted.basis.turnId &&
618
+ computed.basis.turnSeq === persisted.basis.turnSeq) {
619
+ return persisted;
620
+ }
621
+ return computed;
592
622
  }
593
623
  function completedBackfillResult(totalEvents) {
594
624
  return {
@@ -665,6 +695,7 @@ function withHistoricalBackfill(session, backfill) {
665
695
  ...session,
666
696
  historicalBackfill: {
667
697
  cursor: backfill.cursor,
698
+ ...(backfill.head ? { head: backfill.head } : {}),
668
699
  providerCursor: backfill.providerCursor,
669
700
  status: backfill.status,
670
701
  totalEvents: backfill.totalEvents,
@@ -681,6 +712,7 @@ function historicalBackfillMetadata(backfill) {
681
712
  backfilledEvents: backfill.emittedEvents,
682
713
  historicalOlderBackfilledEvents: backfill.olderBackfilledEvents,
683
714
  historicalTailRepairedEvents: backfill.tailRepairedEvents,
715
+ historicalHead: backfill.head,
684
716
  availableHistoricalEvents: backfill.availableEvents,
685
717
  truncatedHistoricalBackfill: backfill.truncated,
686
718
  };
@@ -699,11 +731,22 @@ export async function handleClose(ws, config, command) {
699
731
  return;
700
732
  const session = sessions.get(command.sessionId);
701
733
  const fallback = session ? undefined : await sessionFallbackFromCommand(config, command);
734
+ const fallbackHandle = fallback ? runtimeHandleFromFallback(command.sessionId, fallback.agent, fallback.cwd, fallback) : undefined;
735
+ const sessionForClose = session ?? (fallback && fallbackHandle
736
+ ? {
737
+ sessionId: command.sessionId,
738
+ agent: fallback.agent,
739
+ cwd: fallback.cwd,
740
+ name: fallback.name,
741
+ handle: fallbackHandle,
742
+ historicalBackfill: fallback.historicalBackfill,
743
+ }
744
+ : undefined);
702
745
  let runtimeCloseError;
703
- if (session) {
746
+ if (sessionForClose) {
704
747
  try {
705
- await getRuntime(session.cwd).close({
706
- handle: session.handle,
748
+ await getRuntime(sessionForClose.cwd).close({
749
+ handle: sessionForClose.handle,
707
750
  reason: command.reason ?? "closed by controller",
708
751
  });
709
752
  }
@@ -722,8 +765,9 @@ export async function handleClose(ws, config, command) {
722
765
  requestId: command.requestId,
723
766
  reason: command.reason,
724
767
  loaded: Boolean(session),
725
- agent: session?.agent ?? fallback?.agent,
726
- cwd: session?.cwd ?? fallback?.cwd,
768
+ ...(!session && fallbackHandle ? { runtimeHandleFallback: true } : {}),
769
+ agent: sessionForClose?.agent ?? fallback?.agent,
770
+ cwd: sessionForClose?.cwd ?? fallback?.cwd,
727
771
  runtimeCloseError,
728
772
  },
729
773
  });
@@ -1,4 +1,4 @@
1
- import { type EncryptedEnvelope, type MachineCommand } from "@happy-elves/shared";
1
+ import { type EncryptedEnvelope, type MachineCommand } from "../../../../packages/shared/dist/index.js";
2
2
  import type { DaemonConfig, SessionFallback, SessionMetadata, SessionState } from "../types.js";
3
3
  export declare function encryptedSessionMetadata(config: DaemonConfig, sessionId: string, state: Pick<SessionState, "agent" | "cwd" | "name" | "handle">, extra: Record<string, unknown>): Promise<EncryptedEnvelope>;
4
4
  export declare function commandSessionMetadata(config: DaemonConfig, encryptedMetadata?: EncryptedEnvelope): Promise<SessionMetadata | undefined>;
@@ -52,6 +52,7 @@ function historicalBackfillStateFromMetadata(metadata) {
52
52
  if (status && totalEvents !== undefined && cursor !== undefined) {
53
53
  return {
54
54
  cursor: Math.min(cursor, totalEvents),
55
+ ...(historicalHeadStateFromMetadata(metadata) ? { head: historicalHeadStateFromMetadata(metadata) } : {}),
55
56
  ...(typeof metadata.historicalBackfillProviderCursor === "string" ? { providerCursor: metadata.historicalBackfillProviderCursor } : {}),
56
57
  status,
57
58
  totalEvents,
@@ -60,6 +61,7 @@ function historicalBackfillStateFromMetadata(metadata) {
60
61
  if (status === "completed") {
61
62
  return {
62
63
  cursor: 0,
64
+ ...(historicalHeadStateFromMetadata(metadata) ? { head: historicalHeadStateFromMetadata(metadata) } : {}),
63
65
  ...(typeof metadata.historicalBackfillProviderCursor === "string" ? { providerCursor: metadata.historicalBackfillProviderCursor } : {}),
64
66
  status: "completed",
65
67
  totalEvents: totalEvents ?? 0,
@@ -70,6 +72,7 @@ function historicalBackfillStateFromMetadata(metadata) {
70
72
  if (totalEvents !== undefined && backfilledEvents !== undefined) {
71
73
  return {
72
74
  cursor: Math.max(0, totalEvents - backfilledEvents),
75
+ ...(historicalHeadStateFromMetadata(metadata) ? { head: historicalHeadStateFromMetadata(metadata) } : {}),
73
76
  ...(typeof metadata.historicalBackfillProviderCursor === "string" ? { providerCursor: metadata.historicalBackfillProviderCursor } : {}),
74
77
  status: "partial",
75
78
  totalEvents,
@@ -78,6 +81,31 @@ function historicalBackfillStateFromMetadata(metadata) {
78
81
  }
79
82
  return undefined;
80
83
  }
84
+ function historicalHeadStateFromMetadata(metadata) {
85
+ const head = metadata.historicalHead;
86
+ if (!head || typeof head !== "object")
87
+ return undefined;
88
+ const basis = head.basis;
89
+ if (typeof head.currentHead !== "string" ||
90
+ typeof head.lastTurnId !== "string" ||
91
+ !basis ||
92
+ typeof basis !== "object" ||
93
+ typeof basis.turnId !== "string" ||
94
+ typeof basis.eventMessageId !== "string" ||
95
+ !Number.isInteger(basis.turnSeq)) {
96
+ return undefined;
97
+ }
98
+ return {
99
+ currentHead: head.currentHead,
100
+ lastTurnId: head.lastTurnId,
101
+ basis: {
102
+ turnId: basis.turnId,
103
+ eventMessageId: basis.eventMessageId,
104
+ turnSeq: basis.turnSeq,
105
+ ...(typeof basis.occurredAt === "number" ? { occurredAt: basis.occurredAt } : {}),
106
+ },
107
+ };
108
+ }
81
109
  function historicalBackfillStatus(value) {
82
110
  return value === "partial" || value === "completed" ? value : undefined;
83
111
  }
@@ -1,4 +1,4 @@
1
- import { type MachineCommand } from "@happy-elves/shared";
1
+ import { type MachineCommand } from "../../../../packages/shared/dist/index.js";
2
2
  import type { DaemonConfig } from "../types.js";
3
3
  export declare function handleRewind(ws: WebSocket, config: DaemonConfig, command: MachineCommand): Promise<void>;
4
4
  export declare function handleFork(ws: WebSocket, config: DaemonConfig, command: MachineCommand): Promise<void>;
@@ -113,7 +113,11 @@ export async function handleRewind(ws, config, command) {
113
113
  });
114
114
  if (usesAuthoritativeTranscript(nextSession)) {
115
115
  try {
116
- const backfill = await replaceAuthoritativeTranscript(ws, config, nextSession, undefined, head);
116
+ const backfill = await replaceAuthoritativeTranscript(ws, config, nextSession, undefined, {
117
+ ...head,
118
+ replacementKind: "command",
119
+ requestId: command.requestId,
120
+ });
117
121
  sessions.set(command.sessionId, {
118
122
  ...nextSession,
119
123
  historicalBackfill: {
@@ -241,6 +245,7 @@ export async function handleFork(ws, config, command) {
241
245
  ...primitiveRuntimeEvidence(source.handle, forkState.handle),
242
246
  },
243
247
  });
248
+ const authoritativeForkTranscript = usesAuthoritativeTranscript(forkState);
244
249
  await sendCommandResponse(ws, {
245
250
  type: "machine:sessionForked",
246
251
  requestId: command.requestId,
@@ -248,6 +253,7 @@ export async function handleFork(ws, config, command) {
248
253
  sourceCheckpointId,
249
254
  sessionId: command.targetSessionId,
250
255
  name: command.name,
256
+ ...(authoritativeForkTranscript ? { transcriptPending: true } : {}),
251
257
  encryptedMetadata: await encryptedSessionMetadata(config, command.targetSessionId, forkState, {
252
258
  forkedAt: new Date().toISOString(),
253
259
  importedFromRuntimeSessionId: sourceMetadata?.importedFromRuntimeSessionId,
@@ -256,10 +262,15 @@ export async function handleFork(ws, config, command) {
256
262
  sourceCheckpointId,
257
263
  }),
258
264
  });
259
- if (usesAuthoritativeTranscript(forkState)) {
265
+ if (authoritativeForkTranscript) {
260
266
  try {
261
267
  const targetHead = primitiveResultHead(result);
262
- const backfill = await replaceAuthoritativeTranscript(ws, config, forkState, undefined, targetHead);
268
+ const backfill = await replaceAuthoritativeTranscript(ws, config, forkState, undefined, {
269
+ ...targetHead,
270
+ replacementKind: "command",
271
+ requestId: command.requestId,
272
+ status: "completed",
273
+ });
263
274
  sessions.set(command.targetSessionId, {
264
275
  ...forkState,
265
276
  historicalBackfill: {
@@ -279,6 +290,14 @@ export async function handleFork(ws, config, command) {
279
290
  summary: `Failed to refresh fork target transcript ${command.targetSessionId}`,
280
291
  evidence: { requestId: command.requestId, sourceSessionId: command.sessionId, error: error instanceof Error ? error.message : String(error) },
281
292
  });
293
+ await sendCommandResponse(ws, {
294
+ type: "machine:error",
295
+ requestId: command.requestId,
296
+ sessionId: command.targetSessionId,
297
+ code: "SESSION_TRANSCRIPT_REPLACE_FAILED",
298
+ capability: "session.history",
299
+ message: error instanceof Error ? error.message : String(error),
300
+ });
282
301
  }
283
302
  }
284
303
  }