@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,433 @@
1
+ /**
2
+ * llm-mesh — local LLM gateway management for solo-dev mode.
3
+ *
4
+ * Enrollment: `remote llm-mesh enroll codex` reads ~/.codex/auth.json
5
+ * (supports both raw OPENAI_API_KEY and ChatGPT Pro OAuth JWT) and writes
6
+ * ~/.sentropic/llm-mesh.json.
7
+ *
8
+ * Startup: `remote llm-mesh start` reads the config, starts the embedded
9
+ * gateway runtime as a background process, and prints the env vars to
10
+ * configure Claude Code.
11
+ *
12
+ * Config path: ~/.sentropic/llm-mesh.json (0600)
13
+ * PID file: ~/.sentropic/llm-mesh.pid
14
+ * Token file: ~/.sentropic/llm-mesh-token.json (0600, runtime metadata + derived gw-token)
15
+ * Seed file: ~/.sentropic/llm-mesh-seed (0600, sole durable gateway-token secret)
16
+ */
17
+ import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync, } from "node:fs";
18
+ import { homedir } from "node:os";
19
+ import { dirname, join } from "node:path";
20
+ import { fileURLToPath } from "node:url";
21
+ import { spawn } from "node:child_process";
22
+ import { randomBytes } from "node:crypto";
23
+ // ---------------------------------------------------------------------------
24
+ // Paths
25
+ // ---------------------------------------------------------------------------
26
+ export function sentropicDir() {
27
+ return join(homedir(), ".sentropic");
28
+ }
29
+ export function llmMeshConfigPath(dir) {
30
+ return join(dir ?? sentropicDir(), "llm-mesh.json");
31
+ }
32
+ export function llmMeshPidPath(dir) {
33
+ return join(dir ?? sentropicDir(), "llm-mesh.pid");
34
+ }
35
+ export function llmMeshTokenPath(dir) {
36
+ return join(dir ?? sentropicDir(), "llm-mesh-token.json");
37
+ }
38
+ export function llmMeshSeedPath(dir) {
39
+ return join(dir ?? sentropicDir(), "llm-mesh-seed");
40
+ }
41
+ export function llmMeshStickyPath(dir) {
42
+ return join(dir ?? sentropicDir(), "llm-mesh-sticky.json");
43
+ }
44
+ export function llmMeshLogPath(config, dir) {
45
+ return config?.logFile ?? join(dir ?? sentropicDir(), "llm-mesh.log");
46
+ }
47
+ // ---------------------------------------------------------------------------
48
+ // Config read/write
49
+ // ---------------------------------------------------------------------------
50
+ function readJson(path) {
51
+ try {
52
+ return JSON.parse(readFileSync(path, "utf8"));
53
+ }
54
+ catch {
55
+ return null;
56
+ }
57
+ }
58
+ function writeSecret(path, value) {
59
+ mkdirSync(dirname(path), { recursive: true });
60
+ const tmp = `${path}.tmp.${process.pid}`;
61
+ writeFileSync(tmp, JSON.stringify(value, null, 2) + "\n", { mode: 0o600 });
62
+ chmodSync(tmp, 0o600);
63
+ renameSync(tmp, path);
64
+ }
65
+ function writeSecretString(path, value) {
66
+ mkdirSync(dirname(path), { recursive: true });
67
+ const tmp = `${path}.tmp.${process.pid}`;
68
+ writeFileSync(tmp, value + "\n", { mode: 0o600 });
69
+ chmodSync(tmp, 0o600);
70
+ renameSync(tmp, path);
71
+ }
72
+ export function readLlmMeshConfig(dir) {
73
+ return readJson(llmMeshConfigPath(dir));
74
+ }
75
+ export function writeLlmMeshConfig(config, dir) {
76
+ writeSecret(llmMeshConfigPath(dir), config);
77
+ }
78
+ export function readOrCreateLlmMeshSeed(dir) {
79
+ const path = llmMeshSeedPath(dir);
80
+ try {
81
+ const seed = readFileSync(path, "utf8").trim();
82
+ if (seed) {
83
+ try {
84
+ const mode = statSync(path).mode & 0o777;
85
+ if (mode !== 0o600)
86
+ chmodSync(path, 0o600);
87
+ }
88
+ catch {
89
+ // best effort only
90
+ }
91
+ return seed;
92
+ }
93
+ }
94
+ catch {
95
+ // create below
96
+ }
97
+ const seed = randomBytes(32).toString("base64url");
98
+ writeSecretString(path, seed);
99
+ return seed;
100
+ }
101
+ // ---------------------------------------------------------------------------
102
+ // JWT helpers (no signature verification — expiry check only)
103
+ // ---------------------------------------------------------------------------
104
+ export function jwtExpiry(token) {
105
+ try {
106
+ const parts = token.split(".");
107
+ if (parts.length < 2)
108
+ return null;
109
+ const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
110
+ if (typeof payload.exp !== "number")
111
+ return null;
112
+ return new Date(payload.exp * 1000);
113
+ }
114
+ catch {
115
+ return null;
116
+ }
117
+ }
118
+ export function isTokenExpired(token, graceSeconds = 300) {
119
+ const exp = jwtExpiry(token);
120
+ if (!exp)
121
+ return false; // non-JWT token — assume valid
122
+ return exp.getTime() - graceSeconds * 1000 < Date.now();
123
+ }
124
+ /**
125
+ * Read Codex credentials from ~/.codex/auth.json and produce an LlmMeshAccount.
126
+ * Supports:
127
+ * - OPENAI_API_KEY (raw sk-... key, pay-per-token tier)
128
+ * - tokens.access_token (ChatGPT Pro OAuth JWT, subscription flat-rate tier)
129
+ */
130
+ export function enrollCodexAccount(codexDir) {
131
+ const authPath = join(codexDir ?? join(homedir(), ".codex"), "auth.json");
132
+ const auth = readJson(authPath);
133
+ if (!auth) {
134
+ throw new Error(`Codex auth file not found or unreadable: ${authPath}`);
135
+ }
136
+ // Raw API key path (standard pay-per-token)
137
+ if (typeof auth.OPENAI_API_KEY === "string" && auth.OPENAI_API_KEY.trim()) {
138
+ return {
139
+ id: "codex-api",
140
+ provider: "openai",
141
+ label: "Codex (API key)",
142
+ token: auth.OPENAI_API_KEY.trim(),
143
+ };
144
+ }
145
+ // OAuth path (ChatGPT Pro / subscription)
146
+ const accessToken = auth.tokens?.access_token;
147
+ if (!accessToken || !accessToken.trim()) {
148
+ throw new Error(`No usable credential in ${authPath}: OPENAI_API_KEY is null/absent ` +
149
+ `and tokens.access_token is missing. Run \`codex auth login\` first.`);
150
+ }
151
+ const expiresAt = jwtExpiry(accessToken);
152
+ const refreshToken = auth.tokens?.refresh_token;
153
+ const account = {
154
+ id: "codex-oauth",
155
+ provider: "openai",
156
+ label: "Codex (ChatGPT Pro OAuth)",
157
+ token: accessToken.trim(),
158
+ };
159
+ if (refreshToken)
160
+ account.refreshToken = refreshToken;
161
+ if (expiresAt)
162
+ account.expiresAt = expiresAt.toISOString();
163
+ return account;
164
+ }
165
+ /**
166
+ * Attempt to refresh an account's OAuth access token using its refresh_token.
167
+ * Returns the updated account, or the original if refresh is not applicable
168
+ * (no refresh_token, or already a raw API key).
169
+ */
170
+ export async function refreshAccountToken(account) {
171
+ if (!account.refreshToken)
172
+ return account;
173
+ if (!isTokenExpired(account.token))
174
+ return account;
175
+ const resp = await fetch("https://auth.openai.com/oauth/token", {
176
+ method: "POST",
177
+ headers: { "content-type": "application/x-www-form-urlencoded" },
178
+ body: new URLSearchParams({
179
+ grant_type: "refresh_token",
180
+ refresh_token: account.refreshToken,
181
+ client_id: "app_EMoamEEZ73f0CkXaXp7hrann",
182
+ }),
183
+ });
184
+ if (!resp.ok) {
185
+ throw new Error(`Token refresh failed (${resp.status}): ${await resp.text()}`);
186
+ }
187
+ const data = (await resp.json());
188
+ if (!data.access_token)
189
+ throw new Error("Token refresh: no access_token in response");
190
+ const expiresAt = jwtExpiry(data.access_token);
191
+ return {
192
+ ...account,
193
+ token: data.access_token,
194
+ ...(expiresAt ? { expiresAt: expiresAt.toISOString() } : {}),
195
+ };
196
+ }
197
+ // ---------------------------------------------------------------------------
198
+ // Gateway process management
199
+ // ---------------------------------------------------------------------------
200
+ /** Resolve the embedded gateway runtime entry point relative to this package. */
201
+ export function gatewayScriptPath() {
202
+ const thisFile = fileURLToPath(import.meta.url);
203
+ return join(dirname(thisFile), "llm-gateway-runtime", "index.js");
204
+ }
205
+ /** Build GATEWAY_ACCOUNTS from the llm-mesh config accounts */
206
+ function buildGatewayAccountsEnv(accounts) {
207
+ return JSON.stringify(accounts.map((a) => ({
208
+ id: a.id,
209
+ provider: a.provider,
210
+ label: a.label,
211
+ token: a.token,
212
+ ...(a.refreshToken ? { refreshToken: a.refreshToken } : {}),
213
+ ...(a.expiresAt ? { expiresAt: a.expiresAt } : {}),
214
+ })));
215
+ }
216
+ function isUnsupportedClaudeOAuthAccount(account) {
217
+ return (account.provider === "anthropic" &&
218
+ (account.authType === "bearer" ||
219
+ account.id === "claude-oauth" ||
220
+ account.token.startsWith("sk-ant-oat")));
221
+ }
222
+ /**
223
+ * Start the llm-gateway as a detached background process.
224
+ * Returns the PID, port, and a gw-token for Claude Code.
225
+ */
226
+ export async function startGateway(config, opts = {}) {
227
+ const port = config.port ?? 3002;
228
+ const logFile = llmMeshLogPath(config);
229
+ const gatewayScript = gatewayScriptPath();
230
+ if (!existsSync(gatewayScript)) {
231
+ throw new Error(`Gateway script not found: ${gatewayScript}\n` +
232
+ `Run \`npm run build -w @sentropic/remote-cli\` first.`);
233
+ }
234
+ mkdirSync(sentropicDir(), { recursive: true });
235
+ // Refresh expired tokens before launch
236
+ const refreshedAccounts = [];
237
+ for (const acc of config.accounts) {
238
+ try {
239
+ refreshedAccounts.push(await refreshAccountToken(acc));
240
+ }
241
+ catch (err) {
242
+ if (opts.verbose) {
243
+ process.stderr.write(`[remote] llm-mesh: token refresh failed for ${acc.id}: ${String(err)}\n`);
244
+ }
245
+ refreshedAccounts.push(acc);
246
+ }
247
+ }
248
+ const gatewayAccounts = refreshedAccounts.filter((account) => !isUnsupportedClaudeOAuthAccount(account));
249
+ if (gatewayAccounts.length === 0) {
250
+ throw new Error("llm-mesh has no gateway-supported accounts: Claude Code OAuth cannot be proxied through Anthropic /v1/messages yet");
251
+ }
252
+ const gatewayEnv = {
253
+ ...process.env,
254
+ GATEWAY_ACCOUNTS: buildGatewayAccountsEnv(gatewayAccounts),
255
+ LLM_GATEWAY_TOKEN_SEED: readOrCreateLlmMeshSeed(),
256
+ LLM_GATEWAY_STICKY_FILE: llmMeshStickyPath(),
257
+ PORT: String(port),
258
+ };
259
+ // Start detached, piping stdout+stderr to logFile
260
+ const { openSync } = await import("node:fs");
261
+ const logFd = openSync(logFile, "a");
262
+ const child = spawn("node", [gatewayScript], {
263
+ detached: true,
264
+ stdio: ["ignore", logFd, logFd],
265
+ env: gatewayEnv,
266
+ });
267
+ child.unref();
268
+ const pid = child.pid;
269
+ // Write PID file
270
+ writeFileSync(llmMeshPidPath(), String(pid) + "\n");
271
+ // Wait for the gateway to be ready
272
+ const baseUrl = `http://localhost:${port}`;
273
+ await waitForHealth(baseUrl, 10_000);
274
+ // Acquire a session token
275
+ const sessionResp = await fetch(`${baseUrl}/v1/session`, {
276
+ method: "POST",
277
+ headers: { "content-type": "application/json" },
278
+ body: JSON.stringify({ sessionId: "local-dev" }),
279
+ });
280
+ if (!sessionResp.ok) {
281
+ throw new Error(`Session acquisition failed: ${sessionResp.status}`);
282
+ }
283
+ const session = (await sessionResp.json());
284
+ const gatewayToken = session.gatewayToken;
285
+ if (!gatewayToken)
286
+ throw new Error("No gatewayToken in session response");
287
+ // Persist the token (secret)
288
+ writeSecret(llmMeshTokenPath(), { gatewayToken, baseUrl, pid });
289
+ // Persist refreshed tokens back to config
290
+ writeLlmMeshConfig({ ...config, accounts: refreshedAccounts });
291
+ return { pid, port, gatewayToken };
292
+ }
293
+ async function waitForHealth(baseUrl, timeoutMs) {
294
+ const deadline = Date.now() + timeoutMs;
295
+ while (Date.now() < deadline) {
296
+ try {
297
+ const resp = await fetch(`${baseUrl}/health`);
298
+ if (resp.ok)
299
+ return;
300
+ }
301
+ catch {
302
+ // not ready yet
303
+ }
304
+ await new Promise((r) => setTimeout(r, 200));
305
+ }
306
+ throw new Error(`Gateway did not become healthy within ${timeoutMs}ms`);
307
+ }
308
+ /** Read the running gateway's PID. Returns null if not running. */
309
+ export function readGatewayPid(dir) {
310
+ try {
311
+ const raw = readFileSync(llmMeshPidPath(dir), "utf8").trim();
312
+ const pid = parseInt(raw, 10);
313
+ if (isNaN(pid))
314
+ return null;
315
+ // Check if the process is still alive
316
+ process.kill(pid, 0);
317
+ return pid;
318
+ }
319
+ catch {
320
+ return null;
321
+ }
322
+ }
323
+ function configuredGatewayBaseUrl(dir) {
324
+ const config = readLlmMeshConfig(dir);
325
+ if (!config)
326
+ return null;
327
+ return `http://localhost:${config.port ?? 3002}`;
328
+ }
329
+ /**
330
+ * Returns {ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN} for the running local
331
+ * gateway, or null if not running or token file absent.
332
+ *
333
+ * Used by `remote run` to auto-inject the gateway env into every tmux session
334
+ * (interactive + headless) so all Claude sessions + their subagents use the gateway.
335
+ */
336
+ export function readLlmMeshSessionEnv(dir) {
337
+ try {
338
+ const raw = readFileSync(llmMeshTokenPath(dir), "utf8");
339
+ const { gatewayToken, baseUrl, pid } = JSON.parse(raw);
340
+ if (!gatewayToken || !baseUrl)
341
+ return null;
342
+ // Verify the gateway process is still alive
343
+ try {
344
+ process.kill(pid, 0);
345
+ }
346
+ catch {
347
+ return null;
348
+ }
349
+ return {
350
+ ANTHROPIC_BASE_URL: baseUrl,
351
+ ANTHROPIC_AUTH_TOKEN: gatewayToken,
352
+ // Claude Code subagents may re-read API-key style env instead of the
353
+ // auth-token env used by the parent process. Keep both pointed at the
354
+ // same opaque gateway token; do not write Claude config.
355
+ ANTHROPIC_API_KEY: gatewayToken,
356
+ };
357
+ }
358
+ catch {
359
+ return null;
360
+ }
361
+ }
362
+ /**
363
+ * Acquire a fresh in-memory gateway token from the running local gateway.
364
+ * Gateway tokens are intentionally not durable; after a gateway restart,
365
+ * llm-mesh-token.json may point at a token the new process does not know.
366
+ */
367
+ export async function acquireLlmMeshSessionEnv(dir) {
368
+ try {
369
+ let baseUrl;
370
+ let pid;
371
+ try {
372
+ const raw = readFileSync(llmMeshTokenPath(dir), "utf8");
373
+ const tokenFile = JSON.parse(raw);
374
+ baseUrl = tokenFile.baseUrl;
375
+ pid = tokenFile.pid;
376
+ }
377
+ catch {
378
+ baseUrl = configuredGatewayBaseUrl(dir) ?? undefined;
379
+ pid = readGatewayPid(dir) ?? undefined;
380
+ }
381
+ if (!baseUrl || !pid)
382
+ return null;
383
+ try {
384
+ process.kill(pid, 0);
385
+ }
386
+ catch {
387
+ return null;
388
+ }
389
+ const sessionResp = await fetch(`${baseUrl}/v1/session`, {
390
+ method: "POST",
391
+ headers: { "content-type": "application/json" },
392
+ body: JSON.stringify({ sessionId: "local-dev" }),
393
+ });
394
+ if (!sessionResp.ok)
395
+ return null;
396
+ const session = (await sessionResp.json());
397
+ if (!session.gatewayToken)
398
+ return null;
399
+ writeSecret(llmMeshTokenPath(dir), {
400
+ gatewayToken: session.gatewayToken,
401
+ baseUrl,
402
+ pid,
403
+ });
404
+ return {
405
+ ANTHROPIC_BASE_URL: baseUrl,
406
+ ANTHROPIC_AUTH_TOKEN: session.gatewayToken,
407
+ ANTHROPIC_API_KEY: session.gatewayToken,
408
+ };
409
+ }
410
+ catch {
411
+ return null;
412
+ }
413
+ }
414
+ /** Stop the running gateway. */
415
+ export function stopGateway(dir) {
416
+ const pid = readGatewayPid(dir);
417
+ if (!pid)
418
+ return { stopped: false };
419
+ try {
420
+ process.kill(pid, "SIGTERM");
421
+ }
422
+ catch {
423
+ // already dead
424
+ }
425
+ try {
426
+ unlinkSync(llmMeshPidPath(dir));
427
+ }
428
+ catch {
429
+ // best-effort cleanup
430
+ }
431
+ return { stopped: true, pid };
432
+ }
433
+ //# sourceMappingURL=llm-mesh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-mesh.js","sourceRoot":"","sources":["../src/llm-mesh.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Discovery of local CLI sessions that are candidates for migration to a remote
3
+ * workspace. Scans the claude conversation store (`~/.claude/projects/<encoded>/`)
4
+ * and, for each project, reports the real cwd (read from the conversation), last
5
+ * activity, conversation count/size, whether it is a git repo (cleanly
6
+ * migratable), and whether it is already linked to a remote workspace.
7
+ *
8
+ * This powers `remote migrate ls` (list) and `remote migrate pick` (interactive
9
+ * selection) so a user can move sessions to the cluster progressively, choosing
10
+ * which ones, instead of cd-ing into each project by hand.
11
+ */
12
+ export type MigrationCandidate = {
13
+ /** Real project working directory (from the conversation's cwd field). */
14
+ readonly path: string;
15
+ /** Encoded dir name under ~/.claude/projects. */
16
+ readonly encodedDir: string;
17
+ /** mtime (ms) of the most-recent conversation — proxy for last activity. */
18
+ readonly lastActivity: number;
19
+ /** Number of conversation .jsonl files for this project. */
20
+ readonly convCount: number;
21
+ /** Total bytes of the conversation .jsonl files. */
22
+ readonly sizeBytes: number;
23
+ /** Whether the cwd is a usable git repo (clean migration via .gitignore). */
24
+ readonly isGit: boolean;
25
+ /** Whether the cwd still exists locally. */
26
+ readonly exists: boolean;
27
+ /** Whether the cwd is already linked to a remote workspace. */
28
+ readonly linked: boolean;
29
+ };
30
+ export declare function listMigrationCandidates(home?: string): MigrationCandidate[];
31
+ /** Human-readable size (KiB/MiB). */
32
+ export declare function humanSize(bytes: number): string;
33
+ /** Relative age from an mtime (ms) given "now" (ms). */
34
+ export declare function humanAge(mtimeMs: number, nowMs: number): string;
35
+ //# sourceMappingURL=migrate-candidates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate-candidates.d.ts","sourceRoot":"","sources":["../src/migrate-candidates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,4EAA4E;IAC5E,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,4DAA4D;IAC5D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,oDAAoD;IACpD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,4CAA4C;IAC5C,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B,CAAC;AA0CF,wBAAgB,uBAAuB,CACrC,IAAI,GAAE,MAAkB,GACvB,kBAAkB,EAAE,CA+CtB;AAED,qCAAqC;AACrC,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAG/C;AAED,wDAAwD;AACxD,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAQ/D"}
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Discovery of local CLI sessions that are candidates for migration to a remote
3
+ * workspace. Scans the claude conversation store (`~/.claude/projects/<encoded>/`)
4
+ * and, for each project, reports the real cwd (read from the conversation), last
5
+ * activity, conversation count/size, whether it is a git repo (cleanly
6
+ * migratable), and whether it is already linked to a remote workspace.
7
+ *
8
+ * This powers `remote migrate ls` (list) and `remote migrate pick` (interactive
9
+ * selection) so a user can move sessions to the cluster progressively, choosing
10
+ * which ones, instead of cd-ing into each project by hand.
11
+ */
12
+ import { closeSync, existsSync, openSync, readSync, readdirSync, statSync } from "node:fs";
13
+ import { homedir } from "node:os";
14
+ import { join } from "node:path";
15
+ import { spawnSync } from "node:child_process";
16
+ /** Read the `cwd` field from the first conversation entry that has one. */
17
+ function readCwdFromJsonl(file) {
18
+ let fd;
19
+ try {
20
+ fd = openSync(file, "r");
21
+ const buf = Buffer.alloc(64 * 1024);
22
+ const bytes = readSync(fd, buf, 0, buf.length, 0);
23
+ const text = buf.subarray(0, bytes).toString("utf8");
24
+ for (const line of text.split("\n")) {
25
+ if (!line.includes('"cwd"'))
26
+ continue;
27
+ try {
28
+ const obj = JSON.parse(line);
29
+ if (typeof obj.cwd === "string" && obj.cwd.startsWith("/"))
30
+ return obj.cwd;
31
+ }
32
+ catch {
33
+ // partial last line / non-JSON — keep scanning
34
+ }
35
+ }
36
+ }
37
+ catch {
38
+ // unreadable — fall through
39
+ }
40
+ finally {
41
+ if (fd !== undefined)
42
+ closeSync(fd);
43
+ }
44
+ return undefined;
45
+ }
46
+ /** Best-effort decode of claude's project-dir encoding (slashes → dashes). */
47
+ function decodePath(encodedDir) {
48
+ return "/" + encodedDir.replace(/^-/, "").replace(/-/g, "/");
49
+ }
50
+ function isGitRepo(cwd) {
51
+ if (!existsSync(cwd))
52
+ return false;
53
+ const r = spawnSync("git", ["rev-parse", "--is-inside-work-tree"], {
54
+ cwd,
55
+ encoding: "utf8",
56
+ stdio: ["ignore", "pipe", "ignore"],
57
+ });
58
+ return r.status === 0 && r.stdout.trim() === "true";
59
+ }
60
+ export function listMigrationCandidates(home = homedir()) {
61
+ const projectsRoot = join(home, ".claude", "projects");
62
+ if (!existsSync(projectsRoot))
63
+ return [];
64
+ const out = [];
65
+ for (const entry of readdirSync(projectsRoot, { withFileTypes: true })) {
66
+ if (!entry.isDirectory())
67
+ continue;
68
+ const dir = join(projectsRoot, entry.name);
69
+ let jsonls;
70
+ try {
71
+ jsonls = readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
72
+ }
73
+ catch {
74
+ continue;
75
+ }
76
+ if (jsonls.length === 0)
77
+ continue;
78
+ let lastActivity = 0;
79
+ let sizeBytes = 0;
80
+ let newestFile = jsonls[0];
81
+ for (const f of jsonls) {
82
+ try {
83
+ const st = statSync(join(dir, f));
84
+ sizeBytes += st.size;
85
+ if (st.mtimeMs > lastActivity) {
86
+ lastActivity = st.mtimeMs;
87
+ newestFile = f;
88
+ }
89
+ }
90
+ catch {
91
+ // skip unreadable
92
+ }
93
+ }
94
+ const path = readCwdFromJsonl(join(dir, newestFile)) ?? decodePath(entry.name);
95
+ const exists = existsSync(path);
96
+ out.push({
97
+ path,
98
+ encodedDir: entry.name,
99
+ lastActivity,
100
+ convCount: jsonls.length,
101
+ sizeBytes,
102
+ isGit: isGitRepo(path),
103
+ exists,
104
+ linked: exists && existsSync(join(path, ".remote", "workspace.json")),
105
+ });
106
+ }
107
+ return out.sort((a, b) => b.lastActivity - a.lastActivity);
108
+ }
109
+ /** Human-readable size (KiB/MiB). */
110
+ export function humanSize(bytes) {
111
+ if (bytes >= 1024 * 1024)
112
+ return `${(bytes / 1024 / 1024).toFixed(1)}M`;
113
+ return `${(bytes / 1024).toFixed(0)}K`;
114
+ }
115
+ /** Relative age from an mtime (ms) given "now" (ms). */
116
+ export function humanAge(mtimeMs, nowMs) {
117
+ const s = Math.max(0, Math.round((nowMs - mtimeMs) / 1000));
118
+ if (s < 90)
119
+ return `${s}s`;
120
+ const m = Math.round(s / 60);
121
+ if (m < 90)
122
+ return `${m}m`;
123
+ const h = Math.round(m / 60);
124
+ if (h < 36)
125
+ return `${h}h`;
126
+ return `${Math.round(h / 24)}d`;
127
+ }
128
+ //# sourceMappingURL=migrate-candidates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate-candidates.js","sourceRoot":"","sources":["../src/migrate-candidates.ts"],"names":[],"mappings":"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"}