@adhdev/daemon-core 0.9.82-rc.17 → 0.9.82-rc.170

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 (221) hide show
  1. package/dist/boot/process-hardening.d.ts +50 -0
  2. package/dist/chat/source-machine.d.ts +166 -0
  3. package/dist/chat/source-resolver.d.ts +104 -0
  4. package/dist/chat/subscription-updates.d.ts +1 -0
  5. package/dist/cli-adapter-types.d.ts +22 -2
  6. package/dist/cli-adapters/cli-script-runner.d.ts +117 -0
  7. package/dist/cli-adapters/cli-state-engine.d.ts +178 -0
  8. package/dist/cli-adapters/provider-cli-adapter.d.ts +106 -63
  9. package/dist/cli-adapters/provider-cli-parse.d.ts +4 -0
  10. package/dist/cli-adapters/provider-cli-shared.d.ts +29 -0
  11. package/dist/cli-adapters/raw-terminal-io.d.ts +37 -0
  12. package/dist/commands/handler.d.ts +110 -0
  13. package/dist/commands/mesh-coordinator.d.ts +72 -1
  14. package/dist/commands/router.d.ts +22 -0
  15. package/dist/config/chat-history.d.ts +7 -0
  16. package/dist/config/config.d.ts +5 -0
  17. package/dist/config/mesh-config.d.ts +71 -1
  18. package/dist/git/git-commands.d.ts +5 -1
  19. package/dist/index.d.ts +35 -6
  20. package/dist/index.js +18621 -3760
  21. package/dist/index.js.map +1 -1
  22. package/dist/index.mjs +18525 -3732
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/installer.d.ts +1 -4
  25. package/dist/ipc/local-ipc-server.d.ts +91 -0
  26. package/dist/launch.d.ts +1 -1
  27. package/dist/logging/async-batch-writer.d.ts +10 -0
  28. package/dist/mesh/beads-db.d.ts +72 -0
  29. package/dist/mesh/contracts.d.ts +164 -0
  30. package/dist/mesh/coordinator-prompt.d.ts +30 -0
  31. package/dist/mesh/coordinator-registry.d.ts +59 -0
  32. package/dist/mesh/mesh-active-work.d.ts +90 -0
  33. package/dist/mesh/mesh-events.d.ts +96 -5
  34. package/dist/mesh/mesh-fast-forward.d.ts +39 -0
  35. package/dist/mesh/mesh-host-ownership.d.ts +9 -0
  36. package/dist/mesh/mesh-ledger.d.ts +58 -1
  37. package/dist/mesh/mesh-refine-status.d.ts +26 -0
  38. package/dist/mesh/mesh-work-queue.d.ts +44 -5
  39. package/dist/mesh/preview-freshness.d.ts +18 -0
  40. package/dist/mesh/refine-config.d.ts +193 -0
  41. package/dist/mesh/worktree-bootstrap-config.d.ts +113 -0
  42. package/dist/providers/approval-utils.d.ts +13 -0
  43. package/dist/providers/cli-provider-instance.d.ts +9 -3
  44. package/dist/providers/contracts.d.ts +98 -5
  45. package/dist/providers/external-sources.d.ts +71 -0
  46. package/dist/providers/native-history/antigravity-cli-transcript.d.ts +100 -0
  47. package/dist/providers/native-history/claude-cli-transcript.d.ts +70 -0
  48. package/dist/providers/native-history/codex-cli-transcript.d.ts +73 -0
  49. package/dist/providers/native-history/dispatcher.d.ts +24 -0
  50. package/dist/providers/native-history/hermes-cli-transcript.d.ts +30 -0
  51. package/dist/providers/native-history/index.d.ts +13 -0
  52. package/dist/providers/provider-instance.d.ts +3 -0
  53. package/dist/providers/provider-loader.d.ts +26 -4
  54. package/dist/providers/provider-trust.d.ts +31 -0
  55. package/dist/providers/read-chat-contract.d.ts +29 -0
  56. package/dist/providers/sdk/v1/builders/acp/detect-status.d.ts +68 -0
  57. package/dist/providers/sdk/v1/builders/cli/detect-status.d.ts +85 -0
  58. package/dist/providers/sdk/v1/builders/cli/parse-approval-squash.d.ts +59 -0
  59. package/dist/providers/sdk/v1/builders/cli/parse-approval.d.ts +65 -0
  60. package/dist/providers/sdk/v1/builders/cli/parse-session.d.ts +91 -0
  61. package/dist/providers/sdk/v1/builders/cli/visible-region.d.ts +42 -0
  62. package/dist/providers/sdk/v1/fixture-tooling/format.d.ts +126 -0
  63. package/dist/providers/sdk/v1/fixture-tooling/index.d.ts +8 -0
  64. package/dist/providers/sdk/v1/fixture-tooling/replay.d.ts +38 -0
  65. package/dist/providers/sdk/v1/index.d.ts +30 -0
  66. package/dist/providers/sdk/v1/sandbox/README-design.d.ts +193 -0
  67. package/dist/providers/sdk/v1/sandbox/require-whitelist.d.ts +74 -0
  68. package/dist/providers/sdk/v1/sandbox/script-runner.d.ts +98 -0
  69. package/dist/providers/sdk/v1/types/cli/index.d.ts +277 -0
  70. package/dist/providers/sdk/v1/types/common/index.d.ts +169 -0
  71. package/dist/providers/sdk/v1/validators/index.d.ts +5 -0
  72. package/dist/providers/sdk/v1/validators/manifest.d.ts +40 -0
  73. package/dist/providers/sdk/v1/validators/taint.d.ts +52 -0
  74. package/dist/providers/spec/adapter.d.ts +56 -0
  75. package/dist/providers/spec/cli-adapter.d.ts +95 -0
  76. package/dist/providers/spec/driver.d.ts +149 -0
  77. package/dist/providers/spec/evaluator.d.ts +47 -0
  78. package/dist/providers/spec/loader.d.ts +14 -0
  79. package/dist/providers/spec/native-history-executor.d.ts +39 -0
  80. package/dist/providers/spec/route.d.ts +4 -0
  81. package/dist/providers/spec/schema.gen.d.ts +511 -0
  82. package/dist/providers/spec/types.d.ts +212 -0
  83. package/dist/providers/transcript-v2.d.ts +176 -0
  84. package/dist/providers/types/interactive-prompt.d.ts +48 -0
  85. package/dist/repo-mesh-types.d.ts +100 -1
  86. package/dist/sessions/registry.d.ts +3 -0
  87. package/dist/shared-types.d.ts +42 -1
  88. package/dist/status/reporter.d.ts +2 -0
  89. package/dist/status/snapshot.d.ts +1 -0
  90. package/dist/types.d.ts +5 -0
  91. package/package.json +7 -2
  92. package/src/agent-stream/poller.ts +2 -3
  93. package/src/boot/daemon-lifecycle.ts +17 -10
  94. package/src/boot/process-hardening.ts +89 -0
  95. package/src/chat/source-machine.ts +534 -0
  96. package/src/chat/source-resolver.ts +0 -0
  97. package/src/chat/subscription-updates.ts +14 -1
  98. package/src/cli-adapter-types.d.ts +1 -0
  99. package/src/cli-adapter-types.ts +21 -2
  100. package/src/cli-adapters/cli-script-runner.ts +421 -0
  101. package/src/cli-adapters/cli-state-engine.ts +1086 -0
  102. package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
  103. package/src/cli-adapters/provider-cli-adapter.ts +670 -1137
  104. package/src/cli-adapters/provider-cli-parse.d.ts +1 -0
  105. package/src/cli-adapters/provider-cli-parse.ts +13 -0
  106. package/src/cli-adapters/provider-cli-runtime.ts +3 -1
  107. package/src/cli-adapters/provider-cli-shared.d.ts +2 -0
  108. package/src/cli-adapters/provider-cli-shared.ts +59 -11
  109. package/src/cli-adapters/raw-terminal-io.ts +252 -0
  110. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +17 -1
  111. package/src/cli-adapters/terminal-backends/xterm-backend.ts +8 -1
  112. package/src/commands/chat-commands.ts +1597 -60
  113. package/src/commands/cli-manager.ts +214 -3
  114. package/src/commands/handler.ts +809 -2
  115. package/src/commands/mesh-coordinator.ts +231 -127
  116. package/src/commands/router.ts +3559 -502
  117. package/src/config/chat-history.ts +87 -24
  118. package/src/config/config.ts +12 -0
  119. package/src/config/mesh-config.ts +264 -2
  120. package/src/config/recent-activity.ts +8 -2
  121. package/src/daemon/dev-cli-debug.ts +10 -1
  122. package/src/detection/ide-detector.ts +26 -16
  123. package/src/git/git-commands.ts +17 -5
  124. package/src/git/git-worktree.ts +8 -1
  125. package/src/index.ts +113 -5
  126. package/src/installer.d.ts +1 -1
  127. package/src/installer.ts +8 -6
  128. package/src/ipc/local-ipc-server.ts +278 -0
  129. package/src/launch.d.ts +1 -1
  130. package/src/launch.ts +37 -28
  131. package/src/logging/async-batch-writer.ts +55 -0
  132. package/src/logging/logger.ts +2 -1
  133. package/src/mesh/beads-db.ts +479 -0
  134. package/src/mesh/contracts.ts +329 -0
  135. package/src/mesh/coordinator-prompt.ts +204 -30
  136. package/src/mesh/coordinator-registry.ts +121 -0
  137. package/src/mesh/mesh-active-work.ts +437 -0
  138. package/src/mesh/mesh-events.ts +879 -61
  139. package/src/mesh/mesh-fast-forward.ts +430 -0
  140. package/src/mesh/mesh-host-ownership.ts +73 -0
  141. package/src/mesh/mesh-ledger.ts +457 -104
  142. package/src/mesh/mesh-refine-status.ts +144 -0
  143. package/src/mesh/mesh-work-queue.ts +216 -158
  144. package/src/mesh/preview-freshness.ts +118 -0
  145. package/src/mesh/refine-config.ts +366 -0
  146. package/src/mesh/worktree-bootstrap-config.ts +247 -0
  147. package/src/providers/approval-utils.d.ts +4 -0
  148. package/src/providers/approval-utils.ts +47 -5
  149. package/src/providers/chat-message-normalization.ts +4 -11
  150. package/src/providers/cli-provider-instance.ts +452 -54
  151. package/src/providers/contracts.ts +105 -5
  152. package/src/providers/external-sources.ts +218 -0
  153. package/src/providers/ide-provider-instance.ts +19 -5
  154. package/src/providers/native-history/antigravity-cli-transcript.ts +643 -0
  155. package/src/providers/native-history/claude-cli-transcript.ts +396 -0
  156. package/src/providers/native-history/codex-cli-transcript.ts +419 -0
  157. package/src/providers/native-history/dispatcher.ts +227 -0
  158. package/src/providers/native-history/hermes-cli-transcript.ts +230 -0
  159. package/src/providers/native-history/index.ts +30 -0
  160. package/src/providers/provider-instance.ts +3 -0
  161. package/src/providers/provider-loader.ts +585 -50
  162. package/src/providers/provider-schema.ts +31 -13
  163. package/src/providers/provider-trust.ts +114 -0
  164. package/src/providers/read-chat-contract.ts +76 -16
  165. package/src/providers/sdk/README.md +49 -0
  166. package/src/providers/sdk/v1/builders/acp/detect-status.ts +144 -0
  167. package/src/providers/sdk/v1/builders/cli/detect-status.ts +262 -0
  168. package/src/providers/sdk/v1/builders/cli/parse-approval-squash.ts +158 -0
  169. package/src/providers/sdk/v1/builders/cli/parse-approval.ts +250 -0
  170. package/src/providers/sdk/v1/builders/cli/parse-session.ts +276 -0
  171. package/src/providers/sdk/v1/builders/cli/visible-region.ts +143 -0
  172. package/src/providers/sdk/v1/fixture-tooling/format.ts +130 -0
  173. package/src/providers/sdk/v1/fixture-tooling/index.ts +22 -0
  174. package/src/providers/sdk/v1/fixture-tooling/replay.ts +352 -0
  175. package/src/providers/sdk/v1/index.ts +152 -0
  176. package/src/providers/sdk/v1/sandbox/README-design.ts +195 -0
  177. package/src/providers/sdk/v1/sandbox/require-whitelist.ts +472 -0
  178. package/src/providers/sdk/v1/sandbox/script-runner.ts +150 -0
  179. package/src/providers/sdk/v1/schemas/cli/provider.schema.json +458 -0
  180. package/src/providers/sdk/v1/schemas/primitives/acp-session-protocol-v1.json +131 -0
  181. package/src/providers/sdk/v1/schemas/primitives/native-history-codex-rollout-v1.json +66 -0
  182. package/src/providers/sdk/v1/schemas/primitives/tui-approval-squash-v1.json +91 -0
  183. package/src/providers/sdk/v1/schemas/primitives/tui-assistant-block-v1.json +91 -0
  184. package/src/providers/sdk/v1/schemas/primitives/tui-cue-ordering-v1.json +47 -0
  185. package/src/providers/sdk/v1/schemas/primitives/tui-dispatch-order-v1.json +32 -0
  186. package/src/providers/sdk/v1/schemas/primitives/tui-footer-chrome-v1.json +42 -0
  187. package/src/providers/sdk/v1/schemas/primitives/tui-index-finder-v1.json +27 -0
  188. package/src/providers/sdk/v1/schemas/primitives/tui-modal-v1.json +125 -0
  189. package/src/providers/sdk/v1/schemas/primitives/tui-prompt-marker-v1.json +45 -0
  190. package/src/providers/sdk/v1/schemas/primitives/tui-session-id-extraction-v1.json +46 -0
  191. package/src/providers/sdk/v1/schemas/primitives/tui-settled-prompt-v1.json +71 -0
  192. package/src/providers/sdk/v1/schemas/primitives/tui-spinner-v1.json +83 -0
  193. package/src/providers/sdk/v1/schemas/primitives/tui-transcript-pty-v1.json +83 -0
  194. package/src/providers/sdk/v1/schemas/primitives/tui-visible-region-v1.json +57 -0
  195. package/src/providers/sdk/v1/schemas/primitives/tui-welcome-screen-v1.json +35 -0
  196. package/src/providers/sdk/v1/types/cli/index.ts +365 -0
  197. package/src/providers/sdk/v1/types/common/index.ts +210 -0
  198. package/src/providers/sdk/v1/validators/index.ts +19 -0
  199. package/src/providers/sdk/v1/validators/manifest.ts +110 -0
  200. package/src/providers/sdk/v1/validators/taint.ts +309 -0
  201. package/src/providers/spec/adapter.ts +168 -0
  202. package/src/providers/spec/cli-adapter.ts +430 -0
  203. package/src/providers/spec/driver.ts +502 -0
  204. package/src/providers/spec/evaluator.ts +298 -0
  205. package/src/providers/spec/loader.ts +130 -0
  206. package/src/providers/spec/native-history-executor.ts +623 -0
  207. package/src/providers/spec/route.ts +51 -0
  208. package/src/providers/spec/schema.gen.ts +511 -0
  209. package/src/providers/spec/schema.json +211 -0
  210. package/src/providers/spec/types.ts +231 -0
  211. package/src/providers/transcript-v2.ts +567 -0
  212. package/src/providers/types/interactive-prompt.ts +297 -0
  213. package/src/providers/version-archive.ts +38 -20
  214. package/src/repo-mesh-types.ts +110 -1
  215. package/src/sessions/registry.ts +3 -0
  216. package/src/shared-types.ts +45 -1
  217. package/src/status/builders.ts +24 -6
  218. package/src/status/reporter.ts +15 -0
  219. package/src/status/snapshot.ts +84 -25
  220. package/src/system/host-memory.ts +29 -12
  221. package/src/types.ts +5 -0
