@synap-core/cli 1.13.0 → 1.13.1-next.20261102.3a66eb1

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 (227) hide show
  1. package/README.md +13 -3
  2. package/dist/build-info.json +2 -3
  3. package/dist/commands/agents.js +12 -2
  4. package/dist/commands/agents.js.map +1 -1
  5. package/dist/commands/capability.d.ts +86 -0
  6. package/dist/commands/capability.js +117 -30
  7. package/dist/commands/capability.js.map +1 -1
  8. package/dist/commands/context.js +2 -1
  9. package/dist/commands/context.js.map +1 -1
  10. package/dist/commands/data-extra.d.ts +13 -0
  11. package/dist/commands/data-extra.js +23 -2
  12. package/dist/commands/data-extra.js.map +1 -1
  13. package/dist/commands/doctor.d.ts +18 -0
  14. package/dist/commands/doctor.js +28 -1
  15. package/dist/commands/doctor.js.map +1 -1
  16. package/dist/commands/init.js +4 -2
  17. package/dist/commands/init.js.map +1 -1
  18. package/dist/commands/keys-request.d.ts +48 -0
  19. package/dist/commands/keys-request.js +236 -0
  20. package/dist/commands/keys-request.js.map +1 -0
  21. package/dist/commands/keys-request.test.d.ts +1 -0
  22. package/dist/commands/keys-request.test.js +176 -0
  23. package/dist/commands/keys-request.test.js.map +1 -0
  24. package/dist/commands/knowledge.d.ts +42 -5
  25. package/dist/commands/knowledge.js +90 -27
  26. package/dist/commands/knowledge.js.map +1 -1
  27. package/dist/commands/market.d.ts +89 -31
  28. package/dist/commands/market.js +215 -222
  29. package/dist/commands/market.js.map +1 -1
  30. package/dist/commands/mcp.d.ts +1 -1
  31. package/dist/commands/mcp.js +14 -9
  32. package/dist/commands/mcp.js.map +1 -1
  33. package/dist/commands/pods.js +6 -2
  34. package/dist/commands/pods.js.map +1 -1
  35. package/dist/commands/proposals-actions.js +7 -1
  36. package/dist/commands/proposals-actions.js.map +1 -1
  37. package/dist/commands/providers.d.ts +22 -6
  38. package/dist/commands/providers.js +39 -32
  39. package/dist/commands/providers.js.map +1 -1
  40. package/dist/commands/raycast.d.ts +15 -0
  41. package/dist/commands/raycast.js +36 -10
  42. package/dist/commands/raycast.js.map +1 -1
  43. package/dist/commands/status.js +12 -6
  44. package/dist/commands/status.js.map +1 -1
  45. package/dist/commands/statusline.backoff.test.js +13 -3
  46. package/dist/commands/statusline.backoff.test.js.map +1 -1
  47. package/dist/commands/statusline.d.ts +104 -9
  48. package/dist/commands/statusline.js +392 -148
  49. package/dist/commands/statusline.js.map +1 -1
  50. package/dist/commands/statusline.line2.test.d.ts +15 -0
  51. package/dist/commands/statusline.line2.test.js +226 -0
  52. package/dist/commands/statusline.line2.test.js.map +1 -0
  53. package/dist/commands/statusline.needs-you.test.d.ts +1 -0
  54. package/dist/commands/statusline.needs-you.test.js +17 -0
  55. package/dist/commands/statusline.needs-you.test.js.map +1 -0
  56. package/dist/commands/statusline.now.test.d.ts +10 -0
  57. package/dist/commands/statusline.now.test.js +250 -0
  58. package/dist/commands/statusline.now.test.js.map +1 -0
  59. package/dist/commands/tracks.d.ts +1 -0
  60. package/dist/commands/tracks.js +4 -0
  61. package/dist/commands/tracks.js.map +1 -1
  62. package/dist/commands/upload.js +12 -0
  63. package/dist/commands/upload.js.map +1 -1
  64. package/dist/commands/wait.d.ts +124 -0
  65. package/dist/commands/wait.js +384 -0
  66. package/dist/commands/wait.js.map +1 -0
  67. package/dist/commands/wait.test.d.ts +8 -0
  68. package/dist/commands/wait.test.js +308 -0
  69. package/dist/commands/wait.test.js.map +1 -0
  70. package/dist/commands/worker-github-app.d.ts +63 -0
  71. package/dist/commands/worker-github-app.js +161 -0
  72. package/dist/commands/worker-github-app.js.map +1 -0
  73. package/dist/commands/worker-github-app.test.d.ts +1 -0
  74. package/dist/commands/worker-github-app.test.js +102 -0
  75. package/dist/commands/worker-github-app.test.js.map +1 -0
  76. package/dist/commands/worker-github-broker.d.ts +39 -0
  77. package/dist/commands/worker-github-broker.js +106 -0
  78. package/dist/commands/worker-github-broker.js.map +1 -0
  79. package/dist/commands/worker-github-broker.test.d.ts +1 -0
  80. package/dist/commands/worker-github-broker.test.js +90 -0
  81. package/dist/commands/worker-github-broker.test.js.map +1 -0
  82. package/dist/commands/worker-runs.test.d.ts +1 -0
  83. package/dist/commands/worker-runs.test.js +150 -0
  84. package/dist/commands/worker-runs.test.js.map +1 -0
  85. package/dist/commands/worker-worktrees.d.ts +34 -0
  86. package/dist/commands/worker-worktrees.js +87 -0
  87. package/dist/commands/worker-worktrees.js.map +1 -0
  88. package/dist/commands/worker.d.ts +207 -5
  89. package/dist/commands/worker.js +540 -46
  90. package/dist/commands/worker.js.map +1 -1
  91. package/dist/commands/worker.test.js +269 -3
  92. package/dist/commands/worker.test.js.map +1 -1
  93. package/dist/index.js +60 -4
  94. package/dist/index.js.map +1 -1
  95. package/dist/lib/agents-config.d.ts +9 -0
  96. package/dist/lib/agents-config.js +20 -0
  97. package/dist/lib/agents-config.js.map +1 -1
  98. package/dist/lib/atomic-file.d.ts +20 -1
  99. package/dist/lib/atomic-file.js +100 -2
  100. package/dist/lib/atomic-file.js.map +1 -1
  101. package/dist/lib/auth.d.ts +25 -0
  102. package/dist/lib/auth.js +49 -9
  103. package/dist/lib/auth.js.map +1 -1
  104. package/dist/lib/box/job-server.js +4 -0
  105. package/dist/lib/box/job-server.js.map +1 -1
  106. package/dist/lib/bridge-invocation.test.d.ts +1 -0
  107. package/dist/lib/bridge-invocation.test.js +75 -0
  108. package/dist/lib/bridge-invocation.test.js.map +1 -0
  109. package/dist/lib/bridge-status.d.ts +144 -0
  110. package/dist/lib/bridge-status.js +227 -0
  111. package/dist/lib/bridge-status.js.map +1 -0
  112. package/dist/lib/bridge-status.test.d.ts +6 -0
  113. package/dist/lib/bridge-status.test.js +197 -0
  114. package/dist/lib/bridge-status.test.js.map +1 -0
  115. package/dist/lib/client-header.test.js +19 -1
  116. package/dist/lib/client-header.test.js.map +1 -1
  117. package/dist/lib/conversation-headers.d.ts +67 -2
  118. package/dist/lib/conversation-headers.js +122 -6
  119. package/dist/lib/conversation-headers.js.map +1 -1
  120. package/dist/lib/conversation-headers.test.d.ts +1 -0
  121. package/dist/lib/conversation-headers.test.js +78 -0
  122. package/dist/lib/conversation-headers.test.js.map +1 -0
  123. package/dist/lib/credential-class.d.ts +12 -1
  124. package/dist/lib/credential-class.js +20 -0
  125. package/dist/lib/credential-class.js.map +1 -1
  126. package/dist/lib/device-connect.d.ts +45 -0
  127. package/dist/lib/device-connect.js +60 -0
  128. package/dist/lib/device-connect.js.map +1 -1
  129. package/dist/lib/goal-words.js +6 -3
  130. package/dist/lib/goal-words.js.map +1 -1
  131. package/dist/lib/hub-client.d.ts +59 -1
  132. package/dist/lib/hub-client.js +130 -36
  133. package/dist/lib/hub-client.js.map +1 -1
  134. package/dist/lib/key-locations.d.ts +3 -3
  135. package/dist/lib/key-locations.js +3 -39
  136. package/dist/lib/key-locations.js.map +1 -1
  137. package/dist/lib/machine-instance.d.ts +7 -5
  138. package/dist/lib/machine-instance.js +7 -5
  139. package/dist/lib/machine-instance.js.map +1 -1
  140. package/dist/lib/mcp-bridge.d.ts +43 -0
  141. package/dist/lib/mcp-bridge.js +199 -11
  142. package/dist/lib/mcp-bridge.js.map +1 -1
  143. package/dist/lib/mcp-bridge.test.js +194 -2
  144. package/dist/lib/mcp-bridge.test.js.map +1 -1
  145. package/dist/lib/mcp-call.d.ts +5 -1
  146. package/dist/lib/mcp-call.js +7 -6
  147. package/dist/lib/mcp-call.js.map +1 -1
  148. package/dist/lib/mcp-connector-url.test.d.ts +1 -0
  149. package/dist/lib/mcp-connector-url.test.js +13 -0
  150. package/dist/lib/mcp-connector-url.test.js.map +1 -0
  151. package/dist/lib/mcp-snippets.d.ts +16 -0
  152. package/dist/lib/mcp-snippets.js +20 -2
  153. package/dist/lib/mcp-snippets.js.map +1 -1
  154. package/dist/lib/now-line.d.ts +66 -0
  155. package/dist/lib/now-line.js +193 -0
  156. package/dist/lib/now-line.js.map +1 -0
  157. package/dist/lib/now-line.test.d.ts +5 -0
  158. package/dist/lib/now-line.test.js +177 -0
  159. package/dist/lib/now-line.test.js.map +1 -0
  160. package/dist/lib/package-updates.d.ts +66 -0
  161. package/dist/lib/package-updates.js +76 -0
  162. package/dist/lib/package-updates.js.map +1 -0
  163. package/dist/lib/pod.d.ts +0 -4
  164. package/dist/lib/pod.js +0 -7
  165. package/dist/lib/pod.js.map +1 -1
  166. package/dist/lib/register-claude-code-mcp.test.js +19 -0
  167. package/dist/lib/register-claude-code-mcp.test.js.map +1 -1
  168. package/dist/lib/safe-open.d.ts +5 -3
  169. package/dist/lib/safe-open.js +9 -8
  170. package/dist/lib/safe-open.js.map +1 -1
  171. package/dist/lib/self-host.d.ts +17 -0
  172. package/dist/lib/self-host.js +24 -0
  173. package/dist/lib/self-host.js.map +1 -0
  174. package/dist/lib/targets.d.ts +31 -0
  175. package/dist/lib/targets.js +100 -104
  176. package/dist/lib/targets.js.map +1 -1
  177. package/dist/lib/template-lifecycle.d.ts +0 -31
  178. package/dist/lib/template-lifecycle.js +0 -74
  179. package/dist/lib/template-lifecycle.js.map +1 -1
  180. package/dist/lib/term.d.ts +24 -0
  181. package/dist/lib/term.js +52 -0
  182. package/dist/lib/term.js.map +1 -0
  183. package/dist/lib/term.test.d.ts +1 -0
  184. package/dist/lib/term.test.js +29 -0
  185. package/dist/lib/term.test.js.map +1 -0
  186. package/dist/lib/transcript-index.d.ts +94 -0
  187. package/dist/lib/transcript-index.js +321 -0
  188. package/dist/lib/transcript-index.js.map +1 -0
  189. package/dist/lib/transcript-index.test.d.ts +10 -0
  190. package/dist/lib/transcript-index.test.js +200 -0
  191. package/dist/lib/transcript-index.test.js.map +1 -0
  192. package/dist/lib/wait-help.d.ts +11 -0
  193. package/dist/lib/wait-help.js +25 -0
  194. package/dist/lib/wait-help.js.map +1 -0
  195. package/dist/lib/wait-state.d.ts +57 -0
  196. package/dist/lib/wait-state.js +114 -0
  197. package/dist/lib/wait-state.js.map +1 -0
  198. package/package.json +2 -2
  199. package/skills/synap/SKILL.md +81 -44
  200. package/skills/synap/code-skills.md +15 -1
  201. package/skills/synap/concepts.md +36 -26
  202. package/skills/synap/document-embeds.md +15 -1
  203. package/skills/synap/focus-sessions.md +4 -4
  204. package/skills/synap/from-intent.md +2 -2
  205. package/skills/synap/governance-rules.md +2 -0
  206. package/skills/synap/hand-off.md +10 -6
  207. package/skills/synap/reflexes.md +4 -4
  208. package/skills/synap/work-model.md +1 -1
  209. package/skills/synap/writing-titles.md +7 -0
  210. package/skills/synap-app/SKILL.md +2 -2
  211. package/skills/synap-app/overview.md +2 -2
  212. package/skills/synap-market/SKILL.md +1 -1
  213. package/skills/synap-market/governance-and-catalog.md +1 -1
  214. package/skills/synap-schema/SKILL.md +4 -1
  215. package/skills/synap-schema/intent-vocabulary-ssot.md +4 -1
  216. package/dist/commands/template.d.ts +0 -42
  217. package/dist/commands/template.js +0 -191
  218. package/dist/commands/template.js.map +0 -1
  219. package/dist/lib/browser-auth.d.ts +0 -35
  220. package/dist/lib/browser-auth.js +0 -170
  221. package/dist/lib/browser-auth.js.map +0 -1
  222. package/dist/lib/openclaw.d.ts +0 -32
  223. package/dist/lib/openclaw.js +0 -165
  224. package/dist/lib/openclaw.js.map +0 -1
  225. package/dist/lib/seed.d.ts +0 -13
  226. package/dist/lib/seed.js +0 -135
  227. package/dist/lib/seed.js.map +0 -1
