@sentropic/h2a-runtime 0.81.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. package/dist/account-pool.d.ts +168 -0
  2. package/dist/account-pool.d.ts.map +1 -0
  3. package/dist/account-pool.js +385 -0
  4. package/dist/account-pool.js.map +1 -0
  5. package/dist/agents-projection.d.ts +56 -0
  6. package/dist/agents-projection.d.ts.map +1 -0
  7. package/dist/agents-projection.js +82 -0
  8. package/dist/agents-projection.js.map +1 -0
  9. package/dist/attach.d.ts +75 -0
  10. package/dist/attach.d.ts.map +1 -0
  11. package/dist/attach.js +432 -0
  12. package/dist/attach.js.map +1 -0
  13. package/dist/auth-bundle.d.ts +21 -0
  14. package/dist/auth-bundle.d.ts.map +1 -0
  15. package/dist/auth-bundle.js +112 -0
  16. package/dist/auth-bundle.js.map +1 -0
  17. package/dist/auth-diagnostics.d.ts +18 -0
  18. package/dist/auth-diagnostics.d.ts.map +1 -0
  19. package/dist/auth-diagnostics.js +23 -0
  20. package/dist/auth-diagnostics.js.map +1 -0
  21. package/dist/auth-login.d.ts +9 -0
  22. package/dist/auth-login.d.ts.map +1 -0
  23. package/dist/auth-login.js +21 -0
  24. package/dist/auth-login.js.map +1 -0
  25. package/dist/auth-refresh.d.ts +32 -0
  26. package/dist/auth-refresh.d.ts.map +1 -0
  27. package/dist/auth-refresh.js +83 -0
  28. package/dist/auth-refresh.js.map +1 -0
  29. package/dist/auth-tools.d.ts +55 -0
  30. package/dist/auth-tools.d.ts.map +1 -0
  31. package/dist/auth-tools.js +163 -0
  32. package/dist/auth-tools.js.map +1 -0
  33. package/dist/browser-bridge-local.d.ts +27 -0
  34. package/dist/browser-bridge-local.d.ts.map +1 -0
  35. package/dist/browser-bridge-local.js +51 -0
  36. package/dist/browser-bridge-local.js.map +1 -0
  37. package/dist/browser.d.ts +53 -0
  38. package/dist/browser.d.ts.map +1 -0
  39. package/dist/browser.js +61 -0
  40. package/dist/browser.js.map +1 -0
  41. package/dist/conductor-launch.d.ts +179 -0
  42. package/dist/conductor-launch.d.ts.map +1 -0
  43. package/dist/conductor-launch.js +414 -0
  44. package/dist/conductor-launch.js.map +1 -0
  45. package/dist/config.d.ts +182 -0
  46. package/dist/config.d.ts.map +1 -0
  47. package/dist/config.js +334 -0
  48. package/dist/config.js.map +1 -0
  49. package/dist/conv-guard.d.ts +76 -0
  50. package/dist/conv-guard.d.ts.map +1 -0
  51. package/dist/conv-guard.js +131 -0
  52. package/dist/conv-guard.js.map +1 -0
  53. package/dist/convsync.d.ts +24 -0
  54. package/dist/convsync.d.ts.map +1 -0
  55. package/dist/convsync.js +108 -0
  56. package/dist/convsync.js.map +1 -0
  57. package/dist/cred-health.d.ts +96 -0
  58. package/dist/cred-health.d.ts.map +1 -0
  59. package/dist/cred-health.js +170 -0
  60. package/dist/cred-health.js.map +1 -0
  61. package/dist/delegate.d.ts +406 -0
  62. package/dist/delegate.d.ts.map +1 -0
  63. package/dist/delegate.js +739 -0
  64. package/dist/delegate.js.map +1 -0
  65. package/dist/enroll.d.ts +91 -0
  66. package/dist/enroll.d.ts.map +1 -0
  67. package/dist/enroll.js +248 -0
  68. package/dist/enroll.js.map +1 -0
  69. package/dist/fanout.d.ts +63 -0
  70. package/dist/fanout.d.ts.map +1 -0
  71. package/dist/fanout.js +115 -0
  72. package/dist/fanout.js.map +1 -0
  73. package/dist/forward.d.ts +66 -0
  74. package/dist/forward.d.ts.map +1 -0
  75. package/dist/forward.js +141 -0
  76. package/dist/forward.js.map +1 -0
  77. package/dist/gitdiff.d.ts +31 -0
  78. package/dist/gitdiff.d.ts.map +1 -0
  79. package/dist/gitdiff.js +133 -0
  80. package/dist/gitdiff.js.map +1 -0
  81. package/dist/h2a-bridge.d.ts +102 -0
  82. package/dist/h2a-bridge.d.ts.map +1 -0
  83. package/dist/h2a-bridge.js +333 -0
  84. package/dist/h2a-bridge.js.map +1 -0
  85. package/dist/h2a-jobs.d.ts +235 -0
  86. package/dist/h2a-jobs.d.ts.map +1 -0
  87. package/dist/h2a-jobs.js +388 -0
  88. package/dist/h2a-jobs.js.map +1 -0
  89. package/dist/h2a-ping.d.ts +38 -0
  90. package/dist/h2a-ping.d.ts.map +1 -0
  91. package/dist/h2a-ping.js +58 -0
  92. package/dist/h2a-ping.js.map +1 -0
  93. package/dist/index.d.ts +98 -0
  94. package/dist/index.d.ts.map +1 -0
  95. package/dist/index.js +5887 -0
  96. package/dist/index.js.map +1 -0
  97. package/dist/interactive-throttle.d.ts +164 -0
  98. package/dist/interactive-throttle.d.ts.map +1 -0
  99. package/dist/interactive-throttle.js +194 -0
  100. package/dist/interactive-throttle.js.map +1 -0
  101. package/dist/lineage-client.d.ts +77 -0
  102. package/dist/lineage-client.d.ts.map +1 -0
  103. package/dist/lineage-client.js +117 -0
  104. package/dist/lineage-client.js.map +1 -0
  105. package/dist/lineage-lease.d.ts +152 -0
  106. package/dist/lineage-lease.d.ts.map +1 -0
  107. package/dist/lineage-lease.js +303 -0
  108. package/dist/lineage-lease.js.map +1 -0
  109. package/dist/llm-gateway-runtime/accounts.d.ts +48 -0
  110. package/dist/llm-gateway-runtime/accounts.d.ts.map +1 -0
  111. package/dist/llm-gateway-runtime/accounts.js +226 -0
  112. package/dist/llm-gateway-runtime/accounts.js.map +1 -0
  113. package/dist/llm-gateway-runtime/index.d.ts +4 -0
  114. package/dist/llm-gateway-runtime/index.d.ts.map +1 -0
  115. package/dist/llm-gateway-runtime/index.js +58 -0
  116. package/dist/llm-gateway-runtime/index.js.map +1 -0
  117. package/dist/llm-gateway-runtime/model-catalog.d.ts +36 -0
  118. package/dist/llm-gateway-runtime/model-catalog.d.ts.map +1 -0
  119. package/dist/llm-gateway-runtime/model-catalog.js +146 -0
  120. package/dist/llm-gateway-runtime/model-catalog.js.map +1 -0
  121. package/dist/llm-gateway-runtime/proxy-anthropic.d.ts +3 -0
  122. package/dist/llm-gateway-runtime/proxy-anthropic.d.ts.map +1 -0
  123. package/dist/llm-gateway-runtime/proxy-anthropic.js +139 -0
  124. package/dist/llm-gateway-runtime/proxy-anthropic.js.map +1 -0
  125. package/dist/llm-gateway-runtime/proxy-openai.d.ts +117 -0
  126. package/dist/llm-gateway-runtime/proxy-openai.d.ts.map +1 -0
  127. package/dist/llm-gateway-runtime/proxy-openai.js +1132 -0
  128. package/dist/llm-gateway-runtime/proxy-openai.js.map +1 -0
  129. package/dist/llm-gateway-runtime/session-ledger.d.ts +32 -0
  130. package/dist/llm-gateway-runtime/session-ledger.d.ts.map +1 -0
  131. package/dist/llm-gateway-runtime/session-ledger.js +62 -0
  132. package/dist/llm-gateway-runtime/session-ledger.js.map +1 -0
  133. package/dist/llm-gateway-runtime/sticky.d.ts +40 -0
  134. package/dist/llm-gateway-runtime/sticky.d.ts.map +1 -0
  135. package/dist/llm-gateway-runtime/sticky.js +254 -0
  136. package/dist/llm-gateway-runtime/sticky.js.map +1 -0
  137. package/dist/llm-mesh.d.ts +102 -0
  138. package/dist/llm-mesh.d.ts.map +1 -0
  139. package/dist/llm-mesh.js +433 -0
  140. package/dist/llm-mesh.js.map +1 -0
  141. package/dist/migrate-candidates.d.ts +35 -0
  142. package/dist/migrate-candidates.d.ts.map +1 -0
  143. package/dist/migrate-candidates.js +128 -0
  144. package/dist/migrate-candidates.js.map +1 -0
  145. package/dist/migrate.d.ts +125 -0
  146. package/dist/migrate.d.ts.map +1 -0
  147. package/dist/migrate.js +561 -0
  148. package/dist/migrate.js.map +1 -0
  149. package/dist/plugin-manifest.d.ts +143 -0
  150. package/dist/plugin-manifest.d.ts.map +1 -0
  151. package/dist/plugin-manifest.js +233 -0
  152. package/dist/plugin-manifest.js.map +1 -0
  153. package/dist/plugin.d.ts +274 -0
  154. package/dist/plugin.d.ts.map +1 -0
  155. package/dist/plugin.js +919 -0
  156. package/dist/plugin.js.map +1 -0
  157. package/dist/pod-liveness.d.ts +51 -0
  158. package/dist/pod-liveness.d.ts.map +1 -0
  159. package/dist/pod-liveness.js +80 -0
  160. package/dist/pod-liveness.js.map +1 -0
  161. package/dist/profile-menu.d.ts +7 -0
  162. package/dist/profile-menu.d.ts.map +1 -0
  163. package/dist/profile-menu.js +52 -0
  164. package/dist/profile-menu.js.map +1 -0
  165. package/dist/profiles.d.ts +23 -0
  166. package/dist/profiles.d.ts.map +1 -0
  167. package/dist/profiles.js +66 -0
  168. package/dist/profiles.js.map +1 -0
  169. package/dist/protocol-local.d.ts +27 -0
  170. package/dist/protocol-local.d.ts.map +1 -0
  171. package/dist/protocol-local.js +12 -0
  172. package/dist/protocol-local.js.map +1 -0
  173. package/dist/pty.d.ts +26 -0
  174. package/dist/pty.d.ts.map +1 -0
  175. package/dist/pty.js +45 -0
  176. package/dist/pty.js.map +1 -0
  177. package/dist/readiness.d.ts +38 -0
  178. package/dist/readiness.d.ts.map +1 -0
  179. package/dist/readiness.js +169 -0
  180. package/dist/readiness.js.map +1 -0
  181. package/dist/registry.d.ts +258 -0
  182. package/dist/registry.d.ts.map +1 -0
  183. package/dist/registry.js +570 -0
  184. package/dist/registry.js.map +1 -0
  185. package/dist/relaunch.d.ts +52 -0
  186. package/dist/relaunch.d.ts.map +1 -0
  187. package/dist/relaunch.js +76 -0
  188. package/dist/relaunch.js.map +1 -0
  189. package/dist/restore.d.ts +165 -0
  190. package/dist/restore.d.ts.map +1 -0
  191. package/dist/restore.js +530 -0
  192. package/dist/restore.js.map +1 -0
  193. package/dist/run.d.ts +29 -0
  194. package/dist/run.d.ts.map +1 -0
  195. package/dist/run.js +206 -0
  196. package/dist/run.js.map +1 -0
  197. package/dist/secrets.d.ts +25 -0
  198. package/dist/secrets.d.ts.map +1 -0
  199. package/dist/secrets.js +98 -0
  200. package/dist/secrets.js.map +1 -0
  201. package/dist/session-restore.d.ts +26 -0
  202. package/dist/session-restore.d.ts.map +1 -0
  203. package/dist/session-restore.js +122 -0
  204. package/dist/session-restore.js.map +1 -0
  205. package/dist/skills-sync.d.ts +126 -0
  206. package/dist/skills-sync.d.ts.map +1 -0
  207. package/dist/skills-sync.js +255 -0
  208. package/dist/skills-sync.js.map +1 -0
  209. package/dist/smoke.d.ts +23 -0
  210. package/dist/smoke.d.ts.map +1 -0
  211. package/dist/smoke.js +138 -0
  212. package/dist/smoke.js.map +1 -0
  213. package/dist/soft-refresh.d.ts +107 -0
  214. package/dist/soft-refresh.d.ts.map +1 -0
  215. package/dist/soft-refresh.js +426 -0
  216. package/dist/soft-refresh.js.map +1 -0
  217. package/dist/sync-status.d.ts +22 -0
  218. package/dist/sync-status.d.ts.map +1 -0
  219. package/dist/sync-status.js +41 -0
  220. package/dist/sync-status.js.map +1 -0
  221. package/dist/sync.d.ts +77 -0
  222. package/dist/sync.d.ts.map +1 -0
  223. package/dist/sync.js +302 -0
  224. package/dist/sync.js.map +1 -0
  225. package/dist/throttle-signatures.d.ts +43 -0
  226. package/dist/throttle-signatures.d.ts.map +1 -0
  227. package/dist/throttle-signatures.js +116 -0
  228. package/dist/throttle-signatures.js.map +1 -0
  229. package/dist/tmux.d.ts +286 -0
  230. package/dist/tmux.d.ts.map +1 -0
  231. package/dist/tmux.js +970 -0
  232. package/dist/tmux.js.map +1 -0
  233. package/dist/tunnel.d.ts +25 -0
  234. package/dist/tunnel.d.ts.map +1 -0
  235. package/dist/tunnel.js +127 -0
  236. package/dist/tunnel.js.map +1 -0
  237. package/dist/workspace-merge.d.ts +17 -0
  238. package/dist/workspace-merge.d.ts.map +1 -0
  239. package/dist/workspace-merge.js +153 -0
  240. package/dist/workspace-merge.js.map +1 -0
  241. package/dist/workspace-sync-incremental.d.ts +64 -0
  242. package/dist/workspace-sync-incremental.d.ts.map +1 -0
  243. package/dist/workspace-sync-incremental.js +199 -0
  244. package/dist/workspace-sync-incremental.js.map +1 -0
  245. package/dist/workspace-sync.d.ts +3 -0
  246. package/dist/workspace-sync.d.ts.map +1 -0
  247. package/dist/workspace-sync.js +187 -0
  248. package/dist/workspace-sync.js.map +1 -0
  249. package/dist/workspace.d.ts +70 -0
  250. package/dist/workspace.d.ts.map +1 -0
  251. package/dist/workspace.js +173 -0
  252. package/dist/workspace.js.map +1 -0
  253. package/package.json +44 -0
