@adhdev/daemon-core 0.9.82-rc.22 → 0.9.82-rc.220

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 (277) hide show
  1. package/dist/boot/daemon-lifecycle.d.ts +1 -0
  2. package/dist/boot/process-hardening.d.ts +50 -0
  3. package/dist/chat/source-machine.d.ts +166 -0
  4. package/dist/chat/source-resolver.d.ts +104 -0
  5. package/dist/chat/subscription-updates.d.ts +1 -0
  6. package/dist/cli-adapter-types.d.ts +23 -2
  7. package/dist/cli-adapters/cli-script-runner.d.ts +117 -0
  8. package/dist/cli-adapters/cli-state-engine.d.ts +178 -0
  9. package/dist/cli-adapters/provider-cli-adapter.d.ts +106 -63
  10. package/dist/cli-adapters/provider-cli-parse.d.ts +4 -0
  11. package/dist/cli-adapters/provider-cli-shared.d.ts +29 -0
  12. package/dist/cli-adapters/raw-terminal-io.d.ts +37 -0
  13. package/dist/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +3 -3
  14. package/dist/cli-adapters/terminal-backends/types.d.ts +1 -2
  15. package/dist/cli-adapters/terminal-screen.d.ts +2 -11
  16. package/dist/commands/cli-manager.d.ts +2 -1
  17. package/dist/commands/handler.d.ts +110 -0
  18. package/dist/commands/mesh-coordinator.d.ts +85 -1
  19. package/dist/commands/router.d.ts +32 -1
  20. package/dist/config/chat-history.d.ts +9 -0
  21. package/dist/config/config.d.ts +5 -0
  22. package/dist/config/mesh-config.d.ts +72 -1
  23. package/dist/git/git-commands.d.ts +9 -1
  24. package/dist/git/git-diff.d.ts +6 -0
  25. package/dist/git/git-types.d.ts +2 -0
  26. package/dist/index.d.ts +46 -11
  27. package/dist/index.js +36322 -15614
  28. package/dist/index.js.map +1 -1
  29. package/dist/index.mjs +36182 -15568
  30. package/dist/index.mjs.map +1 -1
  31. package/dist/installer.d.ts +1 -4
  32. package/dist/ipc/local-ipc-server.d.ts +91 -0
  33. package/dist/launch.d.ts +1 -1
  34. package/dist/logging/async-batch-writer.d.ts +10 -0
  35. package/dist/mesh/contracts.d.ts +164 -0
  36. package/dist/mesh/coordinator-prompt.d.ts +36 -0
  37. package/dist/mesh/coordinator-registry.d.ts +59 -0
  38. package/dist/mesh/mesh-active-work.d.ts +90 -0
  39. package/dist/mesh/mesh-delivery-policy.d.ts +131 -0
  40. package/dist/mesh/mesh-events-coordinator.d.ts +151 -0
  41. package/dist/mesh/mesh-events-pending.d.ts +33 -0
  42. package/dist/mesh/mesh-events-stale.d.ts +40 -0
  43. package/dist/mesh/mesh-events-utils.d.ts +14 -0
  44. package/dist/mesh/mesh-events.d.ts +5 -40
  45. package/dist/mesh/mesh-fast-forward.d.ts +41 -0
  46. package/dist/mesh/mesh-host-ownership.d.ts +9 -0
  47. package/dist/mesh/mesh-ledger-reconciliation.d.ts +23 -3
  48. package/dist/mesh/mesh-ledger.d.ts +77 -1
  49. package/dist/mesh/mesh-missions.d.ts +58 -0
  50. package/dist/mesh/mesh-refine-status.d.ts +26 -0
  51. package/dist/mesh/mesh-review-inbox.d.ts +90 -0
  52. package/dist/mesh/mesh-runtime-store.d.ts +324 -0
  53. package/dist/mesh/mesh-task-stats.d.ts +49 -0
  54. package/dist/mesh/mesh-work-queue.d.ts +137 -6
  55. package/dist/mesh/preview-freshness.d.ts +18 -0
  56. package/dist/mesh/refine-config.d.ts +215 -0
  57. package/dist/mesh/worktree-bootstrap-config.d.ts +135 -0
  58. package/dist/providers/acp-provider-instance.d.ts +2 -0
  59. package/dist/providers/approval-utils.d.ts +13 -0
  60. package/dist/providers/cli-provider-instance.d.ts +39 -3
  61. package/dist/providers/contracts.d.ts +130 -6
  62. package/dist/providers/external-sources.d.ts +71 -0
  63. package/dist/providers/native-history/antigravity-cli-transcript.d.ts +100 -0
  64. package/dist/providers/native-history/claude-cli-transcript.d.ts +70 -0
  65. package/dist/providers/native-history/codex-cli-transcript.d.ts +73 -0
  66. package/dist/providers/native-history/dispatcher.d.ts +27 -0
  67. package/dist/providers/native-history/hermes-cli-transcript.d.ts +30 -0
  68. package/dist/providers/native-history/index.d.ts +13 -0
  69. package/dist/providers/provider-instance-manager.d.ts +12 -0
  70. package/dist/providers/provider-instance.d.ts +13 -1
  71. package/dist/providers/provider-loader.d.ts +26 -4
  72. package/dist/providers/provider-trust.d.ts +31 -0
  73. package/dist/providers/read-chat-contract.d.ts +29 -0
  74. package/dist/providers/sdk/v1/builders/acp/detect-status.d.ts +68 -0
  75. package/dist/providers/sdk/v1/builders/cli/detect-status.d.ts +85 -0
  76. package/dist/providers/sdk/v1/builders/cli/parse-approval-squash.d.ts +59 -0
  77. package/dist/providers/sdk/v1/builders/cli/parse-approval.d.ts +65 -0
  78. package/dist/providers/sdk/v1/builders/cli/parse-session.d.ts +91 -0
  79. package/dist/providers/sdk/v1/builders/cli/visible-region.d.ts +42 -0
  80. package/dist/providers/sdk/v1/fixture-tooling/format.d.ts +126 -0
  81. package/dist/providers/sdk/v1/fixture-tooling/index.d.ts +8 -0
  82. package/dist/providers/sdk/v1/fixture-tooling/replay.d.ts +38 -0
  83. package/dist/providers/sdk/v1/index.d.ts +30 -0
  84. package/dist/providers/sdk/v1/sandbox/README-design.d.ts +193 -0
  85. package/dist/providers/sdk/v1/sandbox/require-whitelist.d.ts +74 -0
  86. package/dist/providers/sdk/v1/sandbox/script-runner.d.ts +98 -0
  87. package/dist/providers/sdk/v1/types/cli/index.d.ts +277 -0
  88. package/dist/providers/sdk/v1/types/common/index.d.ts +203 -0
  89. package/dist/providers/sdk/v1/validators/index.d.ts +5 -0
  90. package/dist/providers/sdk/v1/validators/manifest.d.ts +40 -0
  91. package/dist/providers/sdk/v1/validators/taint.d.ts +52 -0
  92. package/dist/providers/spec/adapter.d.ts +52 -0
  93. package/dist/providers/spec/cli-adapter.d.ts +102 -0
  94. package/dist/providers/spec/driver.d.ts +287 -0
  95. package/dist/providers/spec/evaluator.d.ts +70 -0
  96. package/dist/providers/spec/fsm-driver.d.ts +110 -0
  97. package/dist/providers/spec/fsm-evaluator.d.ts +72 -0
  98. package/dist/providers/spec/fsm-loader.d.ts +14 -0
  99. package/dist/providers/spec/fsm-types.d.ts +91 -0
  100. package/dist/providers/spec/loader.d.ts +15 -0
  101. package/dist/providers/spec/native-history-executor.d.ts +41 -0
  102. package/dist/providers/spec/route.d.ts +4 -0
  103. package/dist/providers/spec/schema.gen.d.ts +2039 -0
  104. package/dist/providers/spec/types.d.ts +311 -0
  105. package/dist/providers/transcript-v2.d.ts +176 -0
  106. package/dist/providers/types/interactive-prompt.d.ts +48 -0
  107. package/dist/repo-mesh-types.d.ts +126 -1
  108. package/dist/sessions/registry.d.ts +3 -0
  109. package/dist/shared-types-extra.d.ts +2 -4
  110. package/dist/shared-types.d.ts +42 -1
  111. package/dist/status/normalize.d.ts +1 -1
  112. package/dist/status/normalize.js +1 -0
  113. package/dist/status/normalize.js.map +1 -1
  114. package/dist/status/normalize.mjs +1 -0
  115. package/dist/status/normalize.mjs.map +1 -1
  116. package/dist/status/reporter.d.ts +2 -0
  117. package/dist/status/snapshot.d.ts +1 -0
  118. package/dist/types.d.ts +5 -0
  119. package/package.json +6 -3
  120. package/src/agent-stream/poller.ts +2 -3
  121. package/src/boot/daemon-lifecycle.ts +22 -10
  122. package/src/boot/process-hardening.ts +89 -0
  123. package/src/chat/source-machine.ts +534 -0
  124. package/src/chat/source-resolver.ts +0 -0
  125. package/src/chat/subscription-updates.ts +20 -1
  126. package/src/cli-adapter-types.d.ts +1 -0
  127. package/src/cli-adapter-types.ts +22 -2
  128. package/src/cli-adapters/cli-script-runner.ts +421 -0
  129. package/src/cli-adapters/cli-state-engine.ts +1162 -0
  130. package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
  131. package/src/cli-adapters/provider-cli-adapter.ts +673 -1139
  132. package/src/cli-adapters/provider-cli-parse.d.ts +1 -0
  133. package/src/cli-adapters/provider-cli-parse.ts +13 -0
  134. package/src/cli-adapters/provider-cli-runtime.ts +3 -1
  135. package/src/cli-adapters/provider-cli-shared.d.ts +2 -0
  136. package/src/cli-adapters/provider-cli-shared.ts +59 -11
  137. package/src/cli-adapters/raw-terminal-io.ts +252 -0
  138. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +35 -29
  139. package/src/cli-adapters/terminal-backends/types.ts +1 -3
  140. package/src/cli-adapters/terminal-screen.ts +11 -81
  141. package/src/commands/chat-commands.ts +1787 -60
  142. package/src/commands/cli-manager.ts +283 -14
  143. package/src/commands/handler.ts +809 -2
  144. package/src/commands/mesh-coordinator.ts +332 -122
  145. package/src/commands/router.ts +4369 -558
  146. package/src/config/chat-history.ts +95 -24
  147. package/src/config/config.ts +12 -0
  148. package/src/config/mesh-config.ts +303 -3
  149. package/src/config/recent-activity.ts +8 -2
  150. package/src/daemon/dev-auto-implement.ts +3 -2
  151. package/src/daemon/dev-cli-debug.ts +10 -1
  152. package/src/detection/ide-detector.ts +26 -16
  153. package/src/git/git-commands.ts +42 -12
  154. package/src/git/git-diff.ts +53 -0
  155. package/src/git/git-status.ts +35 -6
  156. package/src/git/git-types.ts +2 -0
  157. package/src/git/git-worktree.ts +8 -1
  158. package/src/index.ts +126 -10
  159. package/src/installer.d.ts +1 -1
  160. package/src/installer.ts +8 -6
  161. package/src/ipc/local-ipc-server.ts +278 -0
  162. package/src/launch.d.ts +1 -1
  163. package/src/launch.ts +37 -28
  164. package/src/logging/async-batch-writer.ts +55 -0
  165. package/src/logging/logger.ts +2 -1
  166. package/src/mesh/contracts.ts +329 -0
  167. package/src/mesh/coordinator-prompt.ts +218 -31
  168. package/src/mesh/coordinator-registry.ts +121 -0
  169. package/src/mesh/mesh-active-work.ts +437 -0
  170. package/src/mesh/mesh-delivery-policy.ts +315 -0
  171. package/src/mesh/mesh-events-coordinator.ts +1447 -0
  172. package/src/mesh/mesh-events-pending.ts +371 -0
  173. package/src/mesh/mesh-events-stale.ts +283 -0
  174. package/src/mesh/mesh-events-utils.ts +166 -0
  175. package/src/mesh/mesh-events.ts +24 -908
  176. package/src/mesh/mesh-fast-forward.ts +438 -0
  177. package/src/mesh/mesh-host-ownership.ts +73 -0
  178. package/src/mesh/mesh-ledger-reconciliation.ts +12 -5
  179. package/src/mesh/mesh-ledger.ts +587 -102
  180. package/src/mesh/mesh-missions.ts +151 -0
  181. package/src/mesh/mesh-refine-status.ts +144 -0
  182. package/src/mesh/mesh-review-inbox.ts +307 -0
  183. package/src/mesh/mesh-runtime-store.ts +1305 -0
  184. package/src/mesh/mesh-task-stats.ts +154 -0
  185. package/src/mesh/mesh-work-queue.ts +490 -166
  186. package/src/mesh/preview-freshness.ts +118 -0
  187. package/src/mesh/refine-config.ts +403 -0
  188. package/src/mesh/worktree-bootstrap-config.ts +326 -0
  189. package/src/providers/acp-provider-instance.ts +15 -1
  190. package/src/providers/approval-utils.d.ts +4 -0
  191. package/src/providers/approval-utils.ts +47 -5
  192. package/src/providers/chat-message-normalization.ts +4 -11
  193. package/src/providers/cli-provider-instance.ts +834 -64
  194. package/src/providers/contracts.d.ts +55 -0
  195. package/src/providers/contracts.ts +141 -6
  196. package/src/providers/external-sources.ts +218 -0
  197. package/src/providers/ide-provider-instance.ts +19 -5
  198. package/src/providers/native-history/antigravity-cli-transcript.ts +643 -0
  199. package/src/providers/native-history/claude-cli-transcript.ts +396 -0
  200. package/src/providers/native-history/codex-cli-transcript.ts +479 -0
  201. package/src/providers/native-history/dispatcher.ts +340 -0
  202. package/src/providers/native-history/hermes-cli-transcript.ts +230 -0
  203. package/src/providers/native-history/index.ts +30 -0
  204. package/src/providers/provider-instance-manager.ts +30 -0
  205. package/src/providers/provider-instance.ts +10 -1
  206. package/src/providers/provider-loader.ts +592 -50
  207. package/src/providers/provider-schema.ts +87 -14
  208. package/src/providers/provider-trust.ts +114 -0
  209. package/src/providers/read-chat-contract.ts +76 -16
  210. package/src/providers/sdk/README.md +49 -0
  211. package/src/providers/sdk/v1/builders/acp/detect-status.ts +144 -0
  212. package/src/providers/sdk/v1/builders/cli/detect-status.ts +262 -0
  213. package/src/providers/sdk/v1/builders/cli/parse-approval-squash.ts +158 -0
  214. package/src/providers/sdk/v1/builders/cli/parse-approval.ts +250 -0
  215. package/src/providers/sdk/v1/builders/cli/parse-session.ts +276 -0
  216. package/src/providers/sdk/v1/builders/cli/visible-region.ts +143 -0
  217. package/src/providers/sdk/v1/fixture-tooling/format.ts +130 -0
  218. package/src/providers/sdk/v1/fixture-tooling/index.ts +22 -0
  219. package/src/providers/sdk/v1/fixture-tooling/replay.ts +352 -0
  220. package/src/providers/sdk/v1/index.ts +152 -0
  221. package/src/providers/sdk/v1/sandbox/README-design.ts +195 -0
  222. package/src/providers/sdk/v1/sandbox/require-whitelist.ts +472 -0
  223. package/src/providers/sdk/v1/sandbox/script-runner.ts +150 -0
  224. package/src/providers/sdk/v1/schemas/cli/provider.schema.json +504 -0
  225. package/src/providers/sdk/v1/schemas/primitives/acp-session-protocol-v1.json +131 -0
  226. package/src/providers/sdk/v1/schemas/primitives/native-history-codex-rollout-v1.json +66 -0
  227. package/src/providers/sdk/v1/schemas/primitives/tui-approval-squash-v1.json +91 -0
  228. package/src/providers/sdk/v1/schemas/primitives/tui-assistant-block-v1.json +91 -0
  229. package/src/providers/sdk/v1/schemas/primitives/tui-cue-ordering-v1.json +47 -0
  230. package/src/providers/sdk/v1/schemas/primitives/tui-dispatch-order-v1.json +32 -0
  231. package/src/providers/sdk/v1/schemas/primitives/tui-footer-chrome-v1.json +42 -0
  232. package/src/providers/sdk/v1/schemas/primitives/tui-index-finder-v1.json +27 -0
  233. package/src/providers/sdk/v1/schemas/primitives/tui-modal-v1.json +125 -0
  234. package/src/providers/sdk/v1/schemas/primitives/tui-prompt-marker-v1.json +45 -0
  235. package/src/providers/sdk/v1/schemas/primitives/tui-session-id-extraction-v1.json +46 -0
  236. package/src/providers/sdk/v1/schemas/primitives/tui-settled-prompt-v1.json +71 -0
  237. package/src/providers/sdk/v1/schemas/primitives/tui-spinner-v1.json +83 -0
  238. package/src/providers/sdk/v1/schemas/primitives/tui-transcript-pty-v1.json +83 -0
  239. package/src/providers/sdk/v1/schemas/primitives/tui-visible-region-v1.json +57 -0
  240. package/src/providers/sdk/v1/schemas/primitives/tui-welcome-screen-v1.json +35 -0
  241. package/src/providers/sdk/v1/types/cli/index.ts +365 -0
  242. package/src/providers/sdk/v1/types/common/index.ts +229 -0
  243. package/src/providers/sdk/v1/validators/index.ts +19 -0
  244. package/src/providers/sdk/v1/validators/manifest.ts +110 -0
  245. package/src/providers/sdk/v1/validators/taint.ts +309 -0
  246. package/src/providers/spec/adapter.ts +138 -0
  247. package/src/providers/spec/cli-adapter.ts +674 -0
  248. package/src/providers/spec/driver.ts +1082 -0
  249. package/src/providers/spec/evaluator.ts +604 -0
  250. package/src/providers/spec/fsm-driver.ts +663 -0
  251. package/src/providers/spec/fsm-evaluator.ts +255 -0
  252. package/src/providers/spec/fsm-loader.ts +102 -0
  253. package/src/providers/spec/fsm-types.ts +184 -0
  254. package/src/providers/spec/loader.ts +325 -0
  255. package/src/providers/spec/native-history-executor.ts +939 -0
  256. package/src/providers/spec/route.ts +51 -0
  257. package/src/providers/spec/schema.gen.ts +693 -0
  258. package/src/providers/spec/schema.json +342 -0
  259. package/src/providers/spec/types.ts +365 -0
  260. package/src/providers/transcript-v2.ts +567 -0
  261. package/src/providers/types/interactive-prompt.ts +425 -0
  262. package/src/providers/version-archive.ts +38 -20
  263. package/src/repo-mesh-types.ts +138 -1
  264. package/src/sessions/registry.ts +3 -0
  265. package/src/shared-types-extra.ts +2 -4
  266. package/src/shared-types.ts +45 -1
  267. package/src/status/builders.ts +24 -6
  268. package/src/status/normalize.ts +2 -0
  269. package/src/status/reporter.ts +15 -0
  270. package/src/status/snapshot.ts +84 -25
  271. package/src/system/host-memory.ts +29 -12
  272. package/src/types.ts +5 -0
  273. package/dist/cli-adapters/terminal-backends/xterm-backend.d.ts +0 -17
  274. package/dist/mesh/mesh-sync.d.ts +0 -53
  275. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +0 -16
  276. package/src/cli-adapters/terminal-backends/xterm-backend.ts +0 -97
  277. package/src/mesh/mesh-sync.ts +0 -111
