@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,255 @@
1
+ /**
2
+ * `remote plugin sync-skills` — propagate the LOCAL user's Claude Code skills
3
+ * and plugin state into each live session Pod's `$HOME/.claude/`, so delegated /
4
+ * remote claude sessions get the same capabilities (superpowers, track, h2a,
5
+ * graphify, sent-tech-design, …) the operator has locally.
6
+ *
7
+ * APPROACH — "copy the resolved cache" (the chosen DEFAULT). We tar a short,
8
+ * explicit WHITELIST of skill+plugin paths and untar it into the Pod. This is
9
+ * deterministic: the Pod gets byte-for-byte the same resolved plugin cache the
10
+ * operator already vetted locally, with no network/marketplace fetch in-Pod.
11
+ * Reversible fork (NOT implemented — documented for the conductor): instead of
12
+ * shipping the cache, re-install marketplaces in-Pod (`claude plugin
13
+ * marketplace add … && claude plugin install …`). That re-resolves remotely
14
+ * (non-deterministic, needs network + auth in the Pod) and is therefore the
15
+ * non-default. If we ever want it, it slots in as an alternate plan builder
16
+ * here; the CLI surface stays the same.
17
+ *
18
+ * CRITICAL SAFETY — we NEVER tar the whole `~/.claude` (it holds settings.json,
19
+ * .credentials.json, OAuth tokens, project transcripts under projects/, and
20
+ * ~/.claude.json). Only the four paths in SKILLS_SYNC_WHITELIST are archived,
21
+ * each a leaf path so no broader directory can sweep a secret in with it. The
22
+ * SAFETY tests assert no credential/transcript path is ever a tar member.
23
+ *
24
+ * Payloads are argv ARRAYS (tar argv, kubectl argv) — never a `bash -lc` string
25
+ * with interpolated paths — so a $HOME (or any path) with shell metacharacters
26
+ * is just a single argument, never a parsed shell word. The archive itself
27
+ * rides stdin (`kubectl exec -i … -- tar -x`), so no file content is ever
28
+ * interpolated either.
29
+ *
30
+ * Idempotent: re-running untars over the existing tree (`--overwrite`), so the
31
+ * Pod's skills/plugins converge to the local state on every run.
32
+ */
33
+ import { spawn, spawnSync } from "node:child_process";
34
+ import { homedir } from "node:os";
35
+ import { join } from "node:path";
36
+ import { listRemoteSessions } from "./attach.js";
37
+ import { getTunnel } from "./config.js";
38
+ // ---------------------------------------------------------------------------
39
+ // Pure helpers (exported for tests)
40
+ // ---------------------------------------------------------------------------
41
+ /**
42
+ * The ONLY paths synced to Pods, relative to `$HOME`. Skills dir + the three
43
+ * plugin-state pieces that make the resolved plugin cache deterministic. Each
44
+ * is a leaf path: no entry is a parent of a secret file (so tarring it can
45
+ * never drag settings.json / .credentials.json / transcripts along). Anything
46
+ * outside this list — including the rest of ~/.claude/plugins (blocklist.json,
47
+ * known_marketplaces.json, plugin-catalog-cache.json, data/) — is excluded.
48
+ */
49
+ export const SKILLS_SYNC_WHITELIST = [
50
+ ".claude/skills",
51
+ ".claude/plugins/installed_plugins.json",
52
+ ".claude/plugins/marketplaces",
53
+ ".claude/plugins/cache",
54
+ ];
55
+ /** The explicit whitelist as a fresh array (callers cannot mutate the source). */
56
+ export function skillsSyncWhitelist() {
57
+ return [...SKILLS_SYNC_WHITELIST];
58
+ }
59
+ /**
60
+ * `tar` argv that archives ONLY the whitelisted paths, relative to `$HOME`, as
61
+ * a gzip stream on stdout (`-f -`). `-C <home>` keeps members relative so they
62
+ * untar cleanly into the Pod's `$HOME`. `--ignore-failed-read` lets a partial
63
+ * local install still sync (a missing member is skipped, not fatal). Members
64
+ * follow `--` so a leading-dash path can never be mistaken for a flag.
65
+ */
66
+ export function buildSkillsTarArgs(home) {
67
+ return [
68
+ "-c",
69
+ "-z",
70
+ "--ignore-failed-read",
71
+ "-C",
72
+ home,
73
+ "-f",
74
+ "-",
75
+ "--",
76
+ ...skillsSyncWhitelist(),
77
+ ];
78
+ }
79
+ /**
80
+ * In-Pod `tar` argv: extract the gzip stream from stdin (`-f -`) into the Pod's
81
+ * `$HOME` (`-C <podHome>`), `--overwrite` so a re-run replaces the existing
82
+ * skills/plugins in place (idempotent). No member is named — extraction takes
83
+ * whatever the archive carries, and the archive only ever carries the
84
+ * whitelist (constrained on the tar side).
85
+ */
86
+ export function buildPodUntarArgs(podHome) {
87
+ return ["-x", "-z", "--overwrite", "-C", podHome, "-f", "-"];
88
+ }
89
+ /** Default Pod `$HOME` — the session-agent container runs as root. */
90
+ const DEFAULT_POD_HOME = "/root";
91
+ /**
92
+ * Compose the local-tar | pod-untar plan for one Pod. Pure: it builds the two
93
+ * argv arrays and a dry-run line, but spawns nothing — the actual transfer is
94
+ * behind the `runSkillsSync` seam so tests never shell out.
95
+ */
96
+ export function buildSkillsSyncPlan(input) {
97
+ const { home, pod } = input;
98
+ const podHome = pod.podHome ?? DEFAULT_POD_HOME;
99
+ const tarArgs = buildSkillsTarArgs(home);
100
+ const untarArgs = buildPodUntarArgs(podHome);
101
+ const podName = `session-${pod.sessionId}`;
102
+ const dryRun = `${podName} (${pod.profile}): tar ${tarArgs.join(" ")} ` +
103
+ `| kubectl exec -i ${podName} -- tar ${untarArgs.join(" ")} ` +
104
+ `[whitelist: ${skillsSyncWhitelist().join(", ")}]`;
105
+ return {
106
+ pod: podName,
107
+ sessionId: pod.sessionId,
108
+ profile: pod.profile,
109
+ tar: { cmd: "tar", args: tarArgs },
110
+ untar: { cmd: "tar", args: untarArgs },
111
+ whitelist: skillsSyncWhitelist(),
112
+ dryRun,
113
+ };
114
+ }
115
+ /**
116
+ * Resolve which live sessions to sync. `--all` => every session; `--pod <ref>`
117
+ * => the single session whose id (or `session-<id>` Pod name) matches. Throws
118
+ * when neither is given, or when `--pod` matches nothing live.
119
+ */
120
+ export function selectSyncPods(sessions, opts) {
121
+ if (opts.all) {
122
+ return sessions.map((s) => ({ sessionId: s.id, profile: s.profile }));
123
+ }
124
+ if (opts.pod) {
125
+ const id = opts.pod.startsWith("session-")
126
+ ? opts.pod.slice("session-".length)
127
+ : opts.pod;
128
+ const match = sessions.find((s) => s.id === id);
129
+ if (!match) {
130
+ throw new Error(`no live session matches --pod "${opts.pod}"`);
131
+ }
132
+ return [{ sessionId: match.id, profile: match.profile }];
133
+ }
134
+ throw new Error("select sessions with --pod <name> or --all");
135
+ }
136
+ // ---------------------------------------------------------------------------
137
+ // Spawn seam (thin — tests stub this, never shell out)
138
+ // ---------------------------------------------------------------------------
139
+ function expandHome(p) {
140
+ return p.startsWith("~") ? join(homedir(), p.slice(1)) : p;
141
+ }
142
+ function kubeEnv(tunnel) {
143
+ const env = { ...process.env };
144
+ if (tunnel.kubeconfig)
145
+ env.KUBECONFIG = expandHome(tunnel.kubeconfig);
146
+ return env;
147
+ }
148
+ const spawnSkillsSync = (plan, tunnel) => new Promise((resolve, reject) => {
149
+ const kubectlArgs = [
150
+ "-n",
151
+ tunnel.namespace,
152
+ "exec",
153
+ "-i",
154
+ plan.pod,
155
+ "-c",
156
+ "session-agent",
157
+ "--",
158
+ plan.untar.cmd,
159
+ ...plan.untar.args,
160
+ ];
161
+ const env = kubeEnv(tunnel);
162
+ const tar = spawn(plan.tar.cmd, plan.tar.args, {
163
+ stdio: ["ignore", "pipe", "pipe"],
164
+ });
165
+ const kube = spawn("kubectl", kubectlArgs, {
166
+ stdio: ["pipe", "inherit", "pipe"],
167
+ env,
168
+ });
169
+ let tarErr = "";
170
+ let kubeErr = "";
171
+ tar.stderr.on("data", (d) => {
172
+ tarErr += d.toString();
173
+ });
174
+ kube.stderr.on("data", (d) => {
175
+ kubeErr += d.toString();
176
+ });
177
+ tar.on("error", reject);
178
+ kube.on("error", reject);
179
+ tar.stdout.pipe(kube.stdin);
180
+ let tarDone = false;
181
+ let kubeDone = false;
182
+ let failed = false;
183
+ const settle = () => {
184
+ if (tarDone && kubeDone && !failed)
185
+ resolve();
186
+ };
187
+ tar.on("close", (code) => {
188
+ tarDone = true;
189
+ if (code !== 0 && !failed) {
190
+ failed = true;
191
+ reject(new Error(`tar exited ${code}: ${tarErr.trim().slice(0, 200)}`));
192
+ return;
193
+ }
194
+ settle();
195
+ });
196
+ kube.on("close", (code) => {
197
+ kubeDone = true;
198
+ if (code !== 0 && !failed) {
199
+ failed = true;
200
+ reject(new Error(`kubectl exec ${plan.pod} exited ${code}: ${kubeErr.trim().slice(0, 200)}`));
201
+ return;
202
+ }
203
+ settle();
204
+ });
205
+ });
206
+ // ---------------------------------------------------------------------------
207
+ // Command
208
+ // ---------------------------------------------------------------------------
209
+ /**
210
+ * `remote plugin sync-skills [--pod <name>|--all] [--dry-run]` — copy the local
211
+ * Claude Code skills + plugin cache (whitelist only) into the selected live
212
+ * session Pod(s). `--dry-run` prints the tar/exec plan and transfers nothing.
213
+ */
214
+ export async function syncSkills(url, opts, stderr = process.stderr, run = spawnSkillsSync) {
215
+ const tunnel = getTunnel();
216
+ if (!tunnel) {
217
+ throw new Error("plugin sync-skills needs a tunnel configured (remote config tunnel …)");
218
+ }
219
+ const sessions = await listRemoteSessions(url);
220
+ if (sessions.length === 0) {
221
+ stderr.write("[remote] no live remote sessions to sync\n");
222
+ return;
223
+ }
224
+ const pods = selectSyncPods(sessions, opts);
225
+ const home = homedir();
226
+ if (opts.dryRun) {
227
+ stderr.write(`[remote] sync-skills DRY-RUN — whitelist (relative to $HOME): ${skillsSyncWhitelist().join(", ")}\n`);
228
+ for (const pod of pods) {
229
+ stderr.write(` ${buildSkillsSyncPlan({ home, pod }).dryRun}\n`);
230
+ }
231
+ stderr.write("[remote] dry-run: nothing transferred\n");
232
+ return;
233
+ }
234
+ // Fail fast if local tar is missing (clearer than a spawn ENOENT mid-loop).
235
+ if (spawnSync("tar", ["--version"], { stdio: "ignore" }).status !== 0) {
236
+ throw new Error("local `tar` not found — required to archive the skills cache");
237
+ }
238
+ let failures = 0;
239
+ for (const pod of pods) {
240
+ const plan = buildSkillsSyncPlan({ home, pod });
241
+ stderr.write(`[remote] ${plan.sessionId} (${plan.profile}): sync-skills…\n`);
242
+ try {
243
+ await run(plan, tunnel);
244
+ stderr.write(` skills/plugins synced (${plan.whitelist.length} whitelist path(s)) -> ${plan.pod}:$HOME\n`);
245
+ }
246
+ catch (error) {
247
+ failures++;
248
+ stderr.write(` sync-skills FAILED: ${String(error).slice(0, 200)}\n`);
249
+ }
250
+ }
251
+ stderr.write(`[remote] sync-skills done: ${pods.length} pod(s)${failures > 0 ? `, ${failures} failure(s)` : ""}\n`);
252
+ if (failures > 0)
253
+ process.exitCode = 1;
254
+ }
255
+ //# sourceMappingURL=skills-sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills-sync.js","sourceRoot":"","sources":["../src/skills-sync.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { CliProfile, SessionTarget } from "./protocol-local.js";
2
+ import { type AuthBundle } from "./auth-bundle.js";
3
+ import { type AuthRefreshResult } from "./auth-refresh.js";
4
+ export type SmokeRemoteProfileOptions = {
5
+ readonly profile: CliProfile;
6
+ readonly baseUrl: string;
7
+ readonly target?: SessionTarget;
8
+ readonly displayName?: string;
9
+ readonly timeoutMs?: number;
10
+ readonly auth?: boolean;
11
+ readonly authRefresh?: boolean;
12
+ readonly fetchImpl?: typeof fetch;
13
+ readonly collectAuth?: (profile: CliProfile) => Promise<AuthBundle>;
14
+ readonly ensureAuthFresh?: (profile: CliProfile) => Promise<AuthRefreshResult>;
15
+ };
16
+ export type SmokeRemoteProfileResult = {
17
+ readonly profile: CliProfile;
18
+ readonly sessionId: string;
19
+ readonly terminalId: string;
20
+ readonly shell: string;
21
+ };
22
+ export declare function smokeRemoteProfile(options: SmokeRemoteProfileOptions): Promise<SmokeRemoteProfileResult>;
23
+ //# sourceMappingURL=smoke.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smoke.d.ts","sourceRoot":"","sources":["../src/smoke.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EAEV,aAAa,EAEd,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAChC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IAClC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IACpE,QAAQ,CAAC,eAAe,CAAC,EAAE,CACzB,OAAO,EAAE,UAAU,KAChB,OAAO,CAAC,iBAAiB,CAAC,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,CAAC;AA2GF,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,wBAAwB,CAAC,CAgEnC"}
package/dist/smoke.js ADDED
@@ -0,0 +1,138 @@
1
+ import { createRemoteSession, stopRemoteSession } from "./attach.js";
2
+ import { assertRequiredAuthBundle, collectProfileAuth, } from "./auth-bundle.js";
3
+ import { ensureProfileAuthFresh, } from "./auth-refresh.js";
4
+ function joinUrl(base, path) {
5
+ return `${base.replace(/\/$/, "")}${path}`;
6
+ }
7
+ function parseSseEvents(buffer) {
8
+ const events = [];
9
+ const chunks = buffer.split("\n\n");
10
+ const rest = chunks.pop() ?? "";
11
+ for (const chunk of chunks) {
12
+ if (!chunk.trim())
13
+ continue;
14
+ let eventName;
15
+ const dataLines = [];
16
+ for (const line of chunk.split("\n")) {
17
+ if (line.startsWith("event:"))
18
+ eventName = line.slice(6).trim();
19
+ else if (line.startsWith("data:"))
20
+ dataLines.push(line.slice(5).trim());
21
+ }
22
+ if (dataLines.length === 0)
23
+ continue;
24
+ events.push({
25
+ ...(eventName !== undefined ? { event: eventName } : {}),
26
+ data: dataLines.join("\n"),
27
+ });
28
+ }
29
+ return { events, rest };
30
+ }
31
+ async function waitForTerminalOpened(options) {
32
+ const controller = new AbortController();
33
+ let reader;
34
+ let timedOut = false;
35
+ const timer = setTimeout(() => {
36
+ timedOut = true;
37
+ controller.abort();
38
+ }, options.timeoutMs);
39
+ try {
40
+ const response = await options.fetchImpl(joinUrl(options.baseUrl, `/sessions/${options.sessionId}/events`), {
41
+ headers: { accept: "text/event-stream" },
42
+ signal: controller.signal,
43
+ });
44
+ if (!response.ok || !response.body) {
45
+ throw new Error(`[remote] smoke event stream returned ${response.status} ${response.statusText}`);
46
+ }
47
+ reader = response.body.getReader();
48
+ const decoder = new TextDecoder("utf-8");
49
+ let buffer = "";
50
+ for (;;) {
51
+ const { value, done } = await reader.read();
52
+ if (done)
53
+ break;
54
+ buffer += decoder.decode(value, { stream: true });
55
+ const { events, rest } = parseSseEvents(buffer);
56
+ buffer = rest;
57
+ for (const ev of events) {
58
+ if (ev.event &&
59
+ ev.event !== "terminal.opened" &&
60
+ ev.event !== "terminal.exited") {
61
+ continue;
62
+ }
63
+ const envelope = JSON.parse(ev.data);
64
+ if (envelope.type === "terminal.opened") {
65
+ return envelope.payload;
66
+ }
67
+ if (envelope.type === "terminal.exited") {
68
+ const payload = envelope.payload;
69
+ throw new Error(`[remote] smoke session ${options.sessionId} exited before terminal.opened (exitCode=${payload.exitCode ?? "unknown"})`);
70
+ }
71
+ }
72
+ }
73
+ throw new Error(`[remote] smoke event stream ended before terminal.opened for ${options.sessionId}`);
74
+ }
75
+ catch (error) {
76
+ if (timedOut) {
77
+ throw new Error(`[remote] smoke timed out waiting for terminal.opened for ${options.sessionId}`);
78
+ }
79
+ throw error;
80
+ }
81
+ finally {
82
+ clearTimeout(timer);
83
+ controller.abort();
84
+ await reader?.cancel().catch(() => { });
85
+ }
86
+ }
87
+ export async function smokeRemoteProfile(options) {
88
+ const fetchImpl = options.fetchImpl ?? fetch;
89
+ let credentials;
90
+ if (options.auth !== false) {
91
+ if (options.authRefresh !== false) {
92
+ await (options.ensureAuthFresh ?? ensureProfileAuthFresh)(options.profile);
93
+ }
94
+ const bundle = await (options.collectAuth ?? collectProfileAuth)(options.profile);
95
+ assertRequiredAuthBundle(options.profile, bundle);
96
+ if (Object.keys(bundle).length > 0)
97
+ credentials = bundle;
98
+ }
99
+ let sessionId;
100
+ let result;
101
+ let failure;
102
+ try {
103
+ sessionId = (await createRemoteSession(options.baseUrl, {
104
+ profile: options.profile,
105
+ target: options.target ?? "k3s",
106
+ displayName: options.displayName ?? `smoke-${options.profile}-${Date.now()}`,
107
+ ...(credentials ? { credentials } : {}),
108
+ }, fetchImpl)).id;
109
+ const opened = await waitForTerminalOpened({
110
+ baseUrl: options.baseUrl,
111
+ sessionId,
112
+ timeoutMs: options.timeoutMs ?? 120_000,
113
+ fetchImpl,
114
+ });
115
+ result = {
116
+ profile: options.profile,
117
+ sessionId,
118
+ terminalId: opened.terminalId,
119
+ shell: opened.shell,
120
+ };
121
+ }
122
+ catch (error) {
123
+ failure = error;
124
+ }
125
+ if (sessionId) {
126
+ try {
127
+ await stopRemoteSession(options.baseUrl, sessionId, "remote-profile-smoke", fetchImpl);
128
+ }
129
+ catch (error) {
130
+ if (!failure)
131
+ failure = error;
132
+ }
133
+ }
134
+ if (failure)
135
+ throw failure;
136
+ return result;
137
+ }
138
+ //# sourceMappingURL=smoke.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smoke.js","sourceRoot":"","sources":["../src/smoke.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Soft credential refresh: push fresh local creds INTO a running session Pod and
3
+ * relaunch the CLI in place — WITHOUT recreating the Pod (keeps HOME parity, the
4
+ * conversation, the node, no image pull). Fixes the recurring ~8h token logout
5
+ * (the CLI can't self-refresh OAuth in a headless Pod). Also patches the auth
6
+ * Secret so the fresh token survives a future Pod restart.
7
+ *
8
+ * Steps (all via kubectl against the configured tunnel):
9
+ * 1. materialize each bundled cred file into $HOME/<rel> in the Pod,
10
+ * 2. patch session-<id>-auth Secret keys (durability),
11
+ * 3. respawn the Pod's tmux `main` pane: `<cli> --resume <newestConv>` with a
12
+ * UTF-8 locale, dropping to a shell on exit (never kills the session).
13
+ *
14
+ * Unchanged-creds gating (`skipIfUnchanged`, used by `refresh --all/--watch`):
15
+ * the respawn INTERRUPTS the Pod's CLI, so it must only happen when the pushed
16
+ * creds actually differ. We sha256 the bundle and compare it with the previous
17
+ * pass (`previousHash`, in-memory --watch state) and with the hash recorded in
18
+ * the Pod ($HOME/.remote-creds.sha256, written after every push). Identical
19
+ * creds = silent no-op: nothing pushed, no Secret patch, NO respawn.
20
+ */
21
+ import { type HealthResult, type ProbeableTool } from "./cred-health.js";
22
+ /** HOME-relative file in the Pod recording the sha256 of the last pushed bundle. */
23
+ export declare const CREDS_HASH_FILE = ".remote-creds.sha256";
24
+ /**
25
+ * Deterministic sha256 of an auth bundle (profile + sorted rel -> base64 value),
26
+ * SKIPPING config-only rels (see CONFIG_ONLY_RELS). Values stay opaque: the
27
+ * hash never leaks any secret material.
28
+ */
29
+ export declare function hashAuthBundle(profile: string, bundle: Readonly<Record<string, string>>): string;
30
+ export type SoftRefreshResult = {
31
+ /** false = creds identical to the Pod's last push — nothing pushed, NO respawn. */
32
+ changed: boolean;
33
+ /** sha256 of the local bundle — feed back as `previousHash` on the next pass. */
34
+ hash: string;
35
+ filesPushed: string[];
36
+ secretKeysPatched: string[];
37
+ convId: string | undefined;
38
+ respawned: boolean;
39
+ };
40
+ export type SoftRefreshOptions = {
41
+ /**
42
+ * Compare the bundle hash with `previousHash` and/or the hash recorded in the
43
+ * Pod, and no-op (no push, no Secret patch, NO respawn) when identical.
44
+ */
45
+ skipIfUnchanged?: boolean;
46
+ /** Bundle hash from the previous pass (in-memory --watch state): when it matches, skip without even reading the Pod. */
47
+ previousHash?: string;
48
+ stderr?: NodeJS.WriteStream;
49
+ };
50
+ /**
51
+ * Push the profile's fresh creds into the Pod, patch the Secret, and relaunch
52
+ * the CLI in place. `bundle` is the already-collected creds (rel -> content).
53
+ */
54
+ export declare function softRefreshSession(sessionId: string, profile: string, options?: SoftRefreshOptions): Promise<SoftRefreshResult>;
55
+ /** Result of a per-pod, per-tool probe→push pass. */
56
+ export type ToolHealthAction = {
57
+ readonly tool: ProbeableTool;
58
+ readonly health: HealthResult;
59
+ /** true when ok:false drove a re-bundle+push of this tool's creds. */
60
+ readonly pushed: boolean;
61
+ /** HOME-relative files materialized into the Pod (empty when not pushed / none local). */
62
+ readonly filesPushed: ReadonlyArray<string>;
63
+ readonly secretKeysPatched: ReadonlyArray<string>;
64
+ };
65
+ /**
66
+ * Injectable seams so the executor is unit-testable WITHOUT shelling out to
67
+ * kubectl or reading ~/. Production defaults wire the real plumbing.
68
+ */
69
+ export type ToolHealthDeps = {
70
+ /** Run the argv-safe probe in the Pod (default: execPodArgv against the tunnel). */
71
+ exec: (argv: ReadonlyArray<string>) => {
72
+ status: number;
73
+ stdout: string;
74
+ };
75
+ /** Re-bundle the LOCAL creds for the tools (default: collectToolAuth). */
76
+ collect: (tools: ReadonlyArray<string>) => Promise<{
77
+ bundle: Record<string, string>;
78
+ bundled: string[];
79
+ }>;
80
+ /** Materialize one base64 file into the Pod's $HOME (default: execPod base64 -d). */
81
+ materialize: (rel: string, base64: string) => void;
82
+ /** Patch one Secret data key with a base64 value (default: kubectl patch). */
83
+ patchSecretKey: (key: string, base64: string) => void;
84
+ stderr?: {
85
+ write: (s: string) => unknown;
86
+ };
87
+ };
88
+ /**
89
+ * Probe ONE covered tool in a live Pod and, if it's unauthenticated, push the
90
+ * tool's LOCAL creds (re-bundle + materialize + Secret patch — the same
91
+ * mechanism as today, an extra trigger). Pure-ish: all IO is injected via
92
+ * `deps`. Returns what happened (probe result + whether/what was pushed).
93
+ * Exported for tests.
94
+ */
95
+ export declare function probeAndPushToolHealth(tool: ProbeableTool, deps: ToolHealthDeps): Promise<ToolHealthAction>;
96
+ /**
97
+ * Production wiring for `probeAndPushToolHealth` against a configured tunnel +
98
+ * live pod. Builds the default `ToolHealthDeps` (real kubectl exec / patch /
99
+ * collectToolAuth) and probes EACH covered tool, pushing on a 401. Best-effort:
100
+ * a probe/push error for one tool is logged and the others continue. Returns the
101
+ * per-tool actions. NOT pure (does IO); the pure decision lives in
102
+ * `probeAndPushToolHealth` + cred-health. Used by the watch loop.
103
+ */
104
+ export declare function probePodCredHealth(sessionId: string, tools?: ReadonlyArray<string>, options?: {
105
+ stderr?: NodeJS.WriteStream;
106
+ }): Promise<ToolHealthAction[]>;
107
+ //# sourceMappingURL=soft-refresh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"soft-refresh.d.ts","sourceRoot":"","sources":["../src/soft-refresh.ts"],"names":[],"mappings":"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"}