@@ -0,0 +1,227 @@
1
+ /**
2
+ * The status line's 4th line from the pod, through the synap-bridge plugin's
3
+ * per-conversation status file (bridge 0.10, plan P3.3).
4
+ *
5
+ * After each read of the bound session the bridge writes
6
+ * `~/.synap/bridge/status/<Claude Code session id>.json`, whole (tmp + `mv -f`,
7
+ * so a reader never sees half a file): `{ v: 1, writtenAt, sessionId, title,
8
+ * live, nextMove, waitingOn, workUnits }`, each from the session's
9
+ * continuation packet. A section the pod could not read is `null`, never
10
+ * empty; `sessionId: null` = nothing is bound. The writer is the bridge's
11
+ * `statusFile` (synap-bridge `hooks/lib.ts`).
12
+ *
13
+ * The file is the FIRST source of what the conversation waits on; the
14
+ * transcript index (lib/now-line.ts) stays the fallback whenever the file is
15
+ * absent, unbound, stale or unreadable. The turn state itself (working /
16
+ * needs you / stopped) stays Claude Code's registry when it is readable: the
17
+ * pod's `live` is the bridge's relay of that same registry, smoothed by the
18
+ * pod's 5-minute rule, so it is used only when the registry is not there.
19
+ *
20
+ * ▶ working · 4m · ⏳ 2 · other work (2) · synap-cli#52 open ✗
21
+ * ⏳ waiting on 3 · other work (2) · approval · synap-cli#52 open ✓
22
+ * ■ stopped · next: Produce "Wave 2 report" · pod 40m ago
23
+ *
24
+ * Local files only, no network. `readBridgeStatus` never throws;
25
+ * `buildBridgeLine` is pure.
26
+ */
27
+ import fs from "node:fs";
28
+ import os from "node:os";
29
+ import path from "node:path";
30
+ import { WAITING_ON_REASON_LABELS, goalWord } from "./goal-words.js";
31
+ import { age, capped, clip, DEFAULT_WIDTH } from "./now-line.js";
32
+ import { AMBER as A, BOLD_YELLOW as Y, CYAN as C, DIM as D, GREEN as G, RED as R, RESET as X, osc8, scrubStrings } from "./term.js";
33
+ /** The pod's working window (`SESSION_WORKING_WINDOW_MS`), for a file whose `live` carries none. */
34
+ export const POD_WORKING_WINDOW_MS = 5 * 60_000;
35
+ /**
36
+ * A file older than this is stale even when no registry says when this
37
+ * Claude Code process started: beyond half a day nothing shows its writer
38
+ * still runs. A quiet file younger than this is still true (the bridge
39
+ * rewrites it on every change the pod's feed sends), and its age is shown.
40
+ */
41
+ export const BRIDGE_STATUS_MAX_AGE_MS = 12 * 60 * 60_000;
42
+ export function bridgeStatusPath(claudeSessionId, home = os.homedir()) {
43
+ return path.join(home, ".synap", "bridge", "status", `${claudeSessionId}.json`);
44
+ }
45
+ const isObj = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
46
+ const isTime = (v) => typeof v === "string" && Number.isFinite(Date.parse(v));
47
+ const isStrOrNull = (v) => v === null || typeof v === "string";
48
+ /**
49
+ * The file's `live`, normalised. One malformed field costs that field (null),
50
+ * and a `live` that is no object at all reads as "not measured" (null): the
51
+ * rest of the file is still true, so it is never a failed read.
52
+ */
53
+ function readLive(v) {
54
+ if (!isObj(v))
55
+ return null;
56
+ const windowMs = typeof v.windowMs === "number" && Number.isFinite(v.windowMs) && v.windowMs > 0 ? v.windowMs : null;
57
+ return {
58
+ state: v.state === "working" ? "working" : "idle",
59
+ turnInFlight: v.turnInFlight === true,
60
+ since: isTime(v.since) ? v.since : null,
61
+ lastActivityAt: isTime(v.lastActivityAt) ? v.lastActivityAt : null,
62
+ measuredAt: isTime(v.measuredAt) ? v.measuredAt : null,
63
+ windowMs,
64
+ };
65
+ }
66
+ /**
67
+ * The parsed JSON as a version-1 file, or why it is not one. Every string in
68
+ * it is scrubbed of control characters first (term.ts): the file carries pod
69
+ * words (titles, labels, PR names) that are printed as they are.
70
+ */
71
+ export function parseBridgeStatus(raw) {
72
+ const json = scrubStrings(raw);
73
+ if (!isObj(json))
74
+ return "not an object";
75
+ if (json.v !== 1)
76
+ return `version ${JSON.stringify(json.v)} is not 1`;
77
+ if (!isTime(json.writtenAt))
78
+ return "no writtenAt time";
79
+ if (!isStrOrNull(json.sessionId))
80
+ return "sessionId is not a string";
81
+ if (!isStrOrNull(json.title ?? null))
82
+ return "title is not a string";
83
+ const live = readLive(json.live);
84
+ const next = json.nextMove ?? null;
85
+ if (next !== null && (!isObj(next) || typeof next.label !== "string"))
86
+ return "nextMove is malformed";
87
+ const waits = json.waitingOn ?? null;
88
+ if (waits !== null && (!Array.isArray(waits) || !waits.every((m) => isObj(m) && typeof m.reason === "string" && typeof m.count === "number")))
89
+ return "waitingOn is malformed";
90
+ const units = json.workUnits ?? null;
91
+ if (units !== null && (!Array.isArray(units) || !units.every((u) => isObj(u) && typeof u.label === "string" && typeof u.state === "string")))
92
+ return "workUnits is malformed";
93
+ return {
94
+ v: 1,
95
+ writtenAt: json.writtenAt,
96
+ sessionId: json.sessionId,
97
+ title: json.title ?? null,
98
+ live,
99
+ nextMove: next,
100
+ waitingOn: waits,
101
+ workUnits: units,
102
+ };
103
+ }
104
+ /**
105
+ * This conversation's status file, judged. Stale when it was written before
106
+ * this Claude Code process started (`startedAt`, from the registry: the
107
+ * bridge of an earlier process wrote it, and this one has not confirmed the
108
+ * binding yet), or is older than BRIDGE_STATUS_MAX_AGE_MS. Never throws.
109
+ */
110
+ export function readBridgeStatus(claudeSessionId, opts) {
111
+ // A session id becomes a file name: anything that could leave the directory is no file.
112
+ if (!/^[A-Za-z0-9_-]+$/.test(claudeSessionId))
113
+ return { status: "absent" };
114
+ let raw;
115
+ try {
116
+ raw = fs.readFileSync(bridgeStatusPath(claudeSessionId, opts.home), "utf-8");
117
+ }
118
+ catch (e) {
119
+ if (e.code === "ENOENT")
120
+ return { status: "absent" };
121
+ return { status: "failed", why: `unreadable (${e.code ?? "error"})` };
122
+ }
123
+ let json;
124
+ try {
125
+ json = JSON.parse(raw);
126
+ }
127
+ catch {
128
+ return { status: "failed", why: "not JSON" };
129
+ }
130
+ const file = parseBridgeStatus(json);
131
+ if (typeof file === "string")
132
+ return { status: "failed", why: file };
133
+ const writtenAt = Date.parse(file.writtenAt);
134
+ if (opts.startedAt && writtenAt < opts.startedAt)
135
+ return { status: "stale", why: "written before this Claude Code process started" };
136
+ if (opts.now - writtenAt > BRIDGE_STATUS_MAX_AGE_MS)
137
+ return { status: "stale", why: `written ${age(opts.now - writtenAt)} ago` };
138
+ if (file.sessionId === null)
139
+ return { status: "unbound" };
140
+ return { status: "fresh", file, writtenAt };
141
+ }
142
+ // ── The line ───────────────────────────────────────────────────────────
143
+ /** One mark: `other work (2)`, words through the vocabulary's table (goal-words.ts). */
144
+ function markText(m) {
145
+ const reason = goalWord(WAITING_ON_REASON_LABELS, m.reason).toLowerCase();
146
+ return m.count > 1 ? `${reason} (${m.count})` : reason;
147
+ }
148
+ /** A pull request still under way: `synap-cli#52 open ✗`, its name a link to it. */
149
+ function unitText(u) {
150
+ const isPr = u.kind === "pull_request" || /\/pull\/\d+/.test(u.url ?? "");
151
+ if (!isPr || (u.state !== "open" && u.state !== "claimed"))
152
+ return null;
153
+ const name = osc8(u.url, /^\S+#\d+/.exec(u.label)?.[0] ?? clip(u.label, 30));
154
+ const p = u.prState;
155
+ if (!p)
156
+ return name; // the pod recorded nothing about it: draw nothing, never a guess
157
+ if (p.status !== "ok")
158
+ return `${name} ${D}⚑ not read${X}`;
159
+ const word = (p.label ?? p.state ?? "").toLowerCase();
160
+ const checks = p.checks === "passed" ? ` ${G}✓${X}` : p.checks === "failed" ? ` ${R}✗${X}` : "";
161
+ return `${name}${word ? ` ${D}${word}${X}` : ""}${checks}`;
162
+ }
163
+ /**
164
+ * The pod's rule (`isSessionWorkingNow`) on the file's `live`, judged now.
165
+ *
166
+ * `turnInFlight` is the pod's word AT `measuredAt` (else when the file was
167
+ * written, `writtenAt`), not now: it holds for one working window after that
168
+ * and no longer. Read as "now", a file the bridge last wrote mid-turn said
169
+ * "working" for as long as the file stayed fresh (12 h).
170
+ */
171
+ export function podWorking(live, now, writtenAt) {
172
+ const window = live.windowMs ?? POD_WORKING_WINDOW_MS;
173
+ const last = live.lastActivityAt ? Date.parse(live.lastActivityAt) : NaN;
174
+ if (Number.isFinite(last) && now - last <= window)
175
+ return true;
176
+ if (!live.turnInFlight)
177
+ return false;
178
+ const measured = live.measuredAt ? Date.parse(live.measuredAt) : writtenAt ?? NaN;
179
+ return Number.isFinite(measured) && now - measured <= window;
180
+ }
181
+ /** The 4th line from a fresh status file. */
182
+ export function buildBridgeLine(input) {
183
+ const { now, file, registry } = input;
184
+ const width = input.width && input.width > 20 ? input.width : DEFAULT_WIDTH;
185
+ if (registry?.status === "waiting") {
186
+ return `${Y}✋ needs you${X} ${D}·${X} ${clip(registry.waitingFor || "your answer", width - 16)}`;
187
+ }
188
+ const marks = (file.waitingOn ?? []).filter((m) => m.count > 0);
189
+ const waited = marks.reduce((n, m) => n + m.count, 0);
190
+ const units = (file.workUnits ?? []).map(unitText).filter((t) => t !== null);
191
+ const unread = [file.waitingOn === null && "waits", file.workUnits === null && "PRs"].filter(Boolean);
192
+ // The registry's turn state when there is one; the pod's relay of it otherwise.
193
+ let working = false;
194
+ let since;
195
+ if (registry) {
196
+ working = registry.status === "busy";
197
+ since = registry.statusUpdatedAt;
198
+ }
199
+ else if (file.live) {
200
+ working = podWorking(file.live, now, input.writtenAt);
201
+ const at = Date.parse((working ? file.live.since : file.live.lastActivityAt) ?? "");
202
+ since = Number.isFinite(at) ? at : undefined;
203
+ }
204
+ const items = [...marks.map(markText), ...units];
205
+ if (!working && file.nextMove?.label)
206
+ items.push(`${D}next:${X} ${clip(file.nextMove.label, 60)}`);
207
+ if (unread.length)
208
+ items.push(`${D}⚑ not read: ${unread.join(", ")}${X}`);
209
+ // A quiet file is still true, but say how old the pod's word is.
210
+ if (now - input.writtenAt > POD_WORKING_WINDOW_MS)
211
+ items.push(`${D}pod ${age(now - input.writtenAt)} ago${X}`);
212
+ let head;
213
+ if (working) {
214
+ head = `${C}▶ working${X}${since ? ` ${D}· ${age(now - since)}${X}` : ""}${waited ? ` ${D}·${X} ⏳ ${waited}` : ""}`;
215
+ }
216
+ else if (waited) {
217
+ head = `${Y}⏳ waiting on ${waited}${X}`;
218
+ }
219
+ else if (!registry && !file.live) {
220
+ head = `${D}○ no session status${X}`;
221
+ }
222
+ else {
223
+ head = `${A}■ stopped${X}${since ? ` ${D}· ${age(now - since)}${X}` : ""}`;
224
+ }
225
+ return capped(head, items, width);
226
+ }
227
+ //# sourceMappingURL=bridge-status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge-status.js","sourceRoot":"","sources":["../../src/lib/bridge-status.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * The bridge's status file as the status line reads it: judged (fresh /
3
+ * absent / unbound / stale / failed) and drawn. Files go under a temp HOME
4
+ * passed as `home`; time, registry and width are arguments.
5
+ */
6
+ export {};
@@ -0,0 +1,197 @@
1
+ /**
2
+ * The bridge's status file as the status line reads it: judged (fresh /
3
+ * absent / unbound / stale / failed) and drawn. Files go under a temp HOME
4
+ * passed as `home`; time, registry and width are arguments.
5
+ */
6
+ import fs from "node:fs";
7
+ import os from "node:os";
8
+ import path from "node:path";
9
+ import { describe, it, expect, beforeEach } from "vitest";
10
+ import { BRIDGE_STATUS_MAX_AGE_MS, bridgeStatusPath, buildBridgeLine, readBridgeStatus, } from "./bridge-status.js";
11
+ const NOW = Date.parse("2026-10-30T22:00:00Z");
12
+ const min = (m) => NOW - m * 60_000;
13
+ const iso = (ms) => new Date(ms).toISOString();
14
+ // eslint-disable-next-line no-control-regex
15
+ const plain = (s) => s.replace(/\x1b\[[0-9;]*m|\x1b\]8;;[^\x1b]*\x1b\\/g, "");
16
+ const CONV = "11111111-2222-3333-4444-555555555555";
17
+ /** A file as the bridge's `statusFile` writes it (synap-bridge hooks/lib.ts). */
18
+ const file = (over = {}) => ({
19
+ v: 1,
20
+ writtenAt: iso(min(1)),
21
+ sessionId: "54436c32-783f-4a9d-9322-16ff18f448f7",
22
+ title: "Lane cli-statusfile",
23
+ live: { state: "idle", turnInFlight: false, since: iso(min(20)), lastActivityAt: iso(min(20)), measuredAt: iso(min(1)), windowMs: 300_000 },
24
+ nextMove: { kind: "agent_slot", actor: "ai", label: 'Produce "Wave 2 report"', reason: "Declared deliverable with no output yet" },
25
+ waitingOn: [],
26
+ workUnits: [],
27
+ ...over,
28
+ });
29
+ const reg = (status, extra = {}) => ({
30
+ sessionId: CONV,
31
+ pid: 1,
32
+ status,
33
+ statusUpdatedAt: min(4),
34
+ startedAt: min(600),
35
+ ...extra,
36
+ });
37
+ let home;
38
+ beforeEach(() => {
39
+ home = fs.mkdtempSync(path.join(os.tmpdir(), "bridge-status-"));
40
+ });
41
+ const write = (content) => {
42
+ const p = bridgeStatusPath(CONV, home);
43
+ fs.mkdirSync(path.dirname(p), { recursive: true });
44
+ fs.writeFileSync(p, content);
45
+ };
46
+ const read = (opts = {}) => readBridgeStatus(CONV, { now: NOW, home, ...opts });
47
+ describe("reading the file", () => {
48
+ it("is where the bridge writes it", () => {
49
+ expect(bridgeStatusPath(CONV, "/home/x")).toBe(`/home/x/.synap/bridge/status/${CONV}.json`);
50
+ });
51
+ it("a fresh file of a bound session is drawn", () => {
52
+ write(JSON.stringify(file()));
53
+ const r = read({ startedAt: min(600) });
54
+ expect(r.status).toBe("fresh");
55
+ if (r.status === "fresh")
56
+ expect(r.writtenAt).toBe(min(1));
57
+ });
58
+ it("no file is absent (no bridge, or it has not written yet)", () => {
59
+ expect(read()).toEqual({ status: "absent" });
60
+ });
61
+ it("nothing bound (`sessionId: null`, /bridge unbind) is unbound, not drawn", () => {
62
+ write(JSON.stringify(file({ sessionId: null, title: null })));
63
+ expect(read()).toEqual({ status: "unbound" });
64
+ });
65
+ it("a file written before this Claude Code process started is stale", () => {
66
+ write(JSON.stringify(file({ writtenAt: iso(min(90)) })));
67
+ expect(read({ startedAt: min(60) })).toEqual({ status: "stale", why: "written before this Claude Code process started" });
68
+ });
69
+ it("a file older than the max age is stale, even with no registry", () => {
70
+ write(JSON.stringify(file({ writtenAt: iso(NOW - BRIDGE_STATUS_MAX_AGE_MS - 60_000) })));
71
+ expect(read()).toMatchObject({ status: "stale" });
72
+ });
73
+ it("a quiet file younger than the max age is still fresh", () => {
74
+ write(JSON.stringify(file({ writtenAt: iso(min(45)) })));
75
+ expect(read({ startedAt: min(600) }).status).toBe("fresh");
76
+ });
77
+ it("malformed JSON is a failed read, never absent, and never throws", () => {
78
+ write('{"v":1,"writtenAt":');
79
+ expect(read()).toEqual({ status: "failed", why: "not JSON" });
80
+ });
81
+ it("another version, a missing time or a malformed section is a failed read", () => {
82
+ write(JSON.stringify({ ...file(), v: 2 }));
83
+ expect(read()).toMatchObject({ status: "failed", why: "version 2 is not 1" });
84
+ write(JSON.stringify({ ...file(), writtenAt: "soon" }));
85
+ expect(read()).toMatchObject({ status: "failed", why: "no writtenAt time" });
86
+ write(JSON.stringify({ ...file(), waitingOn: { status: "ok", marks: [] } }));
87
+ expect(read()).toMatchObject({ status: "failed", why: "waitingOn is malformed" });
88
+ write("[]");
89
+ expect(read()).toMatchObject({ status: "failed", why: "not an object" });
90
+ });
91
+ it("a malformed `live` costs only its own fields, never the file (bridge ≤ 0.11 wrote NaN and \"undefined\")", () => {
92
+ // What `String(undefined)` and `Number(undefined)` (NaN → null in JSON) leave in the file.
93
+ write(JSON.stringify({ ...file(), live: { state: "idle", turnInFlight: false, since: null, lastActivityAt: null, measuredAt: "undefined", windowMs: null } }));
94
+ const r = read({ startedAt: min(600) });
95
+ expect(r.status).toBe("fresh");
96
+ if (r.status === "fresh")
97
+ expect(r.file.live).toEqual({ state: "idle", turnInFlight: false, since: null, lastActivityAt: null, measuredAt: null, windowMs: null });
98
+ write(JSON.stringify({ ...file(), live: { state: "working" } }));
99
+ expect(read().status).toBe("fresh");
100
+ write(JSON.stringify({ ...file(), live: "undefined" }));
101
+ const s = read();
102
+ expect(s.status).toBe("fresh");
103
+ if (s.status === "fresh")
104
+ expect(s.file.live).toBeNull();
105
+ });
106
+ it("every string in the file is scrubbed of control characters", () => {
107
+ write(JSON.stringify(file({
108
+ nextMove: { kind: "agent_slot", actor: "ai", label: "Open\x1b]8;;https://evil.test\x1b\\ the PR\x07", reason: "" },
109
+ workUnits: [{ key: "a", label: "backend#7\x1b[2J x", kind: "pull_request", url: "https://github.com/Synap-core/backend/pull/7\x1b\\", state: "open", prState: null }],
110
+ })));
111
+ const r = read({ startedAt: min(600) });
112
+ expect(r.status).toBe("fresh");
113
+ if (r.status !== "fresh")
114
+ return;
115
+ const raw = buildBridgeLine({ now: NOW, file: r.file, writtenAt: r.writtenAt, registry: reg("idle") });
116
+ expect(raw).not.toContain("https://evil.test\x1b");
117
+ expect(raw).not.toContain("\x1b[2J");
118
+ expect(raw).not.toContain("\x07");
119
+ // The URL's own ESC is gone (its backslash is left, inert); our link around the PR name is intact.
120
+ expect(raw).toContain("\x1b]8;;https://github.com/Synap-core/backend/pull/7\\\x1b\\backend#7\x1b]8;;\x1b\\");
121
+ expect(plain(raw)).toContain("next: Open]8;;https://evil.test\\ the PR");
122
+ });
123
+ it("an unreadable file (here a directory) is a failed read", () => {
124
+ fs.mkdirSync(bridgeStatusPath(CONV, home), { recursive: true });
125
+ expect(read()).toMatchObject({ status: "failed", why: expect.stringContaining("unreadable") });
126
+ });
127
+ it("a session id that could leave the directory reads no file", () => {
128
+ expect(readBridgeStatus("../../etc/passwd", { now: NOW, home })).toEqual({ status: "absent" });
129
+ });
130
+ });
131
+ const line = (f, registry = reg("idle"), width) => plain(buildBridgeLine({ now: NOW, file: f, writtenAt: Date.parse(f.writtenAt), registry, width }));
132
+ describe("drawing the line", () => {
133
+ it("idle with nothing waited on: stopped, with the pod's next move", () => {
134
+ expect(line(file())).toBe('■ stopped · 4m · next: Produce "Wave 2 report"');
135
+ });
136
+ it("idle and waiting: the pod's marks, in the vocabulary's words, and the open PRs", () => {
137
+ const f = file({
138
+ waitingOn: [
139
+ { reason: "another_work", count: 2, refs: [{ kind: "session", id: "s2" }] },
140
+ { reason: "approval", count: 1 },
141
+ ],
142
+ workUnits: [
143
+ { key: "pr-synap-cli-52", label: "synap-cli#52 feat(statusline): read the bridge file", kind: "pull_request", url: "https://github.com/Synap-core/synap-cli/pull/52", state: "open", prState: { status: "ok", label: "Open", state: "open", checks: "failed" } },
144
+ { key: "pr-backend-9", label: "backend#9 done already", kind: "pull_request", url: "https://github.com/Synap-core/backend/pull/9", state: "met", prState: { status: "ok", label: "Merged", state: "merged" } },
145
+ ],
146
+ });
147
+ expect(line(f)).toBe('⏳ waiting on 3 · other work (2) · approval · synap-cli#52 open ✗ · next: Produce "Wave 2 report"');
148
+ });
149
+ it("working (the registry says busy): the marks follow, the next move does not", () => {
150
+ const f = file({ waitingOn: [{ reason: "input", count: 1 }] });
151
+ expect(line(f, reg("busy", { statusUpdatedAt: min(3) }))).toBe("▶ working · 3m · ⏳ 1 · input");
152
+ });
153
+ it("the registry's permission prompt beats everything", () => {
154
+ expect(line(file(), reg("waiting", { waitingFor: "permission prompt" }))).toBe("✋ needs you · permission prompt");
155
+ });
156
+ it("no registry: the pod's live, re-judged now by its own window", () => {
157
+ const working = file({ live: { state: "working", turnInFlight: false, since: iso(min(2)), lastActivityAt: iso(min(2)), measuredAt: iso(min(1)), windowMs: 300_000 } });
158
+ expect(line(working, null)).toBe("▶ working · 2m");
159
+ // Measured as working, but its last activity is now past the window: idle.
160
+ const lapsed = file({ live: { state: "working", turnInFlight: false, since: iso(min(8)), lastActivityAt: iso(min(8)), measuredAt: iso(min(1)), windowMs: 300_000 } });
161
+ expect(line(lapsed, null)).toBe('■ stopped · 8m · next: Produce "Wave 2 report"');
162
+ expect(line(file({ live: null }), null)).toBe('○ no session status · next: Produce "Wave 2 report"');
163
+ });
164
+ it("a turn in flight is the pod's word at `measuredAt`: it lapses one window later, never 12 h later", () => {
165
+ const inFlight = (measured, windowMs = 300_000) => file({ live: { state: "working", turnInFlight: true, since: iso(min(700)), lastActivityAt: iso(min(700)), measuredAt: iso(measured), windowMs } });
166
+ expect(line(inFlight(min(1)), null)).toBe("▶ working · 11h40");
167
+ // Written mid-turn 6 h ago and never rewritten: not "working".
168
+ expect(line(inFlight(min(360)), null)).toBe('■ stopped · 11h40 · next: Produce "Wave 2 report"');
169
+ // No usable measurement time: the time the file was written bounds it, and the pod's default window applies.
170
+ const unmeasured = file({ writtenAt: iso(min(30)), live: { ...inFlight(min(1)).live, measuredAt: null, windowMs: null } });
171
+ expect(line(unmeasured, null)).toBe('■ stopped · 11h40 · next: Produce "Wave 2 report" · pod 30m ago');
172
+ expect(line({ ...unmeasured, writtenAt: iso(min(2)) }, null)).toBe("▶ working · 11h40");
173
+ });
174
+ it("a section the pod could not read is said, never drawn as nothing", () => {
175
+ expect(line(file({ waitingOn: null, workUnits: null, nextMove: null }))).toBe("■ stopped · 4m · ⚑ not read: waits, PRs");
176
+ });
177
+ it("a PR whose state the pod could not read is marked; one with nothing recorded is just named", () => {
178
+ const f = file({
179
+ nextMove: null,
180
+ workUnits: [
181
+ { key: "a", label: "backend#7 x", kind: "pull_request", url: "https://github.com/Synap-core/backend/pull/7", state: "open", prState: { status: "unavailable" } },
182
+ { key: "b", label: "relay-app#3 y", kind: "pull_request", url: null, state: "claimed", prState: null },
183
+ ],
184
+ });
185
+ expect(line(f)).toBe("■ stopped · 4m · backend#7 ⚑ not read · relay-app#3");
186
+ });
187
+ it("a quiet file says how old the pod's word is", () => {
188
+ expect(line(file({ writtenAt: iso(min(40)), nextMove: null }))).toBe("■ stopped · 4m · pod 40m ago");
189
+ });
190
+ it("caps itself to the width", () => {
191
+ const f = file({ waitingOn: Array.from({ length: 6 }, (_, i) => ({ reason: `reason_${i}`, count: 1 })) });
192
+ const out = line(f, reg("idle"), 50);
193
+ expect(out.length).toBeLessThanOrEqual(50);
194
+ expect(out).toMatch(/\+\d+ more$/);
195
+ });
196
+ });
197
+ //# sourceMappingURL=bridge-status.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge-status.test.js","sourceRoot":"","sources":["../../src/lib/bridge-status.test.ts"],"names":[],"mappings":"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"}
@@ -20,7 +20,7 @@ vi.mock("./mcp-bridge.js", async (orig) => {
20
20
  };
21
21
  });
