@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
package/dist/run.js ADDED
@@ -0,0 +1,206 @@
1
+ import { serve } from "@hono/node-server";
2
+ import { createNodeWebSocket } from "@hono/node-ws";
3
+ import { REMOTE_PROTOCOL_VERSION, REMOTE_SCHEMA_VERSION, } from "./protocol-local.js";
4
+ import { Hono } from "hono";
5
+ import { streamSSE } from "hono/streaming";
6
+ import { resolveProfile, withResume } from "./profiles.js";
7
+ import { nodePtySpawner } from "./pty.js";
8
+ function defaultRandomId(prefix) {
9
+ const random = Math.floor(Math.random() * 1e12)
10
+ .toString(36)
11
+ .padStart(8, "0");
12
+ return `${prefix}-${random}`;
13
+ }
14
+ const CONTROL_PLANE_ACTOR = {
15
+ id: "remote-cli",
16
+ kind: "control-plane",
17
+ displayName: "Remote CLI",
18
+ };
19
+ const AGENT_ACTOR = {
20
+ id: "remote-cli-agent",
21
+ kind: "session-agent",
22
+ displayName: "Remote CLI Agent",
23
+ };
24
+ function buildEnvelope(runtime, type, payload, randomId, clock, actor = AGENT_ACTOR) {
25
+ return {
26
+ protocolVersion: REMOTE_PROTOCOL_VERSION,
27
+ schemaVersion: REMOTE_SCHEMA_VERSION,
28
+ eventId: randomId("evt"),
29
+ sessionId: runtime.sessionId,
30
+ sequence: runtime.sequence++,
31
+ type,
32
+ occurredAt: clock().toISOString(),
33
+ correlationId: `cli-${runtime.sessionId}`,
34
+ actor,
35
+ payload,
36
+ };
37
+ }
38
+ export async function run(options) {
39
+ const profile = withResume(resolveProfile(options.profile), options.resume);
40
+ const randomId = options.randomId ?? defaultRandomId;
41
+ const clock = options.clock ?? (() => new Date());
42
+ const spawner = options.spawner ?? nodePtySpawner;
43
+ const stdin = options.stdin ?? process.stdin;
44
+ const stdout = options.stdout ?? process.stdout;
45
+ const cwd = options.cwd ?? process.cwd();
46
+ const initialCols = options.initialSize?.cols ?? stdout.columns ?? 80;
47
+ const initialRows = options.initialSize?.rows ?? stdout.rows ?? 24;
48
+ const startupArgs = options.startupArgs ?? [];
49
+ const handle = spawner({
50
+ command: profile.command,
51
+ args: [...profile.args, ...startupArgs],
52
+ cwd,
53
+ env: { ...(options.env ?? process.env) },
54
+ cols: initialCols,
55
+ rows: initialRows,
56
+ });
57
+ const sessionId = randomId("sess");
58
+ const terminalId = randomId("term");
59
+ const subscribers = new Set();
60
+ const runtime = {
61
+ sessionId,
62
+ profile,
63
+ handle,
64
+ sequence: 0,
65
+ exited: false,
66
+ };
67
+ const broadcast = (envelope) => {
68
+ for (const subscriber of subscribers)
69
+ subscriber(envelope);
70
+ };
71
+ // Forward PTY output to host stdout AND broadcast as terminal.output.
72
+ handle.onData((chunk) => {
73
+ stdout.write(chunk);
74
+ broadcast(buildEnvelope(runtime, "terminal.output", {
75
+ terminalId,
76
+ stream: "stdout",
77
+ data: chunk,
78
+ encoding: "utf8",
79
+ }, randomId, clock));
80
+ });
81
+ // Forward host stdin to the PTY.
82
+ if (stdin.isTTY) {
83
+ stdin.setRawMode?.(true);
84
+ }
85
+ stdin.resume();
86
+ stdin.on("data", (data) => {
87
+ const text = typeof data === "string" ? data : data.toString("utf8");
88
+ handle.write(text);
89
+ });
90
+ // Resize PTY when the host terminal resizes.
91
+ const onResize = () => {
92
+ handle.resize(stdout.columns ?? initialCols, stdout.rows ?? initialRows);
93
+ };
94
+ stdout.on?.("resize", onResize);
95
+ // Open control-plane in-process for remote attach.
96
+ const app = new Hono();
97
+ const nodeWs = createNodeWebSocket({ app });
98
+ app.get("/healthz", (c) => c.json({ ok: true, sessionId, profile: profile.profile }));
99
+ app.get(`/sessions/${sessionId}`, (c) => c.json({
100
+ session: {
101
+ id: sessionId,
102
+ profile: profile.profile,
103
+ target: "k3s",
104
+ workspacePath: cwd,
105
+ createdAt: clock().toISOString(),
106
+ createdBy: CONTROL_PLANE_ACTOR,
107
+ },
108
+ }));
109
+ app.get(`/sessions/${sessionId}/events`, (c) => {
110
+ return streamSSE(c, async (stream) => {
111
+ const queue = [];
112
+ let notify = null;
113
+ const subscriber = (envelope) => {
114
+ queue.push(envelope);
115
+ const wake = notify;
116
+ notify = null;
117
+ wake?.();
118
+ };
119
+ subscribers.add(subscriber);
120
+ stream.onAbort(() => {
121
+ subscribers.delete(subscriber);
122
+ });
123
+ try {
124
+ while (!stream.aborted) {
125
+ while (queue.length > 0 && !stream.aborted) {
126
+ const envelope = queue.shift();
127
+ if (!envelope)
128
+ break;
129
+ await stream.writeSSE({
130
+ event: envelope.type,
131
+ data: JSON.stringify(envelope),
132
+ id: envelope.eventId,
133
+ });
134
+ }
135
+ if (stream.aborted)
136
+ break;
137
+ await new Promise((resolve) => {
138
+ notify = resolve;
139
+ });
140
+ }
141
+ }
142
+ finally {
143
+ subscribers.delete(subscriber);
144
+ }
145
+ });
146
+ });
147
+ app.post(`/sessions/${sessionId}/terminal/input`, async (c) => {
148
+ const body = (await c.req.json());
149
+ if (typeof body.data === "string")
150
+ handle.write(body.data);
151
+ return c.json({ accepted: true }, 202);
152
+ });
153
+ const port = options.port ?? 0;
154
+ const server = serve({ fetch: app.fetch, port, hostname: "127.0.0.1" });
155
+ nodeWs.injectWebSocket(server);
156
+ let actualPort = port;
157
+ const address = server.address();
158
+ if (address && typeof address === "object") {
159
+ actualPort = address.port;
160
+ }
161
+ else {
162
+ await new Promise((resolve, reject) => {
163
+ server.once("listening", () => {
164
+ const addr = server.address();
165
+ if (addr && typeof addr === "object")
166
+ actualPort = addr.port;
167
+ resolve();
168
+ });
169
+ server.once("error", reject);
170
+ });
171
+ }
172
+ // Emit terminal.opened announcement.
173
+ broadcast(buildEnvelope(runtime, "terminal.opened", { terminalId, shell: profile.command }, randomId, clock));
174
+ // Wire exit.
175
+ let resolveExit;
176
+ const exit = new Promise((resolve) => {
177
+ resolveExit = resolve;
178
+ });
179
+ handle.onExit((event) => {
180
+ if (runtime.exited)
181
+ return;
182
+ runtime.exited = true;
183
+ broadcast(buildEnvelope(runtime, "terminal.exited", {
184
+ terminalId,
185
+ exitCode: event.exitCode,
186
+ ...(event.signal !== undefined
187
+ ? { signal: String(event.signal) }
188
+ : {}),
189
+ }, randomId, clock));
190
+ if (stdin.isTTY) {
191
+ stdin.setRawMode?.(false);
192
+ }
193
+ server.close();
194
+ resolveExit(event);
195
+ });
196
+ return {
197
+ sessionId,
198
+ port: actualPort,
199
+ exit,
200
+ async stop() {
201
+ handle.kill();
202
+ await exit;
203
+ },
204
+ };
205
+ }
206
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Secret audit — what auth/credentials were actually transmitted to a session.
3
+ *
4
+ * Source of truth is the LIVE per-session Kubernetes Secret (`session-<id>-auth`)
5
+ * read via kubectl over the configured tunnel — NEVER a local "what I sent"
6
+ * record (which drifts on refresh / a second machine / a control-plane restart).
7
+ * Only KEY NAMES are read (go-template emits keys, never values); values are
8
+ * never decoded or printed. Sanitized Secret keys are mapped back to their
9
+ * original home-relative paths via the known auth registries, and classified by
10
+ * tool with a "broad" flag for account-wide cloud creds.
11
+ */
12
+ export type SecretEntry = {
13
+ /** Original home-relative path (or the raw Secret key if unrecognized). */
14
+ readonly path: string;
15
+ readonly tool: string;
16
+ readonly broad: boolean;
17
+ };
18
+ /**
19
+ * Read the auth-Secret KEY NAMES transmitted to a session (values never read).
20
+ * Returns undefined if there is no configured tunnel / the secret can't be read.
21
+ */
22
+ export declare function transmittedSecrets(sessionId: string): SecretEntry[] | undefined;
23
+ /** One-line summary for `remote status` (e.g. "claude +scw +aws⚠", or "—"). */
24
+ export declare function secretsSummary(sessionId: string): string;
25
+ //# sourceMappingURL=secrets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secrets.d.ts","sourceRoot":"","sources":["../src/secrets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AA+BH,MAAM,MAAM,WAAW,GAAG;IACxB,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB,CAAC;AAcF;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,EAAE,GAAG,SAAS,CA+B/E;AAED,+EAA+E;AAC/E,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAYxD"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Secret audit — what auth/credentials were actually transmitted to a session.
3
+ *
4
+ * Source of truth is the LIVE per-session Kubernetes Secret (`session-<id>-auth`)
5
+ * read via kubectl over the configured tunnel — NEVER a local "what I sent"
6
+ * record (which drifts on refresh / a second machine / a control-plane restart).
7
+ * Only KEY NAMES are read (go-template emits keys, never values); values are
8
+ * never decoded or printed. Sanitized Secret keys are mapped back to their
9
+ * original home-relative paths via the known auth registries, and classified by
10
+ * tool with a "broad" flag for account-wide cloud creds.
11
+ */
12
+ import { spawnSync } from "node:child_process";
13
+ import { homedir } from "node:os";
14
+ import { join } from "node:path";
15
+ import { getTunnel } from "./config.js";
16
+ import { PROFILE_AUTH_FILES } from "./auth-bundle.js";
17
+ import { TOOL_AUTH_INFO } from "./auth-tools.js";
18
+ /** Same sanitization the orchestrator applies to Secret keys (spec.ts). */
19
+ function credentialSecretKey(relativePath) {
20
+ return relativePath.replace(/^\.+/, "").replace(/\//g, "_");
21
+ }
22
+ /** sanitizedSecretKey → {relpath, tool, broad} for every auth file we ever bundle. */
23
+ function knownKeyMap() {
24
+ const m = new Map();
25
+ for (const [profile, files] of Object.entries(PROFILE_AUTH_FILES)) {
26
+ for (const rel of files) {
27
+ m.set(credentialSecretKey(rel), { relpath: rel, tool: profile, broad: false });
28
+ }
29
+ }
30
+ for (const info of TOOL_AUTH_INFO) {
31
+ m.set(credentialSecretKey(info.relpath), { ...info });
32
+ }
33
+ return m;
34
+ }
35
+ function kubeEnv() {
36
+ const tunnel = getTunnel();
37
+ if (!tunnel)
38
+ return undefined;
39
+ const env = { ...process.env };
40
+ if (tunnel.kubeconfig) {
41
+ env.KUBECONFIG = tunnel.kubeconfig.startsWith("~")
42
+ ? join(homedir(), tunnel.kubeconfig.slice(1))
43
+ : tunnel.kubeconfig;
44
+ }
45
+ return env;
46
+ }
47
+ /**
48
+ * Read the auth-Secret KEY NAMES transmitted to a session (values never read).
49
+ * Returns undefined if there is no configured tunnel / the secret can't be read.
50
+ */
51
+ export function transmittedSecrets(sessionId) {
52
+ const tunnel = getTunnel();
53
+ const env = kubeEnv();
54
+ if (!tunnel || !env)
55
+ return undefined;
56
+ const r = spawnSync("kubectl", [
57
+ "-n",
58
+ tunnel.namespace,
59
+ "get",
60
+ "secret",
61
+ `session-${sessionId}-auth`,
62
+ // emit ONLY the keys — the value ($v) is never referenced/printed
63
+ "-o",
64
+ 'go-template={{range $k, $v := .data}}{{$k}}{{"\\n"}}{{end}}',
65
+ ], { encoding: "utf8", env });
66
+ if (r.status !== 0)
67
+ return undefined;
68
+ const map = knownKeyMap();
69
+ return r.stdout
70
+ .split("\n")
71
+ .map((s) => s.trim())
72
+ .filter(Boolean)
73
+ .map((raw) => {
74
+ const info = map.get(raw);
75
+ return info
76
+ ? { path: info.relpath, tool: info.tool, broad: info.broad }
77
+ : { path: raw, tool: "?", broad: false };
78
+ })
79
+ .sort((a, b) => a.path.localeCompare(b.path));
80
+ }
81
+ /** One-line summary for `remote status` (e.g. "claude +scw +aws⚠", or "—"). */
82
+ export function secretsSummary(sessionId) {
83
+ const entries = transmittedSecrets(sessionId);
84
+ if (entries === undefined)
85
+ return "?";
86
+ if (entries.length === 0)
87
+ return "—";
88
+ const seen = new Set();
89
+ const parts = [];
90
+ for (const e of entries) {
91
+ if (seen.has(e.tool))
92
+ continue;
93
+ seen.add(e.tool);
94
+ parts.push(`${e.tool}${e.broad ? "⚠" : ""}`);
95
+ }
96
+ return parts.join(" ");
97
+ }
98
+ //# sourceMappingURL=secrets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secrets.js","sourceRoot":"","sources":["../src/secrets.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ export type OnConflict = "backup" | "keep-local" | "block";
2
+ export type RestoreResult = {
3
+ readonly restored: string[];
4
+ readonly keptLocal: string[];
5
+ readonly backedUp: string[];
6
+ readonly conflicts: string[];
7
+ };
8
+ /**
9
+ * Restore persisted conversation state from a workspace export archive into the
10
+ * local HOME. Per file:
11
+ * - local absent → write remote (new conversation).
12
+ * - local == remote → skip.
13
+ * - local is a prefix of remote (remote is a continuation) → overwrite.
14
+ * - remote is a prefix of local (local is ahead) → keep local.
15
+ * - diverged → conflict, resolved by `onConflict`:
16
+ * backup → duplicate local under a fresh id, then write remote.
17
+ * keep-local→ skip remote.
18
+ * block → leave untouched, report.
19
+ */
20
+ export declare function restoreSessionsToLocal(args: {
21
+ home: string;
22
+ profile: string;
23
+ remoteArchive: Buffer;
24
+ onConflict: OnConflict;
25
+ }): RestoreResult;
26
+ //# sourceMappingURL=session-restore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-restore.d.ts","sourceRoot":"","sources":["../src/session-restore.ts"],"names":[],"mappings":"AAgBA,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,YAAY,GAAG,OAAO,CAAC;AAE3D,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC;CAC9B,CAAC;AA+CF;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,UAAU,CAAC;CACxB,GAAG,aAAa,CAqDhB"}
@@ -0,0 +1,122 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync, } from "node:fs";
3
+ import { dirname, extname, join, relative } from "node:path";
4
+ import { randomUUID } from "node:crypto";
5
+ const STATE_SUBDIR = ".remote/sessions";
6
+ function extractInto(archive, dest) {
7
+ mkdirSync(dest, { recursive: true });
8
+ const res = spawnSync("tar", ["-xzf", "-", "-C", dest], { input: archive });
9
+ if (res.status !== 0) {
10
+ throw new Error(`tar extract failed: ${res.stderr?.toString() ?? res.status}`);
11
+ }
12
+ }
13
+ function walk(root) {
14
+ const out = [];
15
+ if (!existsSync(root))
16
+ return out;
17
+ const stack = [root];
18
+ while (stack.length > 0) {
19
+ const dir = stack.pop();
20
+ for (const e of readdirSync(dir, { withFileTypes: true })) {
21
+ const abs = join(dir, e.name);
22
+ if (e.isDirectory())
23
+ stack.push(abs);
24
+ else if (e.isFile())
25
+ out.push(relative(root, abs));
26
+ }
27
+ }
28
+ return out;
29
+ }
30
+ function isPrefix(short, long) {
31
+ return short.length <= long.length && long.subarray(0, short.length).equals(short);
32
+ }
33
+ function backupWithNewId(home, rel, local) {
34
+ // Heuristic: the conversation id is the filename stem (uuid-like). Duplicate
35
+ // the local conversation under a fresh id so the CLI lists it separately.
36
+ const ext = extname(rel);
37
+ const dir = dirname(rel);
38
+ const stem = rel.slice(dir === "." ? 0 : dir.length + 1, rel.length - ext.length);
39
+ const newId = randomUUID();
40
+ const newRel = join(dir === "." ? "" : dir, `${newId}${ext}`);
41
+ const replaced = stem.length >= 8
42
+ ? Buffer.from(local.toString("utf8").split(stem).join(newId), "utf8")
43
+ : local;
44
+ const dst = join(home, newRel);
45
+ mkdirSync(dirname(dst), { recursive: true });
46
+ writeFileSync(dst, replaced);
47
+ return newRel;
48
+ }
49
+ /**
50
+ * Restore persisted conversation state from a workspace export archive into the
51
+ * local HOME. Per file:
52
+ * - local absent → write remote (new conversation).
53
+ * - local == remote → skip.
54
+ * - local is a prefix of remote (remote is a continuation) → overwrite.
55
+ * - remote is a prefix of local (local is ahead) → keep local.
56
+ * - diverged → conflict, resolved by `onConflict`:
57
+ * backup → duplicate local under a fresh id, then write remote.
58
+ * keep-local→ skip remote.
59
+ * block → leave untouched, report.
60
+ */
61
+ export function restoreSessionsToLocal(args) {
62
+ // Use HOME/.remote/tmp/ as staging area — project policy forbids /tmp.
63
+ const stagingBase = join(args.home, ".remote", "tmp");
64
+ mkdirSync(stagingBase, { recursive: true });
65
+ const tmp = mkdtempSync(join(stagingBase, "restore-"));
66
+ const result = {
67
+ restored: [],
68
+ keptLocal: [],
69
+ backedUp: [],
70
+ conflicts: [],
71
+ };
72
+ try {
73
+ extractInto(args.remoteArchive, tmp);
74
+ const stateRoot = join(tmp, STATE_SUBDIR, args.profile);
75
+ for (const rel of walk(stateRoot)) {
76
+ const remote = readFileSync(join(stateRoot, rel));
77
+ const localPath = join(args.home, rel);
78
+ let local = null;
79
+ try {
80
+ if (statSync(localPath).isFile())
81
+ local = readFileSync(localPath);
82
+ }
83
+ catch {
84
+ local = null;
85
+ }
86
+ const write = () => {
87
+ mkdirSync(dirname(localPath), { recursive: true });
88
+ writeFileSync(localPath, remote);
89
+ };
90
+ if (local === null) {
91
+ write();
92
+ result.restored.push(rel);
93
+ }
94
+ else if (local.equals(remote)) {
95
+ // identical, nothing to do
96
+ }
97
+ else if (isPrefix(local, remote)) {
98
+ write();
99
+ result.restored.push(rel);
100
+ }
101
+ else if (isPrefix(remote, local)) {
102
+ result.keptLocal.push(rel);
103
+ }
104
+ else if (args.onConflict === "backup") {
105
+ const bak = backupWithNewId(args.home, rel, local);
106
+ write();
107
+ result.backedUp.push(`${rel} -> ${bak}`);
108
+ }
109
+ else if (args.onConflict === "keep-local") {
110
+ result.keptLocal.push(rel);
111
+ }
112
+ else {
113
+ result.conflicts.push(rel);
114
+ }
115
+ }
116
+ return result;
117
+ }
118
+ finally {
119
+ rmSync(tmp, { recursive: true, force: true });
120
+ }
121
+ }
122
+ //# sourceMappingURL=session-restore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-restore.js","sourceRoot":"","sources":["../src/session-restore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,126 @@
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 { type TunnelConfig } from "./config.js";
34
+ /**
35
+ * The ONLY paths synced to Pods, relative to `$HOME`. Skills dir + the three
36
+ * plugin-state pieces that make the resolved plugin cache deterministic. Each
37
+ * is a leaf path: no entry is a parent of a secret file (so tarring it can
38
+ * never drag settings.json / .credentials.json / transcripts along). Anything
39
+ * outside this list — including the rest of ~/.claude/plugins (blocklist.json,
40
+ * known_marketplaces.json, plugin-catalog-cache.json, data/) — is excluded.
41
+ */
42
+ export declare const SKILLS_SYNC_WHITELIST: readonly string[];
43
+ /** The explicit whitelist as a fresh array (callers cannot mutate the source). */
44
+ export declare function skillsSyncWhitelist(): string[];
45
+ /**
46
+ * `tar` argv that archives ONLY the whitelisted paths, relative to `$HOME`, as
47
+ * a gzip stream on stdout (`-f -`). `-C <home>` keeps members relative so they
48
+ * untar cleanly into the Pod's `$HOME`. `--ignore-failed-read` lets a partial
49
+ * local install still sync (a missing member is skipped, not fatal). Members
50
+ * follow `--` so a leading-dash path can never be mistaken for a flag.
51
+ */
52
+ export declare function buildSkillsTarArgs(home: string): string[];
53
+ /**
54
+ * In-Pod `tar` argv: extract the gzip stream from stdin (`-f -`) into the Pod's
55
+ * `$HOME` (`-C <podHome>`), `--overwrite` so a re-run replaces the existing
56
+ * skills/plugins in place (idempotent). No member is named — extraction takes
57
+ * whatever the archive carries, and the archive only ever carries the
58
+ * whitelist (constrained on the tar side).
59
+ */
60
+ export declare function buildPodUntarArgs(podHome: string): string[];
61
+ /** A live session resolved to a Pod target for the skills sync. */
62
+ export type SyncPod = {
63
+ sessionId: string;
64
+ profile: string;
65
+ /** Pod `$HOME` (extraction root); defaults to /root (session-agent runs as root). */
66
+ podHome?: string;
67
+ };
68
+ export type SkillsSyncPlan = {
69
+ /** The Pod name (`session-<id>`). */
70
+ pod: string;
71
+ sessionId: string;
72
+ profile: string;
73
+ /** Local archive command: `tar <args>` writing gzip to stdout. */
74
+ tar: {
75
+ cmd: "tar";
76
+ args: string[];
77
+ };
78
+ /** In-Pod extraction command: `tar <args>` reading gzip from stdin. */
79
+ untar: {
80
+ cmd: "tar";
81
+ args: string[];
82
+ };
83
+ /** The whitelist actually transferred (for the recap / dry-run). */
84
+ whitelist: string[];
85
+ /** One-line human-readable plan for `--dry-run` (transfers nothing). */
86
+ dryRun: string;
87
+ };
88
+ /**
89
+ * Compose the local-tar | pod-untar plan for one Pod. Pure: it builds the two
90
+ * argv arrays and a dry-run line, but spawns nothing — the actual transfer is
91
+ * behind the `runSkillsSync` seam so tests never shell out.
92
+ */
93
+ export declare function buildSkillsSyncPlan(input: {
94
+ home: string;
95
+ pod: SyncPod;
96
+ }): SkillsSyncPlan;
97
+ /**
98
+ * Resolve which live sessions to sync. `--all` => every session; `--pod <ref>`
99
+ * => the single session whose id (or `session-<id>` Pod name) matches. Throws
100
+ * when neither is given, or when `--pod` matches nothing live.
101
+ */
102
+ export declare function selectSyncPods(sessions: ReadonlyArray<{
103
+ id: string;
104
+ profile: string;
105
+ }>, opts: {
106
+ pod?: string;
107
+ all?: boolean;
108
+ }): SyncPod[];
109
+ /**
110
+ * Pipe `tar <tarArgs>` (local) → `kubectl exec -i <pod> -- tar <untarArgs>`
111
+ * (Pod). Both ends are pure argv arrays; the gzip archive rides the pipe on
112
+ * stdin so no path/content is ever interpolated into a shell. Resolves on a
113
+ * clean (0/0) exit of both processes, rejects with the first non-zero status.
114
+ */
115
+ export type SkillsSyncRunner = (plan: SkillsSyncPlan, tunnel: TunnelConfig) => Promise<void>;
116
+ /**
117
+ * `remote plugin sync-skills [--pod <name>|--all] [--dry-run]` — copy the local
118
+ * Claude Code skills + plugin cache (whitelist only) into the selected live
119
+ * session Pod(s). `--dry-run` prints the tar/exec plan and transfers nothing.
120
+ */
121
+ export declare function syncSkills(url: string, opts: {
122
+ pod?: string;
123
+ all?: boolean;
124
+ dryRun?: boolean;
125
+ }, stderr?: NodeJS.WriteStream, run?: SkillsSyncRunner): Promise<void>;
126
+ //# sourceMappingURL=skills-sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills-sync.d.ts","sourceRoot":"","sources":["../src/skills-sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAOH,OAAO,EAAa,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAM3D;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAKlD,CAAC;AAEF,kFAAkF;AAClF,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAE9C;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAYzD;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAE3D;AAED,mEAAmE;AACnE,MAAM,MAAM,OAAO,GAAG;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,qFAAqF;IACrF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAKF,MAAM,MAAM,cAAc,GAAG;IAC3B,qCAAqC;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,GAAG,EAAE;QAAE,GAAG,EAAE,KAAK,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACpC,uEAAuE;IACvE,KAAK,EAAE;QAAE,GAAG,EAAE,KAAK,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACtC,oEAAoE;IACpE,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,wEAAwE;IACxE,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;CACd,GAAG,cAAc,CAmBjB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,aAAa,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,EACxD,IAAI,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CAAE,GACpC,OAAO,EAAE,CAeX;AAgBD;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAC7B,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,YAAY,KACjB,OAAO,CAAC,IAAI,CAAC,CAAC;AAoEnB;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,EACvD,MAAM,GAAE,MAAM,CAAC,WAA4B,EAC3C,GAAG,GAAE,gBAAkC,GACtC,OAAO,CAAC,IAAI,CAAC,CAiDf"}