@@ -0,0 +1,297 @@
1
+ export interface InteractivePrompt {
2
+ promptId: string;
3
+ origin: 'cli' | 'mcp' | 'agent';
4
+ providerType: string;
5
+ createdAt: number;
6
+ questions: InteractiveQuestion[];
7
+ }
8
+
9
+ export interface InteractiveQuestion {
10
+ questionId: string;
11
+ question: string;
12
+ header?: string;
13
+ multiSelect: boolean;
14
+ options: InteractiveOption[];
15
+ allowFreeform?: boolean;
16
+ }
17
+
18
+ export interface InteractiveOption {
19
+ label: string;
20
+ description?: string;
21
+ preview?: string;
22
+ }
23
+
24
+ export interface InteractivePromptResponse {
25
+ promptId: string;
26
+ answers: Record<string, InteractiveAnswer>;
27
+ }
28
+
29
+ export interface InteractiveAnswer {
30
+ selectedLabels: string[];
31
+ freeformText?: string;
32
+ }
33
+
34
+ function readString(value: unknown): string | undefined {
35
+ return typeof value === 'string' && value.trim() ? value.trim() : undefined;
36
+ }
37
+
38
+ function readStringArray(value: unknown): string[] {
39
+ return Array.isArray(value)
40
+ ? value.map((item) => readString(item)).filter((item): item is string => !!item)
41
+ : [];
42
+ }
43
+
44
+ function normalizeOption(raw: unknown): InteractiveOption | null {
45
+ if (typeof raw === 'string') {
46
+ const label = raw.trim();
47
+ return label ? { label } : null;
48
+ }
49
+ if (!raw || typeof raw !== 'object') return null;
50
+ const record = raw as Record<string, unknown>;
51
+ const label = readString(record.label);
52
+ if (!label) return null;
53
+ const description = readString(record.description);
54
+ const preview = readString(record.preview);
55
+ return {
56
+ label,
57
+ ...(description ? { description } : {}),
58
+ ...(preview ? { preview } : {}),
59
+ };
60
+ }
61
+
62
+ function normalizeQuestion(raw: unknown, index: number): InteractiveQuestion | null {
63
+ if (!raw || typeof raw !== 'object') return null;
64
+ const record = raw as Record<string, unknown>;
65
+ const question = readString(record.question);
66
+ if (!question) return null;
67
+ const questionId = readString(record.questionId) || readString(record.id) || `q${index + 1}`;
68
+ const options = Array.isArray(record.options)
69
+ ? record.options.map(normalizeOption).filter((item): item is InteractiveOption => !!item)
70
+ : [];
71
+ const header = readString(record.header);
72
+ return {
73
+ questionId,
74
+ question,
75
+ ...(header ? { header } : {}),
76
+ multiSelect: record.multiSelect === true,
77
+ options,
78
+ ...(record.allowFreeform === true ? { allowFreeform: true } : {}),
79
+ };
80
+ }
81
+
82
+ export function normalizeInteractivePrompt(raw: unknown): InteractivePrompt | null {
83
+ if (!raw || typeof raw !== 'object') return null;
84
+ const record = raw as Record<string, unknown>;
85
+ const promptId = readString(record.promptId);
86
+ const providerType = readString(record.providerType);
87
+ const origin = record.origin === 'mcp' || record.origin === 'agent' ? record.origin : 'cli';
88
+ const questions = Array.isArray(record.questions)
89
+ ? record.questions.map(normalizeQuestion).filter((item): item is InteractiveQuestion => !!item)
90
+ : [];
91
+ if (!promptId || !providerType || questions.length === 0) return null;
92
+ const createdAt = typeof record.createdAt === 'number' && Number.isFinite(record.createdAt)
93
+ ? record.createdAt
94
+ : Date.now();
95
+ return { promptId, origin, providerType, createdAt, questions };
96
+ }
97
+
98
+ export function normalizeInteractivePromptResponse(raw: unknown): InteractivePromptResponse {
99
+ if (!raw || typeof raw !== 'object') throw new Error('Interactive prompt response must be an object');
100
+ const record = raw as Record<string, unknown>;
101
+ const promptId = readString(record.promptId);
102
+ if (!promptId) throw new Error('promptId must be a non-empty string');
103
+ if (!record.answers || typeof record.answers !== 'object' || Array.isArray(record.answers)) {
104
+ throw new Error('answers must be an object');
105
+ }
106
+ const answers: Record<string, InteractiveAnswer> = {};
107
+ for (const [questionId, answerRaw] of Object.entries(record.answers as Record<string, unknown>)) {
108
+ if (!answerRaw || typeof answerRaw !== 'object' || Array.isArray(answerRaw)) continue;
109
+ const answer = answerRaw as Record<string, unknown>;
110
+ const selectedLabels = readStringArray(answer.selectedLabels);
111
+ const freeformText = readString(answer.freeformText);
112
+ answers[questionId] = {
113
+ selectedLabels,
114
+ ...(freeformText ? { freeformText } : {}),
115
+ };
116
+ }
117
+ return { promptId, answers };
118
+ }
119
+
120
+ export function buildClaudeInteractiveToolResult(response: InteractivePromptResponse): string {
121
+ return JSON.stringify({
122
+ type: 'user',
123
+ message: {
124
+ role: 'user',
125
+ content: [{
126
+ type: 'tool_result',
127
+ tool_use_id: response.promptId,
128
+ content: JSON.stringify({ answers: response.answers }),
129
+ is_error: false,
130
+ }],
131
+ },
132
+ });
133
+ }
134
+
135
+ export interface ClaudeInteractiveTuiPage {
136
+ screenText: string;
137
+ header?: string;
138
+ }
139
+
140
+ function claudeTuiQuestionHeaders(screenText: string): string[] {
141
+ const navLine = screenText.split(/\r?\n/).find(line => line.includes('✔ Submit') && /[☐☒]/.test(line));
142
+ if (!navLine) return [];
143
+ const headers: string[] = [];
144
+ const pattern = /[☐☒]\s+(.+?)(?=\s+[☐☒]|\s+✔\s+Submit)/g;
145
+ for (const match of navLine.matchAll(pattern)) {
146
+ const header = readString(match[1]);
147
+ if (header) headers.push(header);
148
+ }
149
+ return headers;
150
+ }
151
+
152
+ function parseClaudeInteractiveTuiQuestion(page: ClaudeInteractiveTuiPage, index: number): InteractiveQuestion | null {
153
+ const lines = page.screenText.split(/\r?\n/);
154
+ let navIndex = -1;
155
+ for (let i = lines.length - 1; i >= 0; i -= 1) {
156
+ if (lines[i].includes('✔ Submit') && /[☐☒]/.test(lines[i])) {
157
+ navIndex = i;
158
+ break;
159
+ }
160
+ }
161
+ if (navIndex < 0 || !page.screenText.includes('Enter to select')) return null;
162
+
163
+ let question = '';
164
+ let questionLineIndex = -1;
165
+ for (let i = navIndex + 1; i < lines.length; i += 1) {
166
+ const candidate = lines[i].trim();
167
+ if (!candidate || /^─+$/.test(candidate)) continue;
168
+ if (candidate === 'Review your answers' || candidate === 'Ready to submit your answers?') return null;
169
+ question = candidate;
170
+ questionLineIndex = i;
171
+ break;
172
+ }
173
+ if (!question) return null;
174
+
175
+ const options: InteractiveOption[] = [];
176
+ let allowFreeform = false;
177
+ const optionPattern = /^\s*(?:[❯›>]\s*)?(\d+)\.\s+(.+?)\s*$/;
178
+ for (let i = questionLineIndex + 1; i < lines.length; i += 1) {
179
+ const match = lines[i].match(optionPattern);
180
+ if (!match) continue;
181
+ const label = match[2].trim();
182
+ if (/^Type something\.?$/i.test(label)) {
183
+ allowFreeform = true;
184
+ continue;
185
+ }
186
+ if (/^Chat about this$/i.test(label)) continue;
187
+
188
+ let description: string | undefined;
189
+ const nextLine = lines[i + 1]?.trim();
190
+ if (nextLine
191
+ && !optionPattern.test(lines[i + 1])
192
+ && !/^─+$/.test(nextLine)
193
+ && !/^Enter to select\b/.test(nextLine)) {
194
+ description = nextLine;
195
+ }
196
+ options.push({ label, ...(description ? { description } : {}) });
197
+ }
198
+ if (options.length === 0) return null;
199
+
200
+ const header = readString(page.header);
201
+ return {
202
+ questionId: `q${index + 1}`,
203
+ question,
204
+ ...(header ? { header } : {}),
205
+ multiSelect: /Space to select|toggle selections/i.test(page.screenText),
206
+ options,
207
+ ...(allowFreeform ? { allowFreeform: true } : {}),
208
+ };
209
+ }
210
+
211
+ export function detectClaudeAskUserQuestionPromptFromTuiPages(
212
+ pages: ClaudeInteractiveTuiPage[],
213
+ options: { promptId: string; providerType?: string; createdAt?: number },
214
+ ): InteractivePrompt | null {
215
+ if (pages.length === 0) return null;
216
+ const headers = claudeTuiQuestionHeaders(pages[0].screenText);
217
+ const questions = pages.map((page, index) => parseClaudeInteractiveTuiQuestion({
218
+ ...page,
219
+ header: page.header || headers[index],
220
+ }, index)).filter((question): question is InteractiveQuestion => !!question);
221
+ if (questions.length !== pages.length) return null;
222
+ return {
223
+ promptId: options.promptId,
224
+ origin: 'cli',
225
+ providerType: options.providerType || 'claude-cli',
226
+ createdAt: options.createdAt || Date.now(),
227
+ questions,
228
+ };
229
+ }
230
+
231
+ export function buildClaudeInteractiveTuiAnswerSteps(
232
+ prompt: InteractivePrompt,
233
+ response: InteractivePromptResponse,
234
+ ): string[] {
235
+ if (response.promptId !== prompt.promptId) throw new Error('Interactive prompt response does not match active prompt');
236
+ const steps: string[] = [];
237
+ for (const question of prompt.questions) {
238
+ if (question.multiSelect) throw new Error('Claude TUI multi-select prompts are not supported yet');
239
+ const answer = response.answers[question.questionId];
240
+ if (!answer) throw new Error(`Missing answer for ${question.questionId}`);
241
+ if (answer.freeformText) throw new Error('Claude TUI freeform answers are not supported yet');
242
+ if (answer.selectedLabels.length !== 1) throw new Error(`Expected one selected label for ${question.questionId}`);
243
+ const selectedIndex = question.options.findIndex(option => option.label === answer.selectedLabels[0]);
244
+ if (selectedIndex < 0) throw new Error(`Unknown option for ${question.questionId}: ${answer.selectedLabels[0]}`);
245
+ steps.push(`${'\x1b[B'.repeat(selectedIndex)}\r`);
246
+ }
247
+ steps.push('\r');
248
+ return steps;
249
+ }
250
+
251
+ export function interactivePromptFromClaudeAskUserQuestion(input: unknown, options: {
252
+ promptId: string;
253
+ providerType: string;
254
+ createdAt?: number;
255
+ origin?: InteractivePrompt['origin'];
256
+ }): InteractivePrompt | null {
257
+ if (!input || typeof input !== 'object') return null;
258
+ const record = input as Record<string, unknown>;
259
+ const questions = Array.isArray(record.questions)
260
+ ? record.questions.map(normalizeQuestion).filter((item): item is InteractiveQuestion => !!item)
261
+ : [];
262
+ if (questions.length === 0) return null;
263
+ return {
264
+ promptId: options.promptId,
265
+ origin: options.origin || 'cli',
266
+ providerType: options.providerType,
267
+ createdAt: options.createdAt || Date.now(),
268
+ questions,
269
+ };
270
+ }
271
+
272
+ export function detectClaudeAskUserQuestionPromptFromJson(value: unknown, providerType = 'claude-cli'): InteractivePrompt | null {
273
+ if (!value || typeof value !== 'object') return null;
274
+ const record = value as Record<string, unknown>;
275
+ const blocks: unknown[] = [];
276
+ if (Array.isArray(record.content)) blocks.push(...record.content);
277
+ const message = record.message;
278
+ if (message && typeof message === 'object' && Array.isArray((message as Record<string, unknown>).content)) {
279
+ blocks.push(...((message as Record<string, unknown>).content as unknown[]));
280
+ }
281
+ if (record.type === 'tool_use') blocks.push(record);
282
+
283
+ for (const block of blocks) {
284
+ if (!block || typeof block !== 'object') continue;
285
+ const b = block as Record<string, unknown>;
286
+ const name = readString(b.name);
287
+ if (b.type !== 'tool_use' || name !== 'AskUserQuestion') continue;
288
+ const id = readString(b.id) || readString(record.id) || `ask-user-${Date.now()}`;
289
+ const prompt = interactivePromptFromClaudeAskUserQuestion(b.input, {
290
+ promptId: id,
291
+ providerType,
292
+ origin: 'cli',
293
+ });
294
+ if (prompt) return prompt;
295
+ }
296
+ return null;
297
+ }
@@ -12,7 +12,7 @@
12
12
  import * as fs from 'fs';