22
22
  import { hubGet } from "./hub-client.js";
23
- import { mcpBridgeHeaders, CLIENT_HEADER, clientHeader } from "./conversation-headers.js";
23
+ import { mcpBridgeHeaders, CLIENT_HEADER, RUNNER_HEADER, claudeCodeProcess, clientHeader } from "./conversation-headers.js";
24
24
  import { mcpBridge } from "../commands/mcp.js";
25
25
  const VERSION = JSON.parse(readFileSync(new URL("../../package.json", import.meta.url), "utf8")).version;
26
26
  afterEach(() => {
@@ -45,6 +45,8 @@ describe("X-Synap-Client", () => {
45
45
  await hubGet("/workspaces", {}, { podUrl: "https://pod.example", apiKey: "k" });
46
46
  expect(seen).toHaveLength(1);
47
47
  expect(seen[0][CLIENT_HEADER]).toBe(`synap-cli/${VERSION}`);
48
+ // The worker's served stamp is the worker poll's alone: an ordinary command never claims it.
49
+ expect(seen[0][RUNNER_HEADER]).toBeUndefined();
48
50
  });
49
51
  it("the stdio MCP bridge sends synap-cli-mcp/<version> on every request", async () => {
50
52
  const { runMcpBridge } = await vi.importActual("./mcp-bridge.js");
@@ -74,6 +76,8 @@ describe("X-Synap-Client", () => {
74
76
  expect(sent.length).toBe(2);
75
77
  for (const h of sent)
76
78
  expect(h[CLIENT_HEADER]).toBe(`synap-cli-mcp/${VERSION}`);
79
+ for (const h of sent)
80
+ expect(h[RUNNER_HEADER]).toBeUndefined();
77
81
  });
78
82
  it("`synap mcp bridge` hands the bridge those headers", async () => {
79
83
  vi.stubEnv("SYNAP_HUB_API_KEY", "k");
@@ -81,5 +85,19 @@ describe("X-Synap-Client", () => {
81
85
  expect(captured.opts?.headers?.[CLIENT_HEADER]).toBe(`synap-cli-mcp/${VERSION}`);
82
86
  expect(captured.opts?.headers?.["X-Synap-Conversation"]).toBeTruthy();
83
87
  });
88
+ it("`synap mcp bridge` inside Claude Code names its parent process (plan C2); outside it names none", async () => {
89
+ vi.stubEnv("SYNAP_HUB_API_KEY", "k");
90
+ vi.stubEnv("CLAUDE_CODE_SESSION_ID", "8c34a72b-b1c1-4c37-9c1f-02920b69ccb2");
91
+ await mcpBridge({ url: "https://pod/mcp" });
92
+ const sent = captured.opts?.headers?.["X-Synap-Process"];
93
+ // This runner's own parent stands for Claude Code; a host without ps sends none.
94
+ if (sent !== undefined)
95
+ expect(sent).toMatch(new RegExp(`^[A-Za-z0-9._-]+:${process.ppid}:\\d{13}$`));
96
+ else
97
+ expect(claudeCodeProcess()).toBeUndefined();
98
+ vi.stubEnv("CLAUDE_CODE_SESSION_ID", "");
99
+ await mcpBridge({ url: "https://pod/mcp" });
100
+ expect(captured.opts?.headers?.["X-Synap-Process"]).toBeUndefined();
101
+ });
84
102
  });
85
103
  //# sourceMappingURL=client-header.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client-header.test.js","sourceRoot":"","sources":["../../src/lib/client-header.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client-header.test.js","sourceRoot":"","sources":["../../src/lib/client-header.test.ts"],"names":[],"mappings":"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"}
@@ -11,6 +11,66 @@ export declare const CLIENT_HEADER = "X-Synap-Client";
11
11
  export type SynapClientName = "synap-cli" | "synap-cli-mcp";
12
12
  /** `{ "X-Synap-Client": "<name>/<version>" }`; the version is the package's. */
13
13
  export declare function clientHeader(name: SynapClientName, version?: string): Record<string, string>;
14
+ /**
15
+ * The worker's stamp, `synap-worker/<version>`: sent ONLY by `synap worker` on
16
+ * its own orient poll. The pod records, per key, the last time a request
17
+ * carried it (`servedAt`): proof that a process serves that agent, which a key
18
+ * merely being used is not. Interactive commands and the MCP bridge never send
19
+ * it, or every use of a key would read as "a worker runs".
20
+ */
21
+ export declare const RUNNER_HEADER = "X-Synap-Runner";
22
+ /** `{ "X-Synap-Runner": "synap-worker/<version>" }`; the version is the package's. */
23
+ export declare function workerRunnerHeader(version?: string): Record<string, string>;
24
+ /**
25
+ * Which OS process of a conversation calls (`<host>:<pid>:<startedAtMs>`), and
26
+ * what that runner is doing (`busy` | `idle` | `needs_permission` |
27
+ * `needs_answer` (a question or a plan dialog) | `ended`).
28
+ * The pod records both on the conversation's `session_runners` rows; a pod
29
+ * that reads neither ignores them. synap-bridge sends the state the same way.
30
+ */
31
+ export declare const PROCESS_HEADER = "X-Synap-Process";
32
+ export declare const RUNNER_STATE_HEADER = "X-Synap-Runner-State";
33
+ /**
34
+ * Which MODEL a run uses and which PROVIDER serves it: facts the client
35
+ * reports, never identity (pod decision 5e7c77dc). The pod keeps a provider
36
+ * slug it knows (anthropic, bedrock, vertex, foundry, openai, openrouter, zai,
37
+ * deepseek) and reads any other word as `other`; it drops a model id that is
38
+ * not an id. Send nothing rather than a guess: absent reads unknown, never
39
+ * "anthropic". Never send a URL. A pod that reads neither ignores them.
40
+ */
41
+ export declare const MODEL_HEADER = "X-Synap-Model";
42
+ export declare const MODEL_PROVIDER_HEADER = "X-Synap-Model-Provider";
43
+ /** A model id the pod will keep, else undefined (`<synthetic>`, a URL, junk). */
44
+ export declare function reportableModel(model: string | undefined): string | undefined;
45
+ /** `{ X-Synap-Model?, X-Synap-Model-Provider? }`: each only when known. */
46
+ export declare function modelHeaders(model: string | undefined, provider: string | undefined): Record<string, string>;
47
+ /**
48
+ * THE process identity format, `<host>:<pid>:<startedAtMs>` (the pod's
49
+ * `parseProcessIdentity`): the host with every character outside
50
+ * `[A-Za-z0-9._-]` made `-`, at most 255, `computer` when empty. `synap worker`
51
+ * (`runProcessIdentity`), the stdio MCP bridge (`claudeCodeProcess`) and the
52
+ * synap-bridge mod (`processIdentity`, `hooks/lib.ts`, byte for byte, tested on
53
+ * the same fixture) all format through it, so one Claude Code process is one
54
+ * runner row on the pod.
55
+ */
56
+ export declare function processIdentity(hostname: string, pid: number, startedAtMs: number): string;
57
+ /**
58
+ * `ps -o lstart=` read in UTC with the C locale (`Mon Nov 2 13:09:07 2026`,
59
+ * BSD and procps alike) -> epoch ms; undefined for anything else. Parsed field
60
+ * by field, never by `Date.parse`, as the synap-bridge mod parses it.
61
+ */
62
+ export declare function lstartMs(text: string): number | undefined;
63
+ /**
64
+ * The Claude Code process this stdio MCP bridge serves: Claude Code spawns it
65
+ * directly, so it is the parent (`process.ppid`), started when `ps` says. Read
66
+ * once, at the bridge's start. Undefined when it cannot be read (no `ps`, an
67
+ * orphan): the header is then not sent, never guessed.
68
+ */
69
+ export declare function claudeCodeProcess(read?: {
70
+ ppid?: number;
71
+ hostname?: string;
72
+ startMs?: (pid: number) => number | undefined;
73
+ }): string | undefined;
14
74
  /** The same two values in a request's `params._meta` (reverse-DNS vendor keys; `io.modelcontextprotocol/` is reserved). */
15
75
  export declare const CONVERSATION_META_KEY = "live.synap/conversation";
16
76
  export declare const CONVERSATION_CWD_META_KEY = "live.synap/conversationCwd";
@@ -29,5 +89,10 @@ export declare function cliConversation(env?: NodeJS.ProcessEnv): string;
29
89
  * only with a Claude Code conversation (the one a person can reopen).
30
90
  */
31
91
  export declare function conversationHeaders(sessionId: string | undefined, cwd?: string): Record<string, string>;
32
- /** Every header the stdio MCP bridge sends: its client name plus the conversation. */
33
- export declare function mcpBridgeHeaders(sessionId: string | undefined, cwd?: string): Record<string, string>;
92
+ /**
93
+ * Every header the stdio MCP bridge sends: its client name, the conversation,
94
+ * and, with a Claude Code conversation, the Claude Code process it runs in
95
+ * (`claudeCodeProcess`, the same value the synap-bridge mod sends), so the
96
+ * pod's runner rows of that process are one, whichever door called.
97
+ */
98
+ export declare function mcpBridgeHeaders(sessionId: string | undefined, cwd?: string, processId?: string): Record<string, string>;