@@ -19,10 +19,37 @@ export interface RepoMesh {
19
19
  defaultBranch?: string;
20
20
  policy: RepoMeshPolicy;
21
21
  coordinator: RepoMeshCoordinatorConfig;
22
+ meshHost?: RepoMeshHostMetadata;
22
23
  projectContext: ProjectContextSnapshot;
23
24
  nodes: RepoMeshNode[];
24
25
  status: 'active' | 'archived' | 'deleted';
25
26
  }
27
+ export type RepoMeshDaemonRole = 'host' | 'member';
28
+ export interface RepoMeshHostPairingMetadata {
29
+ status: 'not_configured' | 'pairing' | 'paired' | 'rejected' | 'revoked';
30
+ tokenId?: string;
31
+ joinedAt?: string;
32
+ lastPairedAt?: string;
33
+ lastRejectedAt?: string;
34
+ expiresAt?: string;
35
+ }
36
+ export interface RepoMeshHostMetadata {
37
+ /** Local daemon role for this mesh. Missing metadata defaults to host for standalone compatibility. */
38
+ role: RepoMeshDaemonRole;
39
+ /** Daemon that owns mesh truth/status/git/queue/session/ledger/coordinator ownership. */
40
+ hostDaemonId?: string;
41
+ /** Mesh node that represents the host daemon, when known. */
42
+ hostNodeId?: string;
43
+ /** Future standalone manual pairing endpoint entered by member daemons. */
44
+ hostAddress?: string;
45
+ /** Redacted pairing state only; raw join tokens must not be persisted here. */
46
+ pairing?: RepoMeshHostPairingMetadata;
47
+ }
48
+ export interface RepoMeshHostStatus extends RepoMeshHostMetadata {
49
+ canOwnCoordinator: boolean;
50
+ canOwnQueue: boolean;
51
+ defaulted: boolean;
52
+ }
26
53
  export interface RepoMeshNode {
27
54
  id: string;
28
55
  daemonId: string;
@@ -37,15 +64,31 @@ export interface RepoMeshNode {
37
64
  effectiveCapabilities: RepoMeshNodeCapabilities;
38
65
  policy: RepoMeshNodePolicy;
39
66
  health: RepoMeshNodeHealth;
67
+ role?: RepoMeshDaemonRole;
40
68
  status: 'enabled' | 'disabled' | 'removed';
41
69
  }
42
70
  export type RepoMeshNodeHealth = 'online' | 'offline' | 'degraded' | 'dirty' | 'wrong_branch' | 'unknown';
43
71
  export type RepoMeshSessionCleanupMode = 'preserve' | 'stop' | 'delete_stopped' | 'stop_and_delete';
44
72
  export type RepoMeshSpawnedSessionVisibility = 'visible' | 'hidden';
73
+ export interface RepoMeshAutoFastForwardPolicy {
74
+ /** Defaults to true. Set false to disable daemon-initiated idle fast-forwards. */
75
+ enabled: boolean;
76
+ /** Maximum behind count eligible for automatic fast-forward. Missing means no limit. */
77
+ maxBehind?: number;
78
+ /** Defaults to true. Require submodule status to be clean before automatic fast-forward. */
79
+ requireCleanSubmodules?: boolean;
80
+ }
45
81
  export interface RepoMeshPolicy {
46
82
  requirePreTaskCheckpoint: boolean;
47
83
  requirePostTaskCheckpoint: boolean;
48
84
  requireApprovalForPush: boolean;
85
+ /**
86
+ * Narrow Refinery opt-in: when validation and patch-equivalence have passed,
87
+ * allow Refinery to publish submodule gitlink commits to each submodule's
88
+ * configured remote main branch with a non-force push, then verify reachability.
89
+ * Defaults to false; root branch pushes/merges are not affected.
90
+ */
91
+ allowAutoPublishSubmoduleMainCommits?: boolean;
49
92
  requireApprovalForDestructiveGit: boolean;
50
93
  dirtyWorkspaceBehavior: 'block' | 'warn' | 'checkpoint_then_continue';
51
94
  maxParallelTasks: number;
@@ -62,6 +105,11 @@ export interface RepoMeshPolicy {
62
105
  * runtimes are never stopped/deleted unless the mesh owner opts in.
63
106
  */
64
107
  sessionCleanupOnNodeRemove?: RepoMeshSessionCleanupMode;
108
+ /**
109
+ * Daemon-initiated fast-forward for idle clean nodes that are only behind
110
+ * their tracked upstream. Defaults to enabled.
111
+ */
112
+ autoFastForward?: RepoMeshAutoFastForwardPolicy;
65
113
  /**
66
114
  * Maximum number of automatic retry recommendations for a failed task on the
67
115
  * same node before the daemon advises the coordinator to escalate or reassign.
@@ -167,7 +215,28 @@ export interface RepoMeshCoordinatorConfig {
167
215
  providerType?: string;
168
216
  /** Preferred node to run coordinator on (null = auto) */
169
217
  preferredNodeId?: string;
170
- /** Additional system prompt context for coordinator */
218
+ /**
219
+ * Full mesh-level override for the coordinator system prompt. When set,
220
+ * replaces the daemon's rendered default and any user-file override
221
+ * (~/.adhdev/coordinator-prompts/<cli>.md). The per-launch
222
+ * extraSystemPrompt still composes on top — it always lands last as
223
+ * Additional Context. Supports the same {{placeholders}} the daemon's
224
+ * default template uses ({{meshName}}, {{repo}}, {{nodes}}, …).
225
+ */
226
+ systemPromptOverride?: string;
227
+ /**
228
+ * Mesh-level append. Composes after whichever base prompt won
229
+ * (override → user-file override → daemon default). Use this when you
230
+ * want extra rules for THIS mesh but otherwise the standard prompt is
231
+ * fine. Stacks with the user-file append (`<cli>.append.md`) — both
232
+ * apply if both are set.
233
+ */
234
+ systemPromptAppend?: string;
235
+ /**
236
+ * @deprecated Use systemPromptAppend. Kept as a fallback alias so
237
+ * existing meshes.json files keep working without a migration step;
238
+ * the daemon prefers systemPromptAppend when both are present.
239
+ */
171
240
  systemPromptSuffix?: string;
172
241
  }
173
242
  /**
@@ -185,6 +254,7 @@ export interface LocalMeshEntry {
185
254
  defaultBranch?: string;
186
255
  policy: RepoMeshPolicy;
187
256
  coordinator: RepoMeshCoordinatorConfig;
257
+ meshHost?: RepoMeshHostMetadata;
188
258
  nodes: LocalMeshNodeEntry[];
189
259
  createdAt: string;
190
260
  updatedAt: string;
@@ -196,16 +266,42 @@ export interface LocalMeshNodeEntry {
196
266
  daemonId?: string;
197
267
  /** Machine registry ID that owns this workspace, when known. */
198
268
  machineId?: string;
269
+ /** Operator-defined capability tags used by mesh queue matching. */
270
+ capabilities?: string[];
199
271
  userOverrides: Partial<RepoMeshNodeCapabilities>;
200
272
  policy: RepoMeshNodePolicy;
273
+ /**
274
+ * Per-node instruction surfaced in the coordinator prompt so the LLM
275
+ * knows what each node is for (e.g. "this is the staging mirror — run
276
+ * only smoke tests here", or "use opus on this node, sonnet elsewhere").
277
+ * Empty/missing: omitted silently from the rendered prompt, no rule
278
+ * line about it gets added. The coordinator forwards/honors it when
279
+ * delegating; we don't enforce it at the daemon level.
280
+ */
281
+ systemPrompt?: string;
201
282
  /** For single-machine mesh: same daemon, different worktree */
202
283
  isLocalWorktree?: boolean;
203
284
  /** Branch this worktree tracks (set when created via clone_mesh_node) */
204
285
  worktreeBranch?: string;
205
286
  /** Node ID this worktree was cloned from */
206
287
  clonedFromNodeId?: string;
288
+ /** Repo-local preparation result for ADHDev-created worktree nodes. */
289
+ worktreeBootstrap?: {
290
+ status: 'ready' | 'running' | 'failed' | 'not_configured' | 'disabled' | 'stale';
291
+ required?: boolean;
292
+ configSource?: string;
293
+ configSourceType?: string;
294
+ startedAt?: string;
295
+ completedAt?: string;
296
+ lastCommand?: string;
297
+ exitCode?: number | null;
298
+ error?: string;
299
+ commandsRun?: Array<Record<string, unknown>>;
300
+ staleInputs?: string[];
301
+ };
207
302
  /** Optional associated/external repos configured as node metadata. */
208
303
  relatedRepos?: RepoMeshRelatedRepo[];
304
+ role?: RepoMeshDaemonRole;
209
305
  }
210
306
  export interface RepoMeshStatus {
211
307
  meshId: string;
@@ -213,6 +309,7 @@ export interface RepoMeshStatus {
213
309
  repoIdentity: string;
214
310
  defaultBranch?: string;
215
311
  refreshedAt: string;
312
+ meshHost?: RepoMeshHostStatus;
216
313
  nodes: RepoMeshNodeStatus[];
217
314
  queue?: RepoMeshQueueStatus;
218
315
  ledger?: RepoMeshLedgerStatus;
@@ -221,11 +318,17 @@ export interface RepoMeshSessionStatus {
221
318
  sessionId: string;
222
319
  providerType?: string;
223
320
  state?: string;
321
+ chatStatus?: string;
224
322
  lifecycle?: 'starting' | 'running' | 'stopping' | 'stopped' | 'failed' | 'interrupted';
225
323
  surfaceKind?: 'live_runtime' | 'recovery_snapshot' | 'inactive_record';
226
324
  recoveryState?: string | null;
227
325
  workspace?: string | null;
228
326
  title?: string | null;
327
+ role?: string | null;
328
+ isSelfCoordinator?: boolean;
329
+ statusNote?: string | null;
330
+ createdAt?: string | null;
331
+ startedAt?: string | null;
229
332
  lastActivityAt?: string | null;
230
333
  isCached?: boolean;
231
334
  }
@@ -249,16 +352,33 @@ export interface RepoMeshNodeStatus {
249
352
  repoRoot?: string;
250
353
  daemonId?: string;
251
354
  machineId?: string;
355
+ role?: RepoMeshDaemonRole;
252
356
  machineStatus?: string;
253
357
  isLocalWorktree?: boolean;
254
358
  worktreeBranch?: string;
359
+ /** Mirrored from LocalMeshNodeEntry.systemPrompt for coordinator-prompt rendering. */
360
+ systemPrompt?: string;
255
361
  health: RepoMeshNodeHealth;
256
362
  git?: GitRepoStatus;
363
+ /**
364
+ * True when the selected coordinator has evidence that a peer git probe is still
365
+ * in flight or just timed out during initial mesh handshake, so callers should
366
+ * treat missing git data as pending instead of authoritative absence.
367
+ */
368
+ gitProbePending?: boolean;
257
369
  providers: string[];
258
370
  activeSessions: string[];
259
371
  activeSessionDetails?: RepoMeshSessionStatus[];
260
372
  providerPriority?: string[];
261
373
  launchReady?: boolean;
374
+ /** True when the node is clean, ahead=0, behind>0, and safe for fast-forward consideration. */
375
+ autoFastForwardEligible?: boolean;
376
+ /** Coordinator-facing suggestion for obvious clean catch-up work. */
377
+ suggestedAction?: 'auto_fast_forward';
378
+ worktreeBootstrap?: LocalMeshNodeEntry['worktreeBootstrap'];
379
+ launchBlockedReason?: string;
380
+ launchBlockedMessage?: string;
381
+ recoveryHint?: string;
262
382
  lastSeenAt?: string;
263
383
  updatedAt?: string;
264
384
  connection?: RepoMeshPeerConnectionStatus;
@@ -346,3 +466,8 @@ export interface RepoMeshLedgerStatus {
346
466
  entries: RepoMeshLedgerEntryStatus[];
347
467
  summary: RepoMeshLedgerSummaryStatus;
348
468
  }
469
+ export interface MeshAsyncJobLifecycle {
470
+ startedAt?: string;
471
+ completedAt?: string;
472
+ error?: string;
473
+ }
@@ -7,6 +7,9 @@ export interface SessionRuntimeTarget {
7
7
  cdpManagerKey?: string;
8
8
  adapterKey?: string;
9
9
  instanceKey?: string;
10
+ /** Wall clock at register time. native-history readers use it as a
11
+ * cutoff so a fresh session can't show records from a prior one. */
12
+ spawnedAtMs?: number;
10
13
  }
11
14
  export declare class SessionRegistry {
12
15
  private readonly bySessionId;
@@ -18,12 +18,10 @@ export interface RuntimeAttachedClient {
18
18
  readOnly: boolean;
19
19
  }
20
20
  /** Session status union (used by SessionEntry.status, legacy recent-launch metadata, etc.) */
21
- export type SessionStatus = 'idle' | 'generating' | 'waiting_approval' | 'error' | 'stopped' | 'starting' | 'panel_hidden' | 'not_monitored' | 'disconnected';
21
+ export type SessionStatus = 'idle' | 'generating' | 'waiting_approval' | 'waiting_choice' | 'error' | 'stopped' | 'starting' | 'panel_hidden' | 'not_monitored' | 'disconnected';
22
22
  /** Inbox bucket categories for recent sessions */
23
23
  export type RecentSessionBucket = 'needs_attention' | 'working' | 'task_complete' | 'idle';
24
24
  /** Terminal backend status */
25
25
  export interface TerminalBackendStatus {
26
- backend: 'xterm' | 'ghostty-vt';
27
- preference: 'auto' | 'xterm' | 'ghostty-vt';
28
- ghosttyAvailable: boolean;
26
+ backend: 'ghostty-vt';
29
27
  }
@@ -14,6 +14,7 @@ import type { ActiveChatData as _ActiveChatData, ProviderErrorReason as _Provide
14
14
  import type { WorkspaceEntry } from './config/workspaces.js';
15
15
  import type { ProviderMeshCoordinatorConfig, ProviderResumeCapability } from './providers/contracts.js';
16
16
  import type { GitCompactSummary, GitWorkspaceUpdate, WorkspaceGitSubscriptionParams } from './git/git-types.js';
17
+ import type { InteractivePrompt } from './providers/types/interactive-prompt.js';
17
18
  export type { GitCommandName, GitCompactSummary, GitDiffSummary, GitFailureReason, GitFileChange, GitFileChangeStatus, GitRepoIdentity, GitRepoStatus, GitSnapshot, GitSnapshotCompareSummary, GitSnapshotReason, GitWorkspaceUpdate, WorkspaceGitSubscriptionParams, } from './git/git-types.js';
18
19
  export interface SessionActiveChatData extends Omit<_ActiveChatData, 'messages'> {
19
20
  messages?: _ActiveChatData['messages'];
@@ -49,6 +50,14 @@ export interface ReadChatSyncResult {
49
50
  message: string;
50
51
  buttons: string[];
51
52
  } | null;
53
+ activeInteractivePrompt?: InteractivePrompt | null;
54
+ /**
55
+ * Chat source provenance from ChatSourceMachine (A2). Carries the
56
+ * selected source, transition cause, lock state, and legacy
57
+ * fallbackReason — opaque to the daemon-core, consumed by web-core
58
+ * for the source debug badge and SourceTimeline (A3).
59
+ */
60
+ messageSource?: Record<string, unknown>;
52
61
  }
53
62
  export interface ProviderSummaryItem {
54
63
  id: string;
@@ -268,6 +277,7 @@ export interface SessionEntry {
268
277
  runtimeRecoveryState?: string | null;
269
278
  resume?: ProviderResumeCapability;
270
279
  activeChat: SessionActiveChatData | null;
280
+ activeInteractivePrompt?: InteractivePrompt | null;
271
281
  capabilities?: SessionCapability[];
272
282
  /** Effective message input/media support for this session. Defaults fail-closed to text-only. */
273
283
  messageInput?: MessageInputSupport;
@@ -292,6 +302,11 @@ export interface SessionEntry {
292
302
  seenCompletionMarker?: string;
293
303
  surfaceHidden?: boolean;
294
304
  settings?: Record<string, any>;
305
+ /** Set when this session is acting as a mesh coordinator for the given mesh. */
306
+ coordinator?: {
307
+ meshId: string;
308
+ role: 'coordinator';
309
+ };
295
310
  meshQueueStats?: {
296
311
  total?: number;
297
312
  active?: number;
@@ -410,7 +425,33 @@ export interface AvailableProviderInfo {
410
425
  lastVerification?: MachineProviderCheckResult;
411
426
  /** Provider-declared Repo Mesh coordinator/MCP behavior. */
412
427
  meshCoordinator?: ProviderMeshCoordinatorConfig;
413
- }
428
+ /**
429
+ * Provider trust classification — derived from the on-disk layer the
430
+ * manifest came from and the shape of the manifest. Dashboards use
431
+ * this to render a trust badge and gate activation of
432
+ * `external-untrusted` providers behind a confirm modal.
433
+ */
434
+ trust?: ProviderTrust;
435
+ /** Daemon-side human-readable description of the trust value. */
436
+ trustDescription?: string;
437
+ /** True when activation needs a user-side confirmation step. */
438
+ requiresConfirmation?: boolean;
439
+ /** Which on-disk layer the manifest lives in. */
440
+ sourceLayer?: 'user' | 'upstream' | 'external';
441
+ /** For external providers, the source-name namespace it came from. */
442
+ sourceName?: string | null;
443
+ /** Manifest-declared version, e.g. "1.2.1". */
444
+ providerVersion?: string;
445
+ /** Underlying executable name (CLI/binary providers). */
446
+ binary?: string;
447
+ /** Lifecycle label from the manifest: "Stable", "Beta", … */
448
+ status?: string;
449
+ /** One-line provider description from the manifest. */
450
+ details?: string;
451
+ /** Manifest-declared links: homepage, docs, repo, … */
452
+ links?: Record<string, string>;
453
+ }
454
+ export type ProviderTrust = 'user-custom' | 'trusted' | 'trusted-with-scripts' | 'external-safe' | 'external-untrusted';
414
455
  export interface MachineProviderCheckResult {
415
456
  ok: boolean;
416
457
  stage?: 'detection' | 'runnable' | 'verification';
@@ -1,6 +1,6 @@
1
1
  import type { ActiveChatData } from '../providers/provider-instance.js';
2
2
  import type { SessionActiveChatData } from '../shared-types.js';
3
- export type ManagedStatus = 'idle' | 'generating' | 'waiting_approval' | 'error' | 'stopped' | 'starting' | 'panel_hidden' | 'not_monitored' | 'disconnected';
3
+ export type ManagedStatus = 'idle' | 'generating' | 'waiting_approval' | 'waiting_choice' | 'error' | 'stopped' | 'starting' | 'panel_hidden' | 'not_monitored' | 'disconnected';
4
4
  export interface NormalizeActiveChatOptions {
5
5
  includeMessages?: boolean;
6
6
  includeInputContent?: boolean;
@@ -119,6 +119,7 @@ function normalizeManagedStatus(status, opts) {
119
119
  if (hasApprovalButtons(opts?.activeModal)) return "waiting_approval";
120
120
  const normalized = String(status || "idle").trim().toLowerCase();
121
121
  if (normalized === "waiting_approval") return "waiting_approval";
122
+ if (normalized === "waiting_choice") return "waiting_choice";
122
123
  if (WORKING_STATUSES.has(normalized)) return "generating";
123
124
  if (normalized === "error") return "error";
124
125
  if (normalized === "stopped") return "stopped";
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/status/normalize.ts"],"sourcesContent":["import type { ActiveChatData } from '../providers/provider-instance.js';\nimport type { SessionActiveChatData } from '../shared-types.js';\n\nexport type ManagedStatus =\n | 'idle'\n | 'generating'\n | 'waiting_approval'\n | 'error'\n | 'stopped'\n | 'starting'\n | 'panel_hidden'\n | 'not_monitored'\n | 'disconnected';\n\nconst WORKING_STATUSES = new Set([\n 'generating',\n 'streaming',\n 'loading',\n 'loading_reference',\n 'thinking',\n 'active',\n]);\n\nexport interface NormalizeActiveChatOptions {\n includeMessages?: boolean;\n includeInputContent?: boolean;\n includeActiveModal?: boolean;\n messageLimit?: number;\n totalBytesLimit?: number;\n stringLimit?: number;\n fallbackStringLimit?: number;\n}\n\n// Full snapshots are still capped, but can carry recent chat context for API/inspection use.\nconst FULL_STATUS_ACTIVE_CHAT_OPTIONS: Required<NormalizeActiveChatOptions> = {\n includeMessages: true,\n includeInputContent: true,\n includeActiveModal: true,\n messageLimit: 60,\n totalBytesLimit: 96 * 1024,\n stringLimit: 4 * 1024,\n fallbackStringLimit: 1024,\n};\n\n// Live/metadata snapshots only need routing + UI summary. Current chat text is loaded\n// on demand via `read_chat`, and older history via `chat_history`.\nexport const LIVE_STATUS_ACTIVE_CHAT_OPTIONS: Required<NormalizeActiveChatOptions> = {\n includeMessages: false,\n includeInputContent: false,\n includeActiveModal: false,\n messageLimit: 0,\n totalBytesLimit: 0,\n stringLimit: 512,\n fallbackStringLimit: 256,\n};\n\nconst STATUS_MODAL_MESSAGE_LIMIT = 2 * 1024;\nconst STATUS_MODAL_BUTTON_LIMIT = 120;\n\nfunction truncateString(value: string, maxChars: number): string {\n if (value.length <= maxChars) return value;\n if (maxChars <= 12) return value.slice(0, Math.max(0, maxChars));\n return `${value.slice(0, maxChars - 12)}...[truncated]`;\n}\n\nfunction truncateStringTail(value: string, maxChars: number): string {\n if (value.length <= maxChars) return value;\n if (maxChars <= 12) return value.slice(value.length - Math.max(0, maxChars));\n return `...[truncated]${value.slice(value.length - (maxChars - 12))}`;\n}\n\nfunction trimStructuredStrings(value: unknown, maxChars: number): unknown {\n if (typeof value === 'string') return truncateString(value, maxChars);\n if (Array.isArray(value)) return value.map((item) => trimStructuredStrings(item, maxChars));\n if (!value || typeof value !== 'object') return value;\n return Object.fromEntries(\n Object.entries(value).map(([key, nested]) => [key, trimStructuredStrings(nested, maxChars)]),\n );\n}\n\nfunction estimateBytes(value: unknown): number {\n try {\n return JSON.stringify(value).length;\n } catch {\n return String(value ?? '').length;\n }\n}\n\nfunction trimMessageForStatus(message: unknown, stringLimit: number): unknown {\n if (!message || typeof message !== 'object') return message;\n return trimStructuredStrings(message, stringLimit);\n}\n\n/**\n * Collapse timestamp / createdAt into receivedAt so downstream consumers\n * only ever need to read a single canonical time field.\n */\nfunction normalizeMessageTime(message: unknown): unknown {\n if (!message || typeof message !== 'object') return message;\n const msg = message as Record<string, unknown>;\n if (msg.receivedAt == null) {\n const fallback = msg.timestamp ?? msg.createdAt;\n if (fallback != null) {\n const ts = typeof fallback === 'string' ? Date.parse(fallback as string) : Number(fallback);\n if (Number.isFinite(ts) && ts > 0) msg.receivedAt = ts;\n }\n }\n return msg;\n}\n\nfunction trimMessagesForStatus(\n messages: unknown[] | null | undefined,\n options: Required<NormalizeActiveChatOptions>,\n): unknown[] {\n if (!options.includeMessages || options.messageLimit <= 0 || options.totalBytesLimit <= 0) return [];\n if (!Array.isArray(messages) || messages.length === 0) return [];\n\n const recent = messages.slice(-options.messageLimit);\n const kept: unknown[] = [];\n let totalBytes = 0;\n\n for (let i = recent.length - 1; i >= 0; i -= 1) {\n let normalized = normalizeMessageTime(trimMessageForStatus(recent[i], options.stringLimit));\n let size = estimateBytes(normalized);\n\n if (size > options.totalBytesLimit) {\n normalized = normalizeMessageTime(trimMessageForStatus(recent[i], options.fallbackStringLimit));\n size = estimateBytes(normalized);\n }\n\n if (kept.length > 0 && (totalBytes + size) > options.totalBytesLimit) {\n continue;\n }\n\n kept.push(normalized);\n totalBytes += size;\n }\n\n return kept.reverse();\n}\n\nfunction hasApprovalButtons(activeModal?: { buttons?: unknown[] | null } | null): boolean {\n return (activeModal?.buttons?.length ?? 0) > 0;\n}\n\nexport function normalizeManagedStatus(\n status?: string | null,\n opts?: { activeModal?: { buttons?: unknown[] | null } | null },\n): ManagedStatus {\n if (hasApprovalButtons(opts?.activeModal)) return 'waiting_approval';\n\n const normalized = String(status || 'idle').trim().toLowerCase();\n if (normalized === 'waiting_approval') return 'waiting_approval';\n if (WORKING_STATUSES.has(normalized)) return 'generating';\n if (normalized === 'error') return 'error';\n if (normalized === 'stopped') return 'stopped';\n if (normalized === 'starting') return 'starting';\n if (normalized === 'panel_hidden') return 'panel_hidden';\n if (normalized === 'not_monitored') return 'not_monitored';\n if (normalized === 'disconnected') return 'disconnected';\n return 'idle';\n}\n\nexport function isManagedStatusWorking(status?: string | null): boolean {\n return normalizeManagedStatus(status) === 'generating';\n}\n\nexport function isManagedStatusWaiting(\n status?: string | null,\n opts?: { activeModal?: { buttons?: unknown[] | null } | null },\n): boolean {\n return normalizeManagedStatus(status, opts) === 'waiting_approval';\n}\n\nexport function normalizeActiveChatData<T extends ActiveChatData | null | undefined>(\n activeChat: T,\n options: NormalizeActiveChatOptions = FULL_STATUS_ACTIVE_CHAT_OPTIONS,\n): T extends null | undefined ? T : SessionActiveChatData {\n if (!activeChat) return activeChat as T extends null | undefined ? T : SessionActiveChatData;\n const resolvedOptions: Required<NormalizeActiveChatOptions> = {\n ...FULL_STATUS_ACTIVE_CHAT_OPTIONS,\n ...options,\n };\n const {\n messages: _messages,\n ...rest\n } = activeChat;\n const normalized: SessionActiveChatData = {\n ...rest,\n status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),\n activeModal: resolvedOptions.includeActiveModal && activeChat.activeModal ? {\n message: truncateString(activeChat.activeModal.message || '', STATUS_MODAL_MESSAGE_LIMIT),\n buttons: (activeChat.activeModal.buttons || []).map((button) =>\n truncateString(String(button || ''), STATUS_MODAL_BUTTON_LIMIT)\n ),\n } : null,\n inputContent: resolvedOptions.includeInputContent && activeChat.inputContent\n ? truncateString(activeChat.inputContent, 2 * 1024)\n : undefined,\n };\n if (resolvedOptions.includeMessages) {\n normalized.messages = trimMessagesForStatus(activeChat.messages, resolvedOptions) as SessionActiveChatData['messages'];\n }\n return normalized as T extends null | undefined ? T : SessionActiveChatData;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/status/normalize.ts"],"sourcesContent":["import type { ActiveChatData } from '../providers/provider-instance.js';\nimport type { SessionActiveChatData } from '../shared-types.js';\n\nexport type ManagedStatus =\n | 'idle'\n | 'generating'\n | 'waiting_approval'\n | 'waiting_choice'\n | 'error'\n | 'stopped'\n | 'starting'\n | 'panel_hidden'\n | 'not_monitored'\n | 'disconnected';\n\nconst WORKING_STATUSES = new Set([\n 'generating',\n 'streaming',\n 'loading',\n 'loading_reference',\n 'thinking',\n 'active',\n]);\n\nexport interface NormalizeActiveChatOptions {\n includeMessages?: boolean;\n includeInputContent?: boolean;\n includeActiveModal?: boolean;\n messageLimit?: number;\n totalBytesLimit?: number;\n stringLimit?: number;\n fallbackStringLimit?: number;\n}\n\n// Full snapshots are still capped, but can carry recent chat context for API/inspection use.\nconst FULL_STATUS_ACTIVE_CHAT_OPTIONS: Required<NormalizeActiveChatOptions> = {\n includeMessages: true,\n includeInputContent: true,\n includeActiveModal: true,\n messageLimit: 60,\n totalBytesLimit: 96 * 1024,\n stringLimit: 4 * 1024,\n fallbackStringLimit: 1024,\n};\n\n// Live/metadata snapshots only need routing + UI summary. Current chat text is loaded\n// on demand via `read_chat`, and older history via `chat_history`.\nexport const LIVE_STATUS_ACTIVE_CHAT_OPTIONS: Required<NormalizeActiveChatOptions> = {\n includeMessages: false,\n includeInputContent: false,\n includeActiveModal: false,\n messageLimit: 0,\n totalBytesLimit: 0,\n stringLimit: 512,\n fallbackStringLimit: 256,\n};\n\nconst STATUS_MODAL_MESSAGE_LIMIT = 2 * 1024;\nconst STATUS_MODAL_BUTTON_LIMIT = 120;\n\nfunction truncateString(value: string, maxChars: number): string {\n if (value.length <= maxChars) return value;\n if (maxChars <= 12) return value.slice(0, Math.max(0, maxChars));\n return `${value.slice(0, maxChars - 12)}...[truncated]`;\n}\n\nfunction truncateStringTail(value: string, maxChars: number): string {\n if (value.length <= maxChars) return value;\n if (maxChars <= 12) return value.slice(value.length - Math.max(0, maxChars));\n return `...[truncated]${value.slice(value.length - (maxChars - 12))}`;\n}\n\nfunction trimStructuredStrings(value: unknown, maxChars: number): unknown {\n if (typeof value === 'string') return truncateString(value, maxChars);\n if (Array.isArray(value)) return value.map((item) => trimStructuredStrings(item, maxChars));\n if (!value || typeof value !== 'object') return value;\n return Object.fromEntries(\n Object.entries(value).map(([key, nested]) => [key, trimStructuredStrings(nested, maxChars)]),\n );\n}\n\nfunction estimateBytes(value: unknown): number {\n try {\n return JSON.stringify(value).length;\n } catch {\n return String(value ?? '').length;\n }\n}\n\nfunction trimMessageForStatus(message: unknown, stringLimit: number): unknown {\n if (!message || typeof message !== 'object') return message;\n return trimStructuredStrings(message, stringLimit);\n}\n\n/**\n * Collapse timestamp / createdAt into receivedAt so downstream consumers\n * only ever need to read a single canonical time field.\n */\nfunction normalizeMessageTime(message: unknown): unknown {\n if (!message || typeof message !== 'object') return message;\n const msg = message as Record<string, unknown>;\n if (msg.receivedAt == null) {\n const fallback = msg.timestamp ?? msg.createdAt;\n if (fallback != null) {\n const ts = typeof fallback === 'string' ? Date.parse(fallback as string) : Number(fallback);\n if (Number.isFinite(ts) && ts > 0) msg.receivedAt = ts;\n }\n }\n return msg;\n}\n\nfunction trimMessagesForStatus(\n messages: unknown[] | null | undefined,\n options: Required<NormalizeActiveChatOptions>,\n): unknown[] {\n if (!options.includeMessages || options.messageLimit <= 0 || options.totalBytesLimit <= 0) return [];\n if (!Array.isArray(messages) || messages.length === 0) return [];\n\n const recent = messages.slice(-options.messageLimit);\n const kept: unknown[] = [];\n let totalBytes = 0;\n\n for (let i = recent.length - 1; i >= 0; i -= 1) {\n let normalized = normalizeMessageTime(trimMessageForStatus(recent[i], options.stringLimit));\n let size = estimateBytes(normalized);\n\n if (size > options.totalBytesLimit) {\n normalized = normalizeMessageTime(trimMessageForStatus(recent[i], options.fallbackStringLimit));\n size = estimateBytes(normalized);\n }\n\n if (kept.length > 0 && (totalBytes + size) > options.totalBytesLimit) {\n continue;\n }\n\n kept.push(normalized);\n totalBytes += size;\n }\n\n return kept.reverse();\n}\n\nfunction hasApprovalButtons(activeModal?: { buttons?: unknown[] | null } | null): boolean {\n return (activeModal?.buttons?.length ?? 0) > 0;\n}\n\nexport function normalizeManagedStatus(\n status?: string | null,\n opts?: { activeModal?: { buttons?: unknown[] | null } | null },\n): ManagedStatus {\n if (hasApprovalButtons(opts?.activeModal)) return 'waiting_approval';\n\n const normalized = String(status || 'idle').trim().toLowerCase();\n if (normalized === 'waiting_approval') return 'waiting_approval';\n if (normalized === 'waiting_choice') return 'waiting_choice';\n if (WORKING_STATUSES.has(normalized)) return 'generating';\n if (normalized === 'error') return 'error';\n if (normalized === 'stopped') return 'stopped';\n if (normalized === 'starting') return 'starting';\n if (normalized === 'panel_hidden') return 'panel_hidden';\n if (normalized === 'not_monitored') return 'not_monitored';\n if (normalized === 'disconnected') return 'disconnected';\n return 'idle';\n}\n\nexport function isManagedStatusWorking(status?: string | null): boolean {\n return normalizeManagedStatus(status) === 'generating';\n}\n\nexport function isManagedStatusWaiting(\n status?: string | null,\n opts?: { activeModal?: { buttons?: unknown[] | null } | null },\n): boolean {\n return normalizeManagedStatus(status, opts) === 'waiting_approval';\n}\n\nexport function normalizeActiveChatData<T extends ActiveChatData | null | undefined>(\n activeChat: T,\n options: NormalizeActiveChatOptions = FULL_STATUS_ACTIVE_CHAT_OPTIONS,\n): T extends null | undefined ? T : SessionActiveChatData {\n if (!activeChat) return activeChat as T extends null | undefined ? T : SessionActiveChatData;\n const resolvedOptions: Required<NormalizeActiveChatOptions> = {\n ...FULL_STATUS_ACTIVE_CHAT_OPTIONS,\n ...options,\n };\n const {\n messages: _messages,\n ...rest\n } = activeChat;\n const normalized: SessionActiveChatData = {\n ...rest,\n status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),\n activeModal: resolvedOptions.includeActiveModal && activeChat.activeModal ? {\n message: truncateString(activeChat.activeModal.message || '', STATUS_MODAL_MESSAGE_LIMIT),\n buttons: (activeChat.activeModal.buttons || []).map((button) =>\n truncateString(String(button || ''), STATUS_MODAL_BUTTON_LIMIT)\n ),\n } : null,\n inputContent: resolvedOptions.includeInputContent && activeChat.inputContent\n ? truncateString(activeChat.inputContent, 2 * 1024)\n : undefined,\n };\n if (resolvedOptions.includeMessages) {\n normalized.messages = trimMessagesForStatus(activeChat.messages, resolvedOptions) as SessionActiveChatData['messages'];\n }\n return normalized as T extends null | undefined ? T : SessionActiveChatData;\n}\n"],"mappings":"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","names":[]}
@@ -91,6 +91,7 @@ function normalizeManagedStatus(status, opts) {
91
91
  if (hasApprovalButtons(opts?.activeModal)) return "waiting_approval";
92
92
  const normalized = String(status || "idle").trim().toLowerCase();
93
93
  if (normalized === "waiting_approval") return "waiting_approval";
94
+ if (normalized === "waiting_choice") return "waiting_choice";
94
95
  if (WORKING_STATUSES.has(normalized)) return "generating";
95
96
  if (normalized === "error") return "error";
96
97
  if (normalized === "stopped") return "stopped";
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/status/normalize.ts"],"sourcesContent":["import type { ActiveChatData } from '../providers/provider-instance.js';\nimport type { SessionActiveChatData } from '../shared-types.js';\n\nexport type ManagedStatus =\n | 'idle'\n | 'generating'\n | 'waiting_approval'\n | 'error'\n | 'stopped'\n | 'starting'\n | 'panel_hidden'\n | 'not_monitored'\n | 'disconnected';\n\nconst WORKING_STATUSES = new Set([\n 'generating',\n 'streaming',\n 'loading',\n 'loading_reference',\n 'thinking',\n 'active',\n]);\n\nexport interface NormalizeActiveChatOptions {\n includeMessages?: boolean;\n includeInputContent?: boolean;\n includeActiveModal?: boolean;\n messageLimit?: number;\n totalBytesLimit?: number;\n stringLimit?: number;\n fallbackStringLimit?: number;\n}\n\n// Full snapshots are still capped, but can carry recent chat context for API/inspection use.\nconst FULL_STATUS_ACTIVE_CHAT_OPTIONS: Required<NormalizeActiveChatOptions> = {\n includeMessages: true,\n includeInputContent: true,\n includeActiveModal: true,\n messageLimit: 60,\n totalBytesLimit: 96 * 1024,\n stringLimit: 4 * 1024,\n fallbackStringLimit: 1024,\n};\n\n// Live/metadata snapshots only need routing + UI summary. Current chat text is loaded\n// on demand via `read_chat`, and older history via `chat_history`.\nexport const LIVE_STATUS_ACTIVE_CHAT_OPTIONS: Required<NormalizeActiveChatOptions> = {\n includeMessages: false,\n includeInputContent: false,\n includeActiveModal: false,\n messageLimit: 0,\n totalBytesLimit: 0,\n stringLimit: 512,\n fallbackStringLimit: 256,\n};\n\nconst STATUS_MODAL_MESSAGE_LIMIT = 2 * 1024;\nconst STATUS_MODAL_BUTTON_LIMIT = 120;\n\nfunction truncateString(value: string, maxChars: number): string {\n if (value.length <= maxChars) return value;\n if (maxChars <= 12) return value.slice(0, Math.max(0, maxChars));\n return `${value.slice(0, maxChars - 12)}...[truncated]`;\n}\n\nfunction truncateStringTail(value: string, maxChars: number): string {\n if (value.length <= maxChars) return value;\n if (maxChars <= 12) return value.slice(value.length - Math.max(0, maxChars));\n return `...[truncated]${value.slice(value.length - (maxChars - 12))}`;\n}\n\nfunction trimStructuredStrings(value: unknown, maxChars: number): unknown {\n if (typeof value === 'string') return truncateString(value, maxChars);\n if (Array.isArray(value)) return value.map((item) => trimStructuredStrings(item, maxChars));\n if (!value || typeof value !== 'object') return value;\n return Object.fromEntries(\n Object.entries(value).map(([key, nested]) => [key, trimStructuredStrings(nested, maxChars)]),\n );\n}\n\nfunction estimateBytes(value: unknown): number {\n try {\n return JSON.stringify(value).length;\n } catch {\n return String(value ?? '').length;\n }\n}\n\nfunction trimMessageForStatus(message: unknown, stringLimit: number): unknown {\n if (!message || typeof message !== 'object') return message;\n return trimStructuredStrings(message, stringLimit);\n}\n\n/**\n * Collapse timestamp / createdAt into receivedAt so downstream consumers\n * only ever need to read a single canonical time field.\n */\nfunction normalizeMessageTime(message: unknown): unknown {\n if (!message || typeof message !== 'object') return message;\n const msg = message as Record<string, unknown>;\n if (msg.receivedAt == null) {\n const fallback = msg.timestamp ?? msg.createdAt;\n if (fallback != null) {\n const ts = typeof fallback === 'string' ? Date.parse(fallback as string) : Number(fallback);\n if (Number.isFinite(ts) && ts > 0) msg.receivedAt = ts;\n }\n }\n return msg;\n}\n\nfunction trimMessagesForStatus(\n messages: unknown[] | null | undefined,\n options: Required<NormalizeActiveChatOptions>,\n): unknown[] {\n if (!options.includeMessages || options.messageLimit <= 0 || options.totalBytesLimit <= 0) return [];\n if (!Array.isArray(messages) || messages.length === 0) return [];\n\n const recent = messages.slice(-options.messageLimit);\n const kept: unknown[] = [];\n let totalBytes = 0;\n\n for (let i = recent.length - 1; i >= 0; i -= 1) {\n let normalized = normalizeMessageTime(trimMessageForStatus(recent[i], options.stringLimit));\n let size = estimateBytes(normalized);\n\n if (size > options.totalBytesLimit) {\n normalized = normalizeMessageTime(trimMessageForStatus(recent[i], options.fallbackStringLimit));\n size = estimateBytes(normalized);\n }\n\n if (kept.length > 0 && (totalBytes + size) > options.totalBytesLimit) {\n continue;\n }\n\n kept.push(normalized);\n totalBytes += size;\n }\n\n return kept.reverse();\n}\n\nfunction hasApprovalButtons(activeModal?: { buttons?: unknown[] | null } | null): boolean {\n return (activeModal?.buttons?.length ?? 0) > 0;\n}\n\nexport function normalizeManagedStatus(\n status?: string | null,\n opts?: { activeModal?: { buttons?: unknown[] | null } | null },\n): ManagedStatus {\n if (hasApprovalButtons(opts?.activeModal)) return 'waiting_approval';\n\n const normalized = String(status || 'idle').trim().toLowerCase();\n if (normalized === 'waiting_approval') return 'waiting_approval';\n if (WORKING_STATUSES.has(normalized)) return 'generating';\n if (normalized === 'error') return 'error';\n if (normalized === 'stopped') return 'stopped';\n if (normalized === 'starting') return 'starting';\n if (normalized === 'panel_hidden') return 'panel_hidden';\n if (normalized === 'not_monitored') return 'not_monitored';\n if (normalized === 'disconnected') return 'disconnected';\n return 'idle';\n}\n\nexport function isManagedStatusWorking(status?: string | null): boolean {\n return normalizeManagedStatus(status) === 'generating';\n}\n\nexport function isManagedStatusWaiting(\n status?: string | null,\n opts?: { activeModal?: { buttons?: unknown[] | null } | null },\n): boolean {\n return normalizeManagedStatus(status, opts) === 'waiting_approval';\n}\n\nexport function normalizeActiveChatData<T extends ActiveChatData | null | undefined>(\n activeChat: T,\n options: NormalizeActiveChatOptions = FULL_STATUS_ACTIVE_CHAT_OPTIONS,\n): T extends null | undefined ? T : SessionActiveChatData {\n if (!activeChat) return activeChat as T extends null | undefined ? T : SessionActiveChatData;\n const resolvedOptions: Required<NormalizeActiveChatOptions> = {\n ...FULL_STATUS_ACTIVE_CHAT_OPTIONS,\n ...options,\n };\n const {\n messages: _messages,\n ...rest\n } = activeChat;\n const normalized: SessionActiveChatData = {\n ...rest,\n status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),\n activeModal: resolvedOptions.includeActiveModal && activeChat.activeModal ? {\n message: truncateString(activeChat.activeModal.message || '', STATUS_MODAL_MESSAGE_LIMIT),\n buttons: (activeChat.activeModal.buttons || []).map((button) =>\n truncateString(String(button || ''), STATUS_MODAL_BUTTON_LIMIT)\n ),\n } : null,\n inputContent: resolvedOptions.includeInputContent && activeChat.inputContent\n ? truncateString(activeChat.inputContent, 2 * 1024)\n : undefined,\n };\n if (resolvedOptions.includeMessages) {\n normalized.messages = trimMessagesForStatus(activeChat.messages, resolvedOptions) as SessionActiveChatData['messages'];\n }\n return normalized as T extends null | undefined ? T : SessionActiveChatData;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/status/normalize.ts"],"sourcesContent":["import type { ActiveChatData } from '../providers/provider-instance.js';\nimport type { SessionActiveChatData } from '../shared-types.js';\n\nexport type ManagedStatus =\n | 'idle'\n | 'generating'\n | 'waiting_approval'\n | 'waiting_choice'\n | 'error'\n | 'stopped'\n | 'starting'\n | 'panel_hidden'\n | 'not_monitored'\n | 'disconnected';\n\nconst WORKING_STATUSES = new Set([\n 'generating',\n 'streaming',\n 'loading',\n 'loading_reference',\n 'thinking',\n 'active',\n]);\n\nexport interface NormalizeActiveChatOptions {\n includeMessages?: boolean;\n includeInputContent?: boolean;\n includeActiveModal?: boolean;\n messageLimit?: number;\n totalBytesLimit?: number;\n stringLimit?: number;\n fallbackStringLimit?: number;\n}\n\n// Full snapshots are still capped, but can carry recent chat context for API/inspection use.\nconst FULL_STATUS_ACTIVE_CHAT_OPTIONS: Required<NormalizeActiveChatOptions> = {\n includeMessages: true,\n includeInputContent: true,\n includeActiveModal: true,\n messageLimit: 60,\n totalBytesLimit: 96 * 1024,\n stringLimit: 4 * 1024,\n fallbackStringLimit: 1024,\n};\n\n// Live/metadata snapshots only need routing + UI summary. Current chat text is loaded\n// on demand via `read_chat`, and older history via `chat_history`.\nexport const LIVE_STATUS_ACTIVE_CHAT_OPTIONS: Required<NormalizeActiveChatOptions> = {\n includeMessages: false,\n includeInputContent: false,\n includeActiveModal: false,\n messageLimit: 0,\n totalBytesLimit: 0,\n stringLimit: 512,\n fallbackStringLimit: 256,\n};\n\nconst STATUS_MODAL_MESSAGE_LIMIT = 2 * 1024;\nconst STATUS_MODAL_BUTTON_LIMIT = 120;\n\nfunction truncateString(value: string, maxChars: number): string {\n if (value.length <= maxChars) return value;\n if (maxChars <= 12) return value.slice(0, Math.max(0, maxChars));\n return `${value.slice(0, maxChars - 12)}...[truncated]`;\n}\n\nfunction truncateStringTail(value: string, maxChars: number): string {\n if (value.length <= maxChars) return value;\n if (maxChars <= 12) return value.slice(value.length - Math.max(0, maxChars));\n return `...[truncated]${value.slice(value.length - (maxChars - 12))}`;\n}\n\nfunction trimStructuredStrings(value: unknown, maxChars: number): unknown {\n if (typeof value === 'string') return truncateString(value, maxChars);\n if (Array.isArray(value)) return value.map((item) => trimStructuredStrings(item, maxChars));\n if (!value || typeof value !== 'object') return value;\n return Object.fromEntries(\n Object.entries(value).map(([key, nested]) => [key, trimStructuredStrings(nested, maxChars)]),\n );\n}\n\nfunction estimateBytes(value: unknown): number {\n try {\n return JSON.stringify(value).length;\n } catch {\n return String(value ?? '').length;\n }\n}\n\nfunction trimMessageForStatus(message: unknown, stringLimit: number): unknown {\n if (!message || typeof message !== 'object') return message;\n return trimStructuredStrings(message, stringLimit);\n}\n\n/**\n * Collapse timestamp / createdAt into receivedAt so downstream consumers\n * only ever need to read a single canonical time field.\n */\nfunction normalizeMessageTime(message: unknown): unknown {\n if (!message || typeof message !== 'object') return message;\n const msg = message as Record<string, unknown>;\n if (msg.receivedAt == null) {\n const fallback = msg.timestamp ?? msg.createdAt;\n if (fallback != null) {\n const ts = typeof fallback === 'string' ? Date.parse(fallback as string) : Number(fallback);\n if (Number.isFinite(ts) && ts > 0) msg.receivedAt = ts;\n }\n }\n return msg;\n}\n\nfunction trimMessagesForStatus(\n messages: unknown[] | null | undefined,\n options: Required<NormalizeActiveChatOptions>,\n): unknown[] {\n if (!options.includeMessages || options.messageLimit <= 0 || options.totalBytesLimit <= 0) return [];\n if (!Array.isArray(messages) || messages.length === 0) return [];\n\n const recent = messages.slice(-options.messageLimit);\n const kept: unknown[] = [];\n let totalBytes = 0;\n\n for (let i = recent.length - 1; i >= 0; i -= 1) {\n let normalized = normalizeMessageTime(trimMessageForStatus(recent[i], options.stringLimit));\n let size = estimateBytes(normalized);\n\n if (size > options.totalBytesLimit) {\n normalized = normalizeMessageTime(trimMessageForStatus(recent[i], options.fallbackStringLimit));\n size = estimateBytes(normalized);\n }\n\n if (kept.length > 0 && (totalBytes + size) > options.totalBytesLimit) {\n continue;\n }\n\n kept.push(normalized);\n totalBytes += size;\n }\n\n return kept.reverse();\n}\n\nfunction hasApprovalButtons(activeModal?: { buttons?: unknown[] | null } | null): boolean {\n return (activeModal?.buttons?.length ?? 0) > 0;\n}\n\nexport function normalizeManagedStatus(\n status?: string | null,\n opts?: { activeModal?: { buttons?: unknown[] | null } | null },\n): ManagedStatus {\n if (hasApprovalButtons(opts?.activeModal)) return 'waiting_approval';\n\n const normalized = String(status || 'idle').trim().toLowerCase();\n if (normalized === 'waiting_approval') return 'waiting_approval';\n if (normalized === 'waiting_choice') return 'waiting_choice';\n if (WORKING_STATUSES.has(normalized)) return 'generating';\n if (normalized === 'error') return 'error';\n if (normalized === 'stopped') return 'stopped';\n if (normalized === 'starting') return 'starting';\n if (normalized === 'panel_hidden') return 'panel_hidden';\n if (normalized === 'not_monitored') return 'not_monitored';\n if (normalized === 'disconnected') return 'disconnected';\n return 'idle';\n}\n\nexport function isManagedStatusWorking(status?: string | null): boolean {\n return normalizeManagedStatus(status) === 'generating';\n}\n\nexport function isManagedStatusWaiting(\n status?: string | null,\n opts?: { activeModal?: { buttons?: unknown[] | null } | null },\n): boolean {\n return normalizeManagedStatus(status, opts) === 'waiting_approval';\n}\n\nexport function normalizeActiveChatData<T extends ActiveChatData | null | undefined>(\n activeChat: T,\n options: NormalizeActiveChatOptions = FULL_STATUS_ACTIVE_CHAT_OPTIONS,\n): T extends null | undefined ? T : SessionActiveChatData {\n if (!activeChat) return activeChat as T extends null | undefined ? T : SessionActiveChatData;\n const resolvedOptions: Required<NormalizeActiveChatOptions> = {\n ...FULL_STATUS_ACTIVE_CHAT_OPTIONS,\n ...options,\n };\n const {\n messages: _messages,\n ...rest\n } = activeChat;\n const normalized: SessionActiveChatData = {\n ...rest,\n status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),\n activeModal: resolvedOptions.includeActiveModal && activeChat.activeModal ? {\n message: truncateString(activeChat.activeModal.message || '', STATUS_MODAL_MESSAGE_LIMIT),\n buttons: (activeChat.activeModal.buttons || []).map((button) =>\n truncateString(String(button || ''), STATUS_MODAL_BUTTON_LIMIT)\n ),\n } : null,\n inputContent: resolvedOptions.includeInputContent && activeChat.inputContent\n ? truncateString(activeChat.inputContent, 2 * 1024)\n : undefined,\n };\n if (resolvedOptions.includeMessages) {\n normalized.messages = trimMessagesForStatus(activeChat.messages, resolvedOptions) as SessionActiveChatData['messages'];\n }\n return normalized as T extends null | undefined ? T : SessionActiveChatData;\n}\n"],"mappings":"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","names":[]}
@@ -46,6 +46,8 @@ export declare class DaemonStatusReporter {
46
46
  private lastStatusSentAt;
47
47
  private statusPendingThrottle;
48
48
  private lastP2PStatusHash;
49
+ private lastP2PStatusSentAt;
50
+ private p2pDebounceTimer;
49
51
  private lastServerStatusHash;
50
52
  private lastStatusSummary;
51
53
  private statusTimer;
@@ -75,6 +75,7 @@ export declare function getSessionCompletionMarker(session: {
75
75
  receivedAt?: number | string;
76
76
  timestamp?: number | string;
77
77
  _turnKey?: string;
78
+ kind?: string;
78
79
  }> | null;
79
80
  } | null;
80
81
  }): string;
package/dist/types.d.ts CHANGED
@@ -36,6 +36,11 @@ export interface ChatMessage {
36
36
  index?: number;
37
37
  timestamp?: number;
38
38
  receivedAt?: number;
39
+ /** (A2.3) Monotonic sequence number per (session, source). Producer-asserted
40
+ * when emitted by v2-aware providers (transcript v2 schema); otherwise
41
+ * derived by the daemon from receivedAt/timestamp/index. ChatSourceMachine
42
+ * uses this as the native peak watermark for regression detection. */
43
+ sequence?: number;
39
44
  _turnKey?: string;
40
45
  /** Tool calls associated with this message */
41
46
  toolCalls?: ToolCallInfo[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.9.82-rc.22",
3
+ "version": "0.9.82-rc.220",
4
4
  "description": "ADHDev daemon core — CDP, IDE detection, providers, command execution",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -27,7 +27,7 @@
27
27
  "scripts": {
28
28
  "build": "tsup && npm run build:types",
29
29
  "build:types": "tsc -p tsconfig.json --emitDeclarationOnly --declaration --declarationMap false",
30
- "dev": "tsup --watch",
30
+ "dev": "tsup --watch --no-clean",
31
31
  "test": "vitest run",
32
32
  "test:watch": "vitest",
33
33
  "typecheck": "tsc --noEmit -p tsconfig.json"
@@ -48,7 +48,9 @@
48
48
  "dependencies": {
49
49
  "@adhdev/session-host-core": "*",
50
50
  "@agentclientprotocol/sdk": "^0.16.1",
51
- "@xterm/xterm": "^6.0.0",
51
+ "ajv": "^8.20.0",
52
+ "ajv-formats": "^3.0.1",
53
+ "better-sqlite3": "^12.10.0",
52
54
  "chalk": "^5.3.0",
53
55
  "chokidar": "^4.0.3",
54
56
  "conf": "^13.0.0",
@@ -60,6 +62,7 @@
60
62
  "@adhdev/ghostty-vt-node": "*"
61
63
  },
62
64
  "devDependencies": {
65
+ "@types/better-sqlite3": "^7.6.13",
63
66
  "@types/js-yaml": "^4.0.9",
64
67
  "@types/node": "^22.0.0",
65
68
  "@types/ws": "^8.18.1",
@@ -19,7 +19,7 @@ import type { SessionRegistry } from '../sessions/registry.js';
19
19
  import { reconcileIdeRuntimeSessions } from '../sessions/reconcile.js';
20
20
  import { LOG } from '../logging/logger.js';
21
21
  import type { AgentStreamState } from './types.js';
22
- import { formatAutoApprovalMessage, pickApprovalButton } from '../providers/approval-utils.js';
22
+ import { formatAutoApprovalMessage, pickAutoApprovalButton } from '../providers/approval-utils.js';
23
23
  import type { ProviderModule } from '../providers/contracts.js';
24
24
  import { buildRuntimeSystemChatMessage } from '../providers/chat-message-normalization.js';
25
25
 
@@ -210,8 +210,7 @@ export class AgentStreamPoller {
210
210
  if (stream?.status === 'waiting_approval') {
211
211
  const autoApprove = providerLoader.getSettings(stream.agentType).autoApprove !== false;
212
212
  if (autoApprove && resolvedActiveSessionId) {
213
- const provider = providerLoader.getMeta(stream.agentType);
214
- const { label: buttonLabel } = pickApprovalButton(stream.activeModal?.buttons, provider);
213
+ const { label: buttonLabel } = pickAutoApprovalButton(stream.activeModal?.buttons);
215
214
  const approved = await agentStreamManager.resolveSessionAction(cdp, resolvedActiveSessionId, 'approve', buttonLabel);
216
215
  if (approved) {
217
216
  const effectId = [
@@ -37,6 +37,9 @@ import type { PtyTransportFactory } from '../cli-adapters/pty-transport.js';
37
37
  import type { IdeProviderInstance } from '../providers/ide-provider-instance.js';
38
38
  import { createDefaultGitCommandServices } from '../git/git-commands.js';
39
39
  import { setupMeshEventForwarding } from '../mesh/mesh-events.js';
40
+ import { loadMeshCoordinatorRegistry } from '../mesh/coordinator-registry.js';
41
+ import { applyProcessHardening } from './process-hardening.js';
42
+ import { installProviderProcessShim } from '../providers/sdk/v1/sandbox/require-whitelist.js';
40
43
 
41
44
  // ─── Init Config ───
42
45
 
@@ -60,6 +63,7 @@ export interface DaemonInitConfig {
60
63
 
61
64
  /** Router transport-specific callbacks */
62
65
  onStatusChange?: () => void;
66
+ onMeshStateChange?: (meshId: string) => void;
63
67
  onPostChatCommand?: () => void;
64
68
  sessionHostControl?: SessionHostControlPlane | null;
65
69
  getCdpLogFn?: (ideType: string) => (msg: string) => void;
@@ -129,8 +133,16 @@ export interface DaemonDevSupportOptions {
129
133
  * 8. Start instance ticking
130
134
  */
131
135
  export async function initDaemonComponents(config: DaemonInitConfig): Promise<DaemonComponents> {
136
+ // 0. Process-level hardening (must run before any provider script is loaded).
137
+ // Freezes built-in prototypes (Object/Array/Function/String/Number/Boolean/Promise)
138
+ // and shadows process.exit/kill/abort/binding/dlopen so provider-script callers
139
+ // throw instead of killing the daemon. See ./process-hardening.ts for details.
140
+ applyProcessHardening();
141
+ installProviderProcessShim();
142
+
132
143
  // 1. Global log interceptor
133
144
  installGlobalInterceptor();
145
+ loadMeshCoordinatorRegistry();
134
146
 
135
147
  // 2. ProviderLoader (provider source mode from config.json)
136
148
  const appConfig = loadConfig();
@@ -142,16 +154,11 @@ export async function initDaemonComponents(config: DaemonInitConfig): Promise<Da
142
154
  userDir: appConfig.providerDir,
143
155
  });
144
156
 
145
- // If no upstream providers exist, fetch them first (blocking — critical for new users)
146
- if (!disableUpstream && !providerLoader.hasUpstream()) {
147
- LOG.info('Provider', 'No upstream providers found downloading from GitHub...');
148
- try {
149
- await providerLoader.fetchLatest();
150
- } catch (e: any) {
151
- LOG.warn('Provider', `⚠ Failed to fetch providers: ${e?.message}`);
152
- }
153
- }
154
-
157
+ // Boot-time auto-sync is intentionally disabled. The user picks which
158
+ // providers to install via the dashboard onboarding / Providers tab; the
159
+ // daemon ships empty and only contains what the user explicitly installs.
160
+ // Manual sync is still available via the install / check_provider_updates
161
+ // commands (and the REST endpoint at /api/v1/providers/updates).
155
162
  providerLoader.loadAll();
156
163
  providerLoader.registerToDetector();
157
164
 
@@ -304,11 +311,13 @@ export async function initDaemonComponents(config: DaemonInitConfig): Promise<Da
304
311
  },
305
312
  onIdeConnected: () => poller?.start(),
306
313
  onStatusChange: config.onStatusChange,
314
+ onMeshStateChange: config.onMeshStateChange,
307
315
  onPostChatCommand: config.onPostChatCommand,
308
316
  sessionHostControl: config.sessionHostControl,
309
317
  statusInstanceId: config.statusInstanceId,
310
318
  statusVersion: config.statusVersion,
311
319
  getMeshPeerConnectionStatus: config.getMeshPeerConnectionStatus,
320
+ dispatchMeshCommand: config.dispatchMeshCommand,
312
321
  getCdpLogFn: config.getCdpLogFn || ((ideType: string) => LOG.forComponent(`CDP:${ideType}`).asLogFn()),
313
322
  });
314
323
 
@@ -344,6 +353,9 @@ export async function initDaemonComponents(config: DaemonInitConfig): Promise<Da
344
353
  // 11. Setup Mesh Event Forwarding
345
354
  setupMeshEventForwarding(components);
346
355
 
356
+ // 12. Resume any refine jobs that were interrupted by a previous daemon restart.
357
+ setImmediate(() => void router.resumePendingRefineJobsOnStartup());
358
+
347
359
  return components;
348
360
  }
349
361