@@ -0,0 +1,414 @@
1
+ /**
2
+ * WP10 — handler for h2a `conductor-launch-request` envelopes (PURE core).
3
+ *
4
+ * The h2a maintainer (a2a-cli, h2a 0.68.0) owns the EMIT side: when a workspace
5
+ * has STALLED work AND no live conductor, h2a drops an envelope into `remote`'s
6
+ * h2a inbox. h2a NEVER spawns — `remote` is the executor. This module is the
7
+ * PURE decision core (parse + validate + select host + cooldown gate + task
8
+ * builder); the side-effecting wiring (PATH detection, registry/h2a probes,
9
+ * launch, inbox marking) lives in index.ts behind injectable seams.
10
+ *
11
+ * The on-disk envelope mirrors the standard h2a shape `{protocol, version, id,
12
+ * type, actor, to, body, createdAt}` (h2a-jobs.ts / h2a-bridge.ts README). The
13
+ * WP10 contract puts the payload on `body`:
14
+ * body.kind = "message"
15
+ * body.topic = "conductor-launch-request"
16
+ * body.request = { kind, workspaceId, hostPref, stalled[], reason }
17
+ * (we also tolerate the request fields spread directly onto `body` rather than
18
+ * nested under `body.request`, since the maintainer's exact nesting is not yet
19
+ * pinned — flagged for a2a-cli alignment).
20
+ *
21
+ * SECURITY: the conductor task is plain prose passed as a SINGLE argv token by
22
+ * the caller (buildDelegateArgs → startJob); it is NEVER concatenated into a
23
+ * `bash -lc` string. Nothing here shells out.
24
+ */
25
+ import { spawnSync } from "node:child_process";
26
+ import { createHash } from "node:crypto";
27
+ import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, statSync, writeFileSync, } from "node:fs";
28
+ import { join } from "node:path";
29
+ import { defaultLocalH2aRoot } from "./h2a-bridge.js";
30
+ /** The contract topic the maintainer emits under. */
31
+ export const CONDUCTOR_LAUNCH_TOPIC = "conductor-launch-request";
32
+ /**
33
+ * Default host preference order when the envelope omits one / lists only
34
+ * unknown hosts. Mirrors the maintainer's documented default
35
+ * (`['claude','codex','agy']`).
36
+ */
37
+ export const DEFAULT_HOST_PREF = [
38
+ "claude",
39
+ "codex",
40
+ "agy",
41
+ ];
42
+ function isDelegateHost(value) {
43
+ return value === "claude" || value === "codex" || value === "agy";
44
+ }
45
+ /**
46
+ * Normalize a raw hostPref: keep only known hosts, preserve the given order,
47
+ * and fall back to the default order when nothing usable remains. Pure.
48
+ */
49
+ function normalizeHostPref(raw) {
50
+ const hosts = Array.isArray(raw) ? raw.filter(isDelegateHost) : [];
51
+ return hosts.length > 0 ? hosts : [...DEFAULT_HOST_PREF];
52
+ }
53
+ /** Keep only well-formed stalled items (id + title required). Pure. */
54
+ function normalizeStalled(raw) {
55
+ if (!Array.isArray(raw))
56
+ return [];
57
+ const out = [];
58
+ for (const entry of raw) {
59
+ if (!entry || typeof entry !== "object")
60
+ continue;
61
+ const e = entry;
62
+ if (typeof e.id !== "string" || typeof e.title !== "string")
63
+ continue;
64
+ const item = { id: e.id, title: e.title };
65
+ if (typeof e.reason === "string")
66
+ item.reason = e.reason;
67
+ if (typeof e.since === "string")
68
+ item.since = e.since;
69
+ out.push(item);
70
+ }
71
+ return out;
72
+ }
73
+ /**
74
+ * Parse + validate an incoming `conductor-launch-request` envelope (a JSON
75
+ * string OR an already-parsed object) into a typed `ConductorLaunchRequest`.
76
+ * Returns undefined when the input is not a valid conductor-launch envelope:
77
+ * - not JSON / not an object,
78
+ * - body.kind !== "message" or body.topic !== "conductor-launch-request",
79
+ * - no workspaceId.
80
+ * Tolerates the request nested under `body.request` OR spread onto `body`.
81
+ * Pure (no fs / no clock), exported for tests.
82
+ */
83
+ export function parseConductorLaunchEnvelope(input) {
84
+ let root;
85
+ if (typeof input === "string") {
86
+ try {
87
+ root = JSON.parse(input);
88
+ }
89
+ catch {
90
+ return undefined;
91
+ }
92
+ }
93
+ else {
94
+ root = input;
95
+ }
96
+ if (!root || typeof root !== "object")
97
+ return undefined;
98
+ const body = root.body;
99
+ if (!body || typeof body !== "object")
100
+ return undefined;
101
+ const b = body;
102
+ if (b.kind !== "message" || b.topic !== CONDUCTOR_LAUNCH_TOPIC)
103
+ return undefined;
104
+ // The request is either nested (`body.request`) or spread onto `body`.
105
+ const reqRaw = b.request && typeof b.request === "object"
106
+ ? b.request
107
+ : b;
108
+ const workspaceId = reqRaw.workspaceId;
109
+ if (typeof workspaceId !== "string" || workspaceId.length === 0) {
110
+ return undefined;
111
+ }
112
+ return {
113
+ kind: "conductor-launch-request",
114
+ workspaceId,
115
+ hostPref: normalizeHostPref(reqRaw.hostPref),
116
+ stalled: normalizeStalled(reqRaw.stalled),
117
+ reason: typeof reqRaw.reason === "string" ? reqRaw.reason : "",
118
+ };
119
+ }
120
+ /**
121
+ * Pick the host to launch: the FIRST entry of `hostPref` that is in
122
+ * `availableHosts` (the CLIs found on PATH). Honors the preference ORDER, not
123
+ * the set's. Returns undefined when none of the preferred hosts is available.
124
+ * Pure, exported for tests.
125
+ */
126
+ export function selectHost(hostPref, availableHosts) {
127
+ for (const host of hostPref) {
128
+ if (availableHosts.has(host))
129
+ return host;
130
+ }
131
+ return undefined;
132
+ }
133
+ /**
134
+ * The launch gate, in priority order (each branch is mutually exclusive):
135
+ * 1. a conductor is already alive → SKIP (idempotency, the whole point),
136
+ * 2. there is no stalled work → SKIP (nothing to conduct),
137
+ * 3. a launch happened within the cooldown window → SKIP (watch-loop guard),
138
+ * 4. otherwise → LAUNCH.
139
+ * The live-conductor check wins over the cooldown so an idempotent skip is
140
+ * always reported as such. Pure (clock injected via `now`), exported for tests.
141
+ */
142
+ export function shouldLaunch(input) {
143
+ if (input.liveConductors > 0) {
144
+ return {
145
+ launch: false,
146
+ reason: `a conductor is already alive for ${input.request.workspaceId} (${input.liveConductors}) — idempotent skip`,
147
+ };
148
+ }
149
+ if (input.request.stalled.length === 0) {
150
+ return {
151
+ launch: false,
152
+ reason: "no stalled work to conduct — nothing to launch",
153
+ };
154
+ }
155
+ if (input.lastLaunchAt !== undefined &&
156
+ input.now - input.lastLaunchAt < input.cooldownMs) {
157
+ const mins = Math.ceil((input.cooldownMs - (input.now - input.lastLaunchAt)) / 60_000);
158
+ return {
159
+ launch: false,
160
+ reason: `within cooldown for ${input.request.workspaceId} (~${mins} min left)`,
161
+ };
162
+ }
163
+ return {
164
+ launch: true,
165
+ reason: `stalled work and no live conductor for ${input.request.workspaceId}`,
166
+ };
167
+ }
168
+ /**
169
+ * The task prompt for the delegated conductor. It instructs the agent to CLAIM
170
+ * the conductor role at boot (`h2a conductor claim`, if available) then conduct
171
+ * the stalled items. Returned as plain prose — the caller passes it as a SINGLE
172
+ * argv token (buildDelegateArgs → startJob); it is NEVER shell-concatenated.
173
+ * Pure, exported for tests.
174
+ */
175
+ export function buildConductorTask(request) {
176
+ const items = request.stalled.length > 0
177
+ ? request.stalled
178
+ .map((s) => {
179
+ const why = s.reason ? ` — ${s.reason}` : "";
180
+ return ` - [${s.id}] ${s.title}${why}`;
181
+ })
182
+ .join("\n")
183
+ : " (no specific items listed; discover the stalled work yourself)";
184
+ return [
185
+ `You are the CONDUCTOR for workspace ${request.workspaceId}.`,
186
+ "",
187
+ "BOOT STEP (do this FIRST, before anything else):",
188
+ " Claim the conductor role so peers know you own it. If the `h2a` CLI is",
189
+ " available, run: h2a conductor claim",
190
+ " (If `h2a` is not installed, proceed without claiming — best-effort.)",
191
+ "",
192
+ `Why you were launched: ${request.reason || "stalled work with no live conductor"}.`,
193
+ "",
194
+ "Stalled work to conduct:",
195
+ items,
196
+ "",
197
+ "Drive these items to completion: unblock, delegate, and follow up. When the",
198
+ "backlog is drained, release the conductor role (`h2a conductor release` if",
199
+ "available) and end your session.",
200
+ ].join("\n");
201
+ }
202
+ /**
203
+ * Normalize the root-commit set into the canonical string a2a-cli/track hash:
204
+ * ALL root commits (`git rev-list --max-parents=0 HEAD`), trimmed, de-duped,
205
+ * sorted ascending, joined by ",". A mono-root repo collapses to its single
206
+ * SHA. Invariant across clone / fork / path / machine (unlike a remote url).
207
+ * Pure, exported for tests.
208
+ */
209
+ export function normalizeRootCommits(shas) {
210
+ return [...new Set(shas.map((s) => s.trim()).filter((s) => s.length > 0))]
211
+ .sort()
212
+ .join(",");
213
+ }
214
+ /**
215
+ * Durable, git-shared workspace id — byte-identical to track + h2a 0.68's
216
+ * `durableWorkspaceId`:
217
+ *
218
+ * workspaceId = "ws:" + sha256hex( rootCommitSHA + "\n" + worktreeRelPath )
219
+ *
220
+ * where `rootCommitSHA` is {@link normalizeRootCommits}' output and
221
+ * `worktreeRelPath` is "" for the primary worktree, else the basename of
222
+ * `git rev-parse --git-dir` (the `.git/worktrees/<name>` dir) for a linked
223
+ * worktree. Pinned vectors (shared with track): ("abc","") →
224
+ * ws:edeaaff3… ; ("abc","my-feature") → ws:81a25e53…. Pure, exported for tests.
225
+ */
226
+ export function computeDurableWorkspaceId(rootCommitSHA, worktreeRelPath) {
227
+ const hex = createHash("sha256")
228
+ .update(`${rootCommitSHA}\n${worktreeRelPath}`, "utf8")
229
+ .digest("hex");
230
+ return `ws:${hex}`;
231
+ }
232
+ // ---------------------------------------------------------------------------
233
+ // Side-effecting seams (PATH detection, h2a probe, inbox read + processed
234
+ // marking, last-launch tracking). Each takes an injectable seam so index.ts
235
+ // stays thin and tests never shell out / touch the real ~/h2a-workspace.
236
+ // ---------------------------------------------------------------------------
237
+ /**
238
+ * Which delegate hosts (claude/codex/agy) are resolvable on PATH. The `which`
239
+ * seam is injectable; the default uses a login shell `command -v` (same probe
240
+ * as tmux.ts commandAvailable / delegate.ts defaultWhich), so it sees the same
241
+ * binaries the tmux windows would. Best-effort: a failing probe = not present.
242
+ */
243
+ export function detectAvailableHosts(which = defaultHostAvailable) {
244
+ const out = new Set();
245
+ for (const host of ["claude", "codex", "agy"]) {
246
+ if (which(host))
247
+ out.add(host);
248
+ }
249
+ return out;
250
+ }
251
+ function defaultHostAvailable(bin) {
252
+ try {
253
+ return (spawnSync("bash", ["-lc", `command -v -- ${bin}`], { stdio: "ignore" })
254
+ .status === 0);
255
+ }
256
+ catch {
257
+ return false;
258
+ }
259
+ }
260
+ export function defaultH2aRunner(args) {
261
+ try {
262
+ const probe = spawnSync("bash", ["-lc", "command -v -- h2a"], {
263
+ stdio: "ignore",
264
+ });
265
+ if (probe.status !== 0)
266
+ return undefined; // h2a not installed → degrade
267
+ const r = spawnSync("h2a", [...args], {
268
+ encoding: "utf8",
269
+ stdio: ["ignore", "pipe", "ignore"],
270
+ });
271
+ if (r.status !== 0)
272
+ return undefined;
273
+ return r.stdout;
274
+ }
275
+ catch {
276
+ return undefined;
277
+ }
278
+ }
279
+ /**
280
+ * Does h2a itself report a live conductor for `workspaceId`? Best-effort over
281
+ * `h2a discover` (whatever shape it prints — we only look for the durable id +
282
+ * a "conductor" mention near it). Returns:
283
+ * - true → h2a sees a conductor (definitely skip),
284
+ * - false → h2a ran and did NOT mention one,
285
+ * - undefined → h2a unavailable / unparseable (caller relies on the registry).
286
+ * Conservative substring match (the maintainer's discover output is not pinned
287
+ * — flagged for a2a-cli alignment). The runner is injectable.
288
+ */
289
+ export function h2aReportsLiveConductor(workspaceId, run = defaultH2aRunner) {
290
+ const out = run(["discover"]);
291
+ if (out === undefined)
292
+ return undefined;
293
+ // A line mentioning the workspace id, "conductor", AND connectionConfidence=active
294
+ // is the live signal. idle-uncertain/unknown are not considered live (h2a 0.70.0+).
295
+ for (const line of out.split("\n")) {
296
+ if (line.includes(workspaceId) &&
297
+ /conductor/i.test(line) &&
298
+ /\bactive\b/i.test(line))
299
+ return true;
300
+ }
301
+ // h2a ran but said nothing about a conductor for this workspace.
302
+ return false;
303
+ }
304
+ /**
305
+ * Read every `conductor-launch-request` envelope under `<localRoot>/inbox/**`
306
+ * (one dir level deep, the h2a layout — same as h2a-jobs.readInboxEnvelopes),
307
+ * parsed + validated. Skips already-processed ones (a sibling `.processed`
308
+ * stamp, see markProcessed). Missing store → []. Never throws on a bad file.
309
+ * The fs is isolated here so the parsing above stays pure.
310
+ */
311
+ export function readLaunchEnvelopes(localRoot = defaultLocalH2aRoot()) {
312
+ const inbox = join(localRoot, "inbox");
313
+ if (!existsSync(inbox))
314
+ return [];
315
+ const out = [];
316
+ for (const dir of readdirSync(inbox, { withFileTypes: true })) {
317
+ if (!dir.isDirectory())
318
+ continue;
319
+ const dirPath = join(inbox, dir.name);
320
+ for (const f of readdirSync(dirPath, { withFileTypes: true })) {
321
+ if (!f.isFile() || !f.name.endsWith(".json"))
322
+ continue;
323
+ const path = join(dirPath, f.name);
324
+ if (existsSync(processedStampPath(path)))
325
+ continue; // already handled
326
+ let raw;
327
+ let mtimeMs;
328
+ try {
329
+ raw = readFileSync(path, "utf8");
330
+ mtimeMs = statSync(path).mtimeMs;
331
+ }
332
+ catch {
333
+ continue;
334
+ }
335
+ const request = parseConductorLaunchEnvelope(raw);
336
+ if (request)
337
+ out.push({ path, mtimeMs, request });
338
+ }
339
+ }
340
+ return out;
341
+ }
342
+ /** The freshest (highest mtime) unprocessed launch envelope, or undefined. Pure. */
343
+ export function freshestLaunchEnvelope(envelopes) {
344
+ let best;
345
+ for (const e of envelopes) {
346
+ if (!best || e.mtimeMs > best.mtimeMs)
347
+ best = e;
348
+ }
349
+ return best;
350
+ }
351
+ /** Sibling stamp marking an envelope as processed (idempotency, never re-acted). */
352
+ function processedStampPath(envelopePath) {
353
+ return `${envelopePath}.processed`;
354
+ }
355
+ /**
356
+ * Idempotently mark an envelope processed by dropping a sibling `.processed`
357
+ * stamp next to it (we never DELETE the envelope — the bridge/h2a own cleanup,
358
+ * exactly like dropEnvelope's non-destructive contract). Best-effort: returns
359
+ * false on any fs error. `note` is a short human reason (dry-run vs launched).
360
+ */
361
+ export function markLaunchEnvelopeProcessed(envelopePath, note, nowMs = Date.now()) {
362
+ try {
363
+ writeFileSync(processedStampPath(envelopePath), `${JSON.stringify({ processedAt: new Date(nowMs).toISOString(), note })}\n`, "utf8");
364
+ return true;
365
+ }
366
+ catch {
367
+ return false;
368
+ }
369
+ }
370
+ /** Path of the per-workspace last-launch log under the h2a store. */
371
+ function launchLogPath(localRoot) {
372
+ return join(localRoot, "conductor-launch-log.json");
373
+ }
374
+ /** Read the last-launch epoch ms for `workspaceId`, or undefined. Best-effort. */
375
+ export function readLastLaunchAt(workspaceId, localRoot = defaultLocalH2aRoot()) {
376
+ try {
377
+ const log = JSON.parse(readFileSync(launchLogPath(localRoot), "utf8"));
378
+ const at = log.lastLaunchAt?.[workspaceId];
379
+ return typeof at === "number" && Number.isFinite(at) ? at : undefined;
380
+ }
381
+ catch {
382
+ return undefined;
383
+ }
384
+ }
385
+ /**
386
+ * Record `nowMs` as the last launch for `workspaceId` (so a watch loop honors
387
+ * the per-workspace cooldown). Best-effort: returns false on any fs error.
388
+ * Atomic-ish (tmp + rename) like the registry.
389
+ */
390
+ export function recordLaunchAt(workspaceId, nowMs = Date.now(), localRoot = defaultLocalH2aRoot()) {
391
+ try {
392
+ const path = launchLogPath(localRoot);
393
+ let log = { version: 1, lastLaunchAt: {} };
394
+ try {
395
+ const parsed = JSON.parse(readFileSync(path, "utf8"));
396
+ if (parsed.lastLaunchAt && typeof parsed.lastLaunchAt === "object") {
397
+ log = { version: 1, lastLaunchAt: { ...parsed.lastLaunchAt } };
398
+ }
399
+ }
400
+ catch {
401
+ // missing / corrupt → start fresh
402
+ }
403
+ log.lastLaunchAt[workspaceId] = nowMs;
404
+ mkdirSync(localRoot, { recursive: true });
405
+ const tmp = `${path}.tmp.${process.pid}`;
406
+ writeFileSync(tmp, `${JSON.stringify(log, null, 2)}\n`, "utf8");
407
+ renameSync(tmp, path);
408
+ return true;
409
+ }
410
+ catch {
411
+ return false;
412
+ }
413
+ }
414
+ //# sourceMappingURL=conductor-launch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conductor-launch.js","sourceRoot":"","sources":["../src/conductor-launch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,182 @@
1
+ import type { SessionTarget } from "./protocol-local.js";
2
+ /**
3
+ * How the CLI reaches the control-plane when the configured URL is not directly
4
+ * routable (no public ingress). When set, the CLI brings this tunnel up on
5
+ * demand (kubectl port-forward) at connect/attach/ls/migrate time — so the user
6
+ * never manages a port-forward by hand.
7
+ */
8
+ export type TunnelConfig = {
9
+ /** kubeconfig path (a leading ~ is expanded); defaults to kubectl's default. */
10
+ kubeconfig?: string;
11
+ namespace: string;
12
+ service: string;
13
+ localPort: number;
14
+ remotePort: number;
15
+ };
16
+ /**
17
+ * A named terminal window in `remote restore`. A LOCAL group lists `projects`
18
+ * (resumed as local tmux sessions). A REMOTE group (`remote: true`) has its tabs
19
+ * filled from the SCW control-plane's live sessions (attached via `--exec`).
20
+ */
21
+ export type LayoutGroup = {
22
+ title: string;
23
+ projects?: string[];
24
+ remote?: boolean;
25
+ };
26
+ /** Layout for `remote restore`: how recent local sessions map to windows/tabs. */
27
+ export type LayoutConfig = {
28
+ /** Only resume sessions touched within this many hours. */
29
+ maxAgeHours: number;
30
+ /** Max tabs per terminal window. */
31
+ maxPerWindow: number;
32
+ /** Number of shared round-robin windows for ungrouped projects. */
33
+ sharedWindows: number;
34
+ /** Per-project: how many recent sessions to resume (default `multiSessionDefault`). */
35
+ multiSession: Record<string, number>;
36
+ /**
37
+ * Fallback per-project cap when a project has no `multiSession` override.
38
+ * 1 = the old behaviour (one tab per project). <= 0 = no limit (resume EVERY
39
+ * live session of the project) — useful for a full-fleet `remote restore`.
40
+ */
41
+ multiSessionDefault: number;
42
+ /** Explicit windows; their projects leave the shared pool. */
43
+ groups: LayoutGroup[];
44
+ };
45
+ export declare const DEFAULT_LAYOUT: LayoutConfig;
46
+ /**
47
+ * One MCP server provided by an installed plugin package.
48
+ *
49
+ * `command` is always "node" and `args` the script's realpath: some packages
50
+ * (track@0.2.0) have an entrypoint guard that breaks when the script is run
51
+ * through the npm-global bin symlink, so the bare bin name must never be
52
+ * registered — see plugin.ts.
53
+ */
54
+ export type PluginMcp = {
55
+ name: string;
56
+ command: string;
57
+ args: string[];
58
+ /**
59
+ * Bin script path relative to the package dir (e.g. "dist/mcp.js") — used by
60
+ * `remote plugin sync` to recompute the realpath inside remote Pods, where
61
+ * the npm global root differs from the local one.
62
+ */
63
+ scriptRel?: string;
64
+ };
65
+ /**
66
+ * How a plugin is installed in a session Pod. Default (omitted) = `npm`
67
+ * (`npm i -g <pkg>@<version>`). `curl` pipes an installer script
68
+ * (`curl -fsSL <spec> | bash`) — e.g. a Go binary's install.sh. `script` runs
69
+ * an arbitrary shell line (from the user's own config). Lets non-npm tools be
70
+ * propagated the same way.
71
+ */
72
+ export type PluginInstall = {
73
+ method: "npm" | "curl" | "script";
74
+ /** curl: the installer URL; script: the shell command. Unused for npm. */
75
+ spec?: string;
76
+ };
77
+ /** A plugin propagated to sessions (npm pkg, or curl/script installer) + MCP(s). */
78
+ export type PluginEntry = {
79
+ pkg: string;
80
+ version: string;
81
+ mcp: PluginMcp[];
82
+ /** Install method; omitted ⇒ npm (pkg@version). */
83
+ install?: PluginInstall;
84
+ };
85
+ /**
86
+ * h2a launcher contract (opt-in): when a local session starts via `remote run`,
87
+ * also start `h2a mcp-serve` in a side tmux window so the agent is
88
+ * reachable/wakeable by the h2a file-based agent network (~/h2a-workspace/.h2a).
89
+ */
90
+ export type H2aConfig = {
91
+ /** Start the h2a window on every `remote run` (default false; `--h2a` forces one run). */
92
+ enabled?: boolean;
93
+ /** Command line run in the dedicated "h2a" window (default: DEFAULT_H2A_COMMAND). */
94
+ command?: string;
95
+ };
96
+ /** Default h2a side-window command (a2a-cli launcher contract). */
97
+ export declare const DEFAULT_H2A_COMMAND = "h2a mcp-serve --auto-open --auto-upgrade --wake local-tmux";
98
+ /**
99
+ * Local LLM gateway runtime policy. The credential/account material itself
100
+ * lives in ~/.sentropic/llm-mesh.json; this config only records whether remote
101
+ * should reactivate that gateway for local sessions and restore.
102
+ */
103
+ export type LlmMeshRuntimeConfig = {
104
+ /** Auto-inject/reactivate llm-mesh for local Claude sessions. Default false. */
105
+ enabled?: boolean;
106
+ };
107
+ export type TmuxProfileConfig = {
108
+ /** Remote-managed tmux profile name applied to local sessions. Default: remote. */
109
+ profile?: string;
110
+ };
111
+ export type RemoteCliConfig = {
112
+ defaultRemote?: string;
113
+ token?: string;
114
+ tunnel?: TunnelConfig;
115
+ /** Session target label (where the workload runs). Defaults to scaleway-kapsule. */
116
+ defaultTarget?: string;
117
+ /** Tool CLIs whose auth to bundle into deported sessions by default (scw, gh, …). */
118
+ defaultTools?: string[];
119
+ /** `remote restore` layout (windows/tabs from recent local sessions). */
120
+ layout?: Partial<LayoutConfig>;
121
+ /** Plugins installed via `remote plugin add` (synced to Pods via `remote plugin sync`). */
122
+ plugins?: PluginEntry[];
123
+ /** h2a launcher contract for `remote run` (opt-in side window). */
124
+ h2a?: H2aConfig;
125
+ /** Local LLM gateway runtime policy (credentials remain in ~/.sentropic). */
126
+ llmMesh?: LlmMeshRuntimeConfig;
127
+ /** Remote-managed tmux config profile for local tmux sessions. */
128
+ tmux?: TmuxProfileConfig;
129
+ /** P4 — default concurrency cap for delegated jobs (local AND remote). */
130
+ maxConcurrent?: number;
131
+ };
132
+ /** Default session target when none is configured/passed. */
133
+ export declare const DEFAULT_SESSION_TARGET: SessionTarget;
134
+ export declare function resolveConfigPath(): string;
135
+ export declare function normalizeRemoteUrl(rawUrl: string): string;
136
+ export declare function readRemoteConfig(): RemoteCliConfig;
137
+ export declare function writeRemoteConfig(config: RemoteCliConfig): void;
138
+ export declare function getDefaultRemote(): string | undefined;
139
+ export declare function setDefaultRemote(rawUrl: string): string;
140
+ export declare function clearDefaultRemote(): void;
141
+ export declare function getDefaultTarget(): SessionTarget;
142
+ export declare function setDefaultTarget(value: string): void;
143
+ export declare function getDefaultTools(): string[];
144
+ export declare function setDefaultTools(tools: string[]): void;
145
+ /** Plugins installed via `remote plugin add` (mirrors getDefaultTools). */
146
+ export declare function getPlugins(): PluginEntry[];
147
+ export declare function setPlugins(plugins: PluginEntry[]): void;
148
+ /** h2a config merged with defaults (enabled=false, default mcp-serve command). */
149
+ export declare function getH2aConfig(): Required<H2aConfig>;
150
+ export declare function setH2aConfig(h2a: H2aConfig): void;
151
+ export declare function getLlmMeshRuntimeConfig(): Required<LlmMeshRuntimeConfig>;
152
+ export declare function setLlmMeshRuntimeConfig(llmMesh: LlmMeshRuntimeConfig): void;
153
+ export declare function getTmuxProfileConfig(): Required<TmuxProfileConfig>;
154
+ export declare function setTmuxProfileConfig(tmux: TmuxProfileConfig): void;
155
+ /**
156
+ * P4 — the configured default concurrency cap for delegated jobs, or undefined
157
+ * when unset (the caller falls back to DEFAULT_MAX_CONCURRENT). The env override
158
+ * `REMOTE_MAX_CONCURRENT` wins so a conductor window can be tuned without writing
159
+ * config.
160
+ */
161
+ export declare function getMaxConcurrent(): number | undefined;
162
+ export declare function setMaxConcurrent(value: number): void;
163
+ /** Generous default age (hours) after which a stuck `running` job is swept → failed. */
164
+ export declare const DEFAULT_JOB_MAX_AGE_HOURS = 24;
165
+ /**
166
+ * Max age (hours) a delegated job may stay `running`/`awaiting-decision` before
167
+ * the reconciler sweeps it to `failed` (M2 — convergence: a job whose hook +
168
+ * liveness signal were both lost would otherwise occupy a slot forever).
169
+ * `REMOTE_JOB_MAX_AGE_HOURS` overrides; default is generous (24h) so a genuinely
170
+ * long-running interactive job is never killed prematurely.
171
+ */
172
+ export declare function getJobMaxAgeHours(): number;
173
+ export declare function getTunnel(): TunnelConfig | undefined;
174
+ export declare function setTunnel(tunnel: TunnelConfig): void;
175
+ export declare function clearTunnel(): void;
176
+ /** Layout config merged with defaults (used by `remote restore`). */
177
+ export declare function getLayoutConfig(): LayoutConfig;
178
+ export declare function setLayoutConfig(layout: Partial<LayoutConfig>): void;
179
+ export declare function getToken(): string | undefined;
180
+ export declare function setToken(value: string): void;
181
+ export declare function authHeaders(): Record<string, string>;
182
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}