13
13
  import * as path from 'path';
14
14
  import * as os from 'os';
15
- import { execSync } from 'child_process';
15
+ // Removed execSync import
16
16
  import { platform } from 'os';
17
17
  import type { ProviderLoader } from './provider-loader.js';
18
18
  import type { ProviderModule } from './contracts.js';
@@ -117,22 +117,40 @@ export class VersionArchive {
117
117
 
118
118
  // ─── Version Detection ──────────────────────────────
119
119
 
120
- function runCommand(cmd: string, timeout = 10000): string | null {
121
- try {
122
- return execSync(cmd, {
120
+ import { exec } from 'child_process';
121
+
122
+ async function runCommand(cmd: string, timeout = 10000): Promise<string | null> {
123
+ return new Promise((resolve) => {
124
+ exec(cmd, {
123
125
  encoding: 'utf-8',
124
126
  timeout,
125
- stdio: ['pipe', 'pipe', 'pipe'],
126
- }).trim();
127
- } catch {
128
- return null;
129
- }
127
+ }, (error, stdout) => {
128
+ if (error) return resolve(null);
129
+ resolve(stdout.trim());
130
+ });
131
+ });
130
132
  }
131
133
 
132
134
  function findBinary(name: string): string | null {
133
- const cmd = platform() === 'win32' ? `where ${name}` : `which ${name}`;
134
- const result = runCommand(cmd, 5000);
135
- return result ? result.split('\n')[0] : null;
135
+ const isWin = platform() === 'win32';
136
+ const paths = (process.env.PATH || '').split(isWin ? ';' : ':');
137
+ const exes = isWin ? ['.exe', '.cmd', '.bat', ''] : [''];
138
+
139
+ for (const p of paths) {
140
+ if (!p) continue;
141
+ for (const ext of exes) {
142
+ const fullPath = path.join(p, name + ext);
143
+ try {
144
+ if (fs.existsSync(fullPath)) {
145
+ const stat = fs.statSync(fullPath);
146
+ if (stat.isFile() && (isWin || (stat.mode & 0o111))) {
147
+ return fullPath;
148
+ }
149
+ }
150
+ } catch { }
151
+ }
152
+ }
153
+ return null;
136
154
  }
137
155
 
138
156
  /** Extract version string from CLI output */
@@ -162,16 +180,16 @@ function getPlatformVersionCommand(
162
180
  return undefined;
163
181
  }
164
182
 
165
- function getVersion(binary: string, versionCommand?: string): string | null {
183
+ async function getVersion(binary: string, versionCommand?: string): Promise<string | null> {
166
184
  // Custom version command from provider.json
167
185
  if (versionCommand) {
168
- const raw = runCommand(versionCommand);
186
+ const raw = await runCommand(versionCommand);
169
187
  return raw ? parseVersion(raw) : null;
170
188
  }
171
189
 
172
190
  // Default: try --version, then -V, then -v
173
191
  for (const flag of ['--version', '-V', '-v']) {
174
- const raw = runCommand(`"${binary}" ${flag}`);
192
+ const raw = await runCommand(`"${binary}" ${flag}`);
175
193
  if (raw && raw.length < 500) return parseVersion(raw);
176
194
  }
177
195
  return null;
@@ -191,11 +209,11 @@ function checkPathExists(paths: string[]): string | null {
191
209
  }
192
210
 
193
211
  /** macOS: Get app version from Info.plist */
194
- function getMacAppVersion(appPath: string): string | null {
212
+ async function getMacAppVersion(appPath: string): Promise<string | null> {
195
213
  if (platform() !== 'darwin' || !appPath.endsWith('.app')) return null;
196
214
  const plistPath = path.join(appPath, 'Contents', 'Info.plist');
197
215
  if (!fs.existsSync(plistPath)) return null;
198
- const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
216
+ const raw = await runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
199
217
  return raw || null;
200
218
  }
201
219
 
@@ -242,10 +260,10 @@ export async function detectAllVersions(
242
260
 
243
261
  // Version: try CLI first, then plist
244
262
  if (resolvedBin) {
245
- info.version = getVersion(resolvedBin, versionCommand);
263
+ info.version = await getVersion(resolvedBin, versionCommand);
246
264
  }
247
265
  if (!info.version && appPath) {
248
- info.version = getMacAppVersion(appPath);
266
+ info.version = await getMacAppVersion(appPath);
249
267
  }
250
268
 
251
269
  } else if (provider.category === 'cli' || provider.category === 'acp') {
@@ -256,7 +274,7 @@ export async function detectAllVersions(
256
274
  info.binary = binPath || null;
257
275
 
258
276
  if (binPath) {
259
- info.version = getVersion(binPath, versionCommand);
277
+ info.version = await getVersion(binPath, versionCommand);
260
278
  }
261
279
 
262
280
  } else if (provider.category === 'extension') {
@@ -23,11 +23,42 @@ export interface RepoMesh {
23
23
  defaultBranch?: string;
24
24
  policy: RepoMeshPolicy;
25
25
  coordinator: RepoMeshCoordinatorConfig;
26
+ meshHost?: RepoMeshHostMetadata;
26
27
  projectContext: ProjectContextSnapshot;
27
28
  nodes: RepoMeshNode[];
28
29
  status: 'active' | 'archived' | 'deleted';
29
30
  }
30
31
 
32
+ export type RepoMeshDaemonRole = 'host' | 'member';
33
+
34
+ export interface RepoMeshHostPairingMetadata {
35
+ status: 'not_configured' | 'pairing' | 'paired' | 'rejected' | 'revoked';
36
+ tokenId?: string;
37
+ joinedAt?: string;
38
+ lastPairedAt?: string;
39
+ lastRejectedAt?: string;
40
+ expiresAt?: string;
41
+ }
42
+
43
+ export interface RepoMeshHostMetadata {
44
+ /** Local daemon role for this mesh. Missing metadata defaults to host for standalone compatibility. */
45
+ role: RepoMeshDaemonRole;
46
+ /** Daemon that owns mesh truth/status/git/queue/session/ledger/coordinator ownership. */
47
+ hostDaemonId?: string;
48
+ /** Mesh node that represents the host daemon, when known. */
49
+ hostNodeId?: string;
50
+ /** Future standalone manual pairing endpoint entered by member daemons. */
51
+ hostAddress?: string;
52
+ /** Redacted pairing state only; raw join tokens must not be persisted here. */
53
+ pairing?: RepoMeshHostPairingMetadata;
54
+ }
55
+
56
+ export interface RepoMeshHostStatus extends RepoMeshHostMetadata {
57
+ canOwnCoordinator: boolean;
58
+ canOwnQueue: boolean;
59
+ defaulted: boolean;
60
+ }
61
+
31
62
  export interface RepoMeshNode {
32
63
  id: string;
33
64
  daemonId: string;
@@ -42,6 +73,7 @@ export interface RepoMeshNode {
42
73
  effectiveCapabilities: RepoMeshNodeCapabilities;
43
74
  policy: RepoMeshNodePolicy;
44
75
  health: RepoMeshNodeHealth;
76
+ role?: RepoMeshDaemonRole;
45
77
  status: 'enabled' | 'disabled' | 'removed';
46
78
  }
47
79
 
@@ -62,6 +94,13 @@ export interface RepoMeshPolicy {
62
94
  requirePreTaskCheckpoint: boolean;
63
95
  requirePostTaskCheckpoint: boolean;
64
96
  requireApprovalForPush: boolean;
97
+ /**
98
+ * Narrow Refinery opt-in: when validation and patch-equivalence have passed,
99
+ * allow Refinery to publish submodule gitlink commits to each submodule's
100
+ * configured remote main branch with a non-force push, then verify reachability.
101
+ * Defaults to false; root branch pushes/merges are not affected.
102
+ */
103
+ allowAutoPublishSubmoduleMainCommits?: boolean;
65
104
  requireApprovalForDestructiveGit: boolean;
66
105
  dirtyWorkspaceBehavior: 'block' | 'warn' | 'checkpoint_then_continue';
67
106
  maxParallelTasks: number;
@@ -126,6 +165,7 @@ export const DEFAULT_MESH_POLICY: RepoMeshPolicy = {
126
165
  requirePreTaskCheckpoint: false,
127
166
  requirePostTaskCheckpoint: true,
128
167
  requireApprovalForPush: true,
168
+ allowAutoPublishSubmoduleMainCommits: false,
129
169
  requireApprovalForDestructiveGit: true,
130
170
  dirtyWorkspaceBehavior: 'warn',
131
171
  maxParallelTasks: 2,
@@ -207,7 +247,28 @@ export interface RepoMeshCoordinatorConfig {
207
247
  providerType?: string;
208
248
  /** Preferred node to run coordinator on (null = auto) */
209
249
  preferredNodeId?: string;
210
- /** Additional system prompt context for coordinator */
250
+ /**
251
+ * Full mesh-level override for the coordinator system prompt. When set,
252
+ * replaces the daemon's rendered default and any user-file override
253
+ * (~/.adhdev/coordinator-prompts/<cli>.md). The per-launch
254
+ * extraSystemPrompt still composes on top — it always lands last as
255
+ * Additional Context. Supports the same {{placeholders}} the daemon's
256
+ * default template uses ({{meshName}}, {{repo}}, {{nodes}}, …).
257
+ */
258
+ systemPromptOverride?: string;
259
+ /**
260
+ * Mesh-level append. Composes after whichever base prompt won
261
+ * (override → user-file override → daemon default). Use this when you
262
+ * want extra rules for THIS mesh but otherwise the standard prompt is
263
+ * fine. Stacks with the user-file append (`<cli>.append.md`) — both
264
+ * apply if both are set.
265
+ */
266
+ systemPromptAppend?: string;
267
+ /**
268
+ * @deprecated Use systemPromptAppend. Kept as a fallback alias so
269
+ * existing meshes.json files keep working without a migration step;
270
+ * the daemon prefers systemPromptAppend when both are present.
271
+ */
211
272
  systemPromptSuffix?: string;
212
273
  }
213
274
 
@@ -229,6 +290,7 @@ export interface LocalMeshEntry {
229
290
  defaultBranch?: string;
230
291
  policy: RepoMeshPolicy;
231
292
  coordinator: RepoMeshCoordinatorConfig;
293
+ meshHost?: RepoMeshHostMetadata;
232
294
  nodes: LocalMeshNodeEntry[];
233
295
  createdAt: string;
234
296
  updatedAt: string;
@@ -243,14 +305,38 @@ export interface LocalMeshNodeEntry {
243
305
  machineId?: string;
244
306
  userOverrides: Partial<RepoMeshNodeCapabilities>;
245
307
  policy: RepoMeshNodePolicy;
308
+ /**
309
+ * Per-node instruction surfaced in the coordinator prompt so the LLM
310
+ * knows what each node is for (e.g. "this is the staging mirror — run
311
+ * only smoke tests here", or "use opus on this node, sonnet elsewhere").
312
+ * Empty/missing: omitted silently from the rendered prompt, no rule
313
+ * line about it gets added. The coordinator forwards/honors it when
314
+ * delegating; we don't enforce it at the daemon level.
315
+ */
316
+ systemPrompt?: string;
246
317
  /** For single-machine mesh: same daemon, different worktree */
247
318
  isLocalWorktree?: boolean;
248
319
  /** Branch this worktree tracks (set when created via clone_mesh_node) */
249
320
  worktreeBranch?: string;
250
321
  /** Node ID this worktree was cloned from */
251
322
  clonedFromNodeId?: string;
323
+ /** Repo-local preparation result for ADHDev-created worktree nodes. */
324
+ worktreeBootstrap?: {
325
+ status: 'ready' | 'running' | 'failed' | 'not_configured' | 'disabled' | 'stale';
326
+ required?: boolean;
327
+ configSource?: string;
328
+ configSourceType?: string;
329
+ startedAt?: string;
330
+ completedAt?: string;
331
+ lastCommand?: string;
332
+ exitCode?: number | null;
333
+ error?: string;
334
+ commandsRun?: Array<Record<string, unknown>>;
335
+ staleInputs?: string[];
336
+ };
252
337
  /** Optional associated/external repos configured as node metadata. */
253
338
  relatedRepos?: RepoMeshRelatedRepo[];
339
+ role?: RepoMeshDaemonRole;
254
340
  }
255
341
 
256
342
  // ─── Mesh Status (runtime, not persisted) ───────
@@ -261,6 +347,7 @@ export interface RepoMeshStatus {
261
347
  repoIdentity: string;
262
348
  defaultBranch?: string;
263
349
  refreshedAt: string;
350
+ meshHost?: RepoMeshHostStatus;
264
351
  nodes: RepoMeshNodeStatus[];
265
352
  queue?: RepoMeshQueueStatus;
266
353
  ledger?: RepoMeshLedgerStatus;
@@ -301,16 +388,28 @@ export interface RepoMeshNodeStatus {
301
388
  repoRoot?: string;
302
389
  daemonId?: string;
303
390
  machineId?: string;
391
+ role?: RepoMeshDaemonRole;
304
392
  machineStatus?: string;
305
393
  isLocalWorktree?: boolean;
306
394
  worktreeBranch?: string;
395
+ /** Mirrored from LocalMeshNodeEntry.systemPrompt for coordinator-prompt rendering. */
396
+ systemPrompt?: string;
307
397
  health: RepoMeshNodeHealth;
308
398
  git?: GitRepoStatus;
399
+ /**
400
+ * True when the selected coordinator has evidence that a peer git probe is still
401
+ * in flight or just timed out during initial mesh handshake, so callers should
402
+ * treat missing git data as pending instead of authoritative absence.
403
+ */
404
+ gitProbePending?: boolean;
309
405
  providers: string[];
310
406
  activeSessions: string[];
311
407
  activeSessionDetails?: RepoMeshSessionStatus[];
312
408
  providerPriority?: string[];
313
409
  launchReady?: boolean;
410
+ worktreeBootstrap?: LocalMeshNodeEntry['worktreeBootstrap'];
411
+ launchBlockedReason?: string;
412
+ launchBlockedMessage?: string;
314
413
  lastSeenAt?: string;
315
414
  updatedAt?: string;
316
415
  connection?: RepoMeshPeerConnectionStatus;
@@ -405,3 +504,13 @@ export interface RepoMeshLedgerStatus {
405
504
  entries: RepoMeshLedgerEntryStatus[];
406
505
  summary: RepoMeshLedgerSummaryStatus;
407
506
  }
507
+
508
+ // ─── Async Job Lifecycle ─────────────────────────
509
+ // Shared base for all mesh async job types (refine jobs, bootstrap runs, etc.)
510
+ // Each concrete type adds its own status enum and domain-specific fields.
511
+
512
+ export interface MeshAsyncJobLifecycle {
513
+ startedAt?: string;
514
+ completedAt?: string;
515
+ error?: string;
516
+ }
@@ -8,6 +8,9 @@ export interface SessionRuntimeTarget {
8
8
  cdpManagerKey?: string;
9
9
  adapterKey?: string;
10
10
  instanceKey?: string;
11
+ /** Wall clock at register time. native-history readers use it as a
12
+ * cutoff so a fresh session can't show records from a prior one. */
13
+ spawnedAtMs?: number;
11
14
  }
12
15
 
13
16
  export class SessionRegistry {