@wrongstack/cli 1.0.26 → 1.0.28

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 (52) hide show
  1. package/dist/{acp-LI665LO2.js → acp-M4565YUW.js} +30 -17
  2. package/dist/boot/dispatch-singleshot.d.ts +8 -0
  3. package/dist/boot/dispatch-webui.d.ts +2 -0
  4. package/dist/boot/goal-tui-default.d.ts +10 -0
  5. package/dist/{chunk-BEHGRNOQ.js → chunk-3ZTLPNEQ.js} +10 -10
  6. package/dist/chunk-7IQWQCBH.js +160 -0
  7. package/dist/{chunk-OAVBM55Q.js → chunk-ENRYW73H.js} +525 -379
  8. package/dist/{chunk-WQV2NP57.js → chunk-L5TD7UIG.js} +2 -2
  9. package/dist/{chunk-2EBVTYJR.js → chunk-NRXWOMK7.js} +17 -3
  10. package/dist/{chunk-5SEYGOCH.js → chunk-RDGGWMTI.js} +2 -2
  11. package/dist/{chunk-KJS5543T.js → chunk-RGFWGUAB.js} +26 -14
  12. package/dist/{chunk-S4FFHDJG.js → chunk-SDJCLEK6.js} +6 -2
  13. package/dist/{cli-context-UVGAN3NO.js → cli-context-O2SHBDFH.js} +33 -6
  14. package/dist/{cli-main-TN3KZ2P6.js → cli-main-BKG4ZVLN.js} +1079 -616
  15. package/dist/{execution-7QIP6GRY.js → execution-THXWTHYT.js} +87 -33
  16. package/dist/execution-chimera-review.d.ts +18 -1
  17. package/dist/fleet/host-memory-companion.d.ts +43 -0
  18. package/dist/fleet/host-subagent-factory.d.ts +1 -1
  19. package/dist/fleet/host.d.ts +1 -0
  20. package/dist/fleet/memory-companion-evidence.d.ts +12 -0
  21. package/dist/fleet/memory-companion-policy.d.ts +9 -0
  22. package/dist/goal-commands.d.ts +10 -0
  23. package/dist/{hq-GLZ7QESM.js → hq-44F4OQH2.js} +5 -4
  24. package/dist/hq-fleet-control.d.ts +36 -0
  25. package/dist/hq-live-status.d.ts +22 -0
  26. package/dist/hq-publisher.d.ts +18 -0
  27. package/dist/hq-server/routes/command-handlers.d.ts +12 -1
  28. package/dist/hq-server/routes/data-handlers.d.ts +1 -1
  29. package/dist/hq-server/socket-credentials.d.ts +63 -0
  30. package/dist/hq-server/upgrade-handler.d.ts +2 -0
  31. package/dist/hq-server/ws.d.ts +24 -0
  32. package/dist/{hq-server-YTKDVQPY.js → hq-server-UIB24LU6.js} +2 -2
  33. package/dist/{import-claude-code-32PCSIQI.js → import-claude-code-AYG24RG2.js} +36 -4
  34. package/dist/index.js +3 -3
  35. package/dist/live-settings-input.d.ts +1 -0
  36. package/dist/{mailbox-serve-NW5VZG7R.js → mailbox-serve-GNGXEQ2R.js} +2 -2
  37. package/dist/{modeldiag-36VODVIH.js → modeldiag-W7XAE625.js} +2 -2
  38. package/dist/{remote-O5WXHLWV.js → remote-GB5VXCCT.js} +38 -23
  39. package/dist/services/run-git.d.ts +3 -1
  40. package/dist/{sessions-config-SXTTLNXA.js → sessions-config-XHLXJ5C3.js} +75 -6
  41. package/dist/{short-circuit-flags-74Y5N6CF.js → short-circuit-flags-BSIPTAPD.js} +2 -2
  42. package/dist/slash-commands/theme.d.ts +15 -1
  43. package/dist/subcommands/handlers/import-claude-code.d.ts +10 -0
  44. package/dist/subcommands/handlers/sessions-fleet.d.ts +0 -12
  45. package/dist/{subcommands-Q6ORSB2E.js → subcommands-SRRB3RAS.js} +2 -2
  46. package/dist/{typesafe-U7YB2RRV.js → typesafe-WA5O3KVS.js} +10 -2
  47. package/dist/{webui-server-YTHLRFD2.js → webui-server-GCXIO3JY.js} +37 -30
  48. package/dist/webui-server-options.d.ts +10 -0
  49. package/dist/wiring/command-host-state.d.ts +2 -0
  50. package/dist/wiring/hq-telemetry.d.ts +12 -0
  51. package/package.json +29 -28
  52. package/dist/chunk-OWNC7LMD.js +0 -78
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Credential enforcement for HQ sockets that are ALREADY open.
3
+ *
4
+ * Neither side of a WebSocket re-presents its credential after the upgrade,
5
+ * so every rule here is the only enforcement that credential gets once the
6
+ * socket is live: revocation notices, expiry that happens with the clock
7
+ * rather than with an auth.json write, and client tokens that stopped being
8
+ * live.
9
+ *
10
+ * @module hq-server/socket-credentials
11
+ */
12
+ import { type HqToken } from '@wrongstack/core/hq';
13
+ import { WebSocket } from 'ws';
14
+ import type { HqRouterMutableAuth, HqSessionEntry } from './types.js';
15
+ export interface HqSocketCredentialState {
16
+ mutableAuth: HqRouterMutableAuth;
17
+ sessions: Map<string, HqSessionEntry>;
18
+ browsers: Set<WebSocket>;
19
+ /** Session that authorized each cookie-authenticated browser socket. */
20
+ browserSocketSessions: Map<WebSocket, string>;
21
+ /** Token each `/ws/client` socket authenticated with (absent in open mode). */
22
+ clientSocketTokens: Map<WebSocket, HqToken | undefined>;
23
+ /**
24
+ * Browser-token verifier each bare loopback `?token=` `/ws/browser` socket
25
+ * authenticated with. Those sockets have no session, so the session sweep
26
+ * never saw them: one kept streaming after its token expired by the clock
27
+ * (H-3, security-check 2026-09-26). Optional for callers that predate it.
28
+ */
29
+ browserSocketTokenKeys?: Map<WebSocket, string> | undefined;
30
+ }
31
+ export interface HqSocketCredentialEnforcer {
32
+ /**
33
+ * Tell the browsers a token revocation can concern.
34
+ *
35
+ * This ONLY announces; it deliberately does not close. The auth.json
36
+ * watcher owns eviction and does it precisely (it deletes the sessions
37
+ * whose `tokenId` is no longer live, and distinguishes a password change
38
+ * from a token change). Because the revocation hook fires from
39
+ * `authState.apply`, which the watcher calls before its close loop, the
40
+ * browser still learns why it is about to be disconnected.
41
+ *
42
+ * A socket bound to a password (or mobile) session, or to a session minted
43
+ * from a DIFFERENT token, is untouched by the revocation — telling it anyway
44
+ * made every password-signed dashboard re-validate and, having no stored
45
+ * token to re-mint, sign itself out. A socket with no recorded session
46
+ * authenticated with a bare `?token=` the server cannot attribute, so it is
47
+ * told and re-validates on its own (fail closed).
48
+ */
49
+ announceRevokedTokens(keys: readonly string[], ids: readonly string[]): void;
50
+ /** Close every `/ws/client` socket whose credential is no longer live. */
51
+ closeUnauthorizedClientSockets(): void;
52
+ /**
53
+ * Credentials also die with the clock. The watcher reacts to file changes
54
+ * only, so before this a client token or a token-backed browser session
55
+ * that reached its `expiresAt` kept its open socket (telemetry in, commands
56
+ * out) until the process restarted.
57
+ */
58
+ sweepExpiredSocketCredentials(now?: number): void;
59
+ /** Close the browser sockets bound to a session that was just removed. */
60
+ closeSessionSockets(sessionId: string, reason: string): void;
61
+ }
62
+ export declare function createHqSocketCredentialEnforcer(state: HqSocketCredentialState): HqSocketCredentialEnforcer;
63
+ //# sourceMappingURL=socket-credentials.d.ts.map
@@ -28,6 +28,8 @@ interface HqUpgradeHandlerDeps {
28
28
  * the revocation path treats that absence as "affected" (fail closed).
29
29
  */
30
30
  browserSocketSessions: Map<WebSocket, string>;
31
+ /** Browser-token verifier behind each bare `?token=` browser socket (H-3). */
32
+ browserSocketTokenKeys?: Map<WebSocket, string> | undefined;
31
33
  browsers: Set<WebSocket>;
32
34
  eventLog: import('@wrongstack/core/hq').HqEventEnvelope[];
33
35
  transcripts: Map<string, TranscriptRing>;
@@ -10,6 +10,30 @@ export { fanoutKanbanDelta } from './ws-client-events.js';
10
10
  export { detectLeaderLoss } from './ws-leader.js';
11
11
  export { handleClientResume } from './ws-resume.js';
12
12
  export declare function handleBrowser(ws: WebSocket, snapshotBroadcaster: HqSnapshotBroadcaster, browsers: Set<WebSocket>, eventLog: HqEventEnvelope[]): void;
13
+ /**
14
+ * Resolve every command the disconnecting client never picked up.
15
+ *
16
+ * The queue lives on the per-socket `ConnectedClient`, so it dies with the
17
+ * socket: a command enqueued in the window between the operator's dispatch and
18
+ * the next 500 ms `command_poll` is simply gone, and nothing re-queues it on
19
+ * the replacement connection. Left alone, its audit row stayed `queued`
20
+ * forever — the Control rail showed a command as pending that will never run,
21
+ * which is the one thing an operator must not have to guess about.
22
+ *
23
+ * `status: 'queued'` in the audit log is the exact undelivered set: the poll
24
+ * handler flips a command to `delivered` the moment it is put on the wire, so
25
+ * anything still `queued` never reached the client. Delivered-but-unacked
26
+ * commands are deliberately left alone — those DID run, and the ack may simply
27
+ * have been in flight when the socket closed.
28
+ *
29
+ * EVERY path that removes a client from `clients` must call this. The socket's
30
+ * own `close` handler finds the client through `clients.get(ws)`, so a path
31
+ * that deletes the entry first — the heartbeat-timeout eviction, the
32
+ * sessionless-surface eviction, the supersede loop — leaves that handler with
33
+ * nothing to resolve, and the rows it owned stayed `queued` forever. Those are
34
+ * exactly the cases (a hung client, a zombie socket) where commands strand.
35
+ */
36
+ export declare function failUndeliveredCommands(lostClient: ConnectedClient, browsers: Set<WebSocket>, auditLog: HqCommandAuditLog | undefined): void;
13
37
  export declare function handleClient(ws: WebSocket, clients: Map<WebSocket, ConnectedClient>, browsers: Set<WebSocket>, eventLog: HqEventEnvelope[], auth: {
14
38
  token?: HqToken | undefined;
15
39
  getOperatorPolicy: () => Partial<HqRedactionPolicy> | undefined;
@@ -10,7 +10,7 @@ import {
10
10
  readLocalSubagentTranscript,
11
11
  sanitizeApiError,
12
12
  startHqServer
13
- } from "./chunk-OAVBM55Q.js";
13
+ } from "./chunk-ENRYW73H.js";
14
14
  import "./chunk-HXJYHAR4.js";
15
15
  import "./chunk-5EA6OTLJ.js";
16
16
  import "./chunk-Q7E3BPDU.js";
@@ -27,4 +27,4 @@ export {
27
27
  sanitizeApiError,
28
28
  startHqServer
29
29
  };
30
- //# sourceMappingURL=hq-server-YTKDVQPY.js.map
30
+ //# sourceMappingURL=hq-server-UIB24LU6.js.map
@@ -17,6 +17,25 @@ import { mcpEnvPlaceholders } from "@wrongstack/mcp";
17
17
  function isRecord(value) {
18
18
  return typeof value === "object" && value !== null && !Array.isArray(value);
19
19
  }
20
+ var REPOSITORY_STRIPPED_MCP_FIELDS = [
21
+ "permission",
22
+ "bearerTokenEnv",
23
+ "passthroughEnv",
24
+ "allowPrivateNetworks"
25
+ ];
26
+ function envReads(config) {
27
+ const reads = new Set(mcpEnvPlaceholders(config));
28
+ if (config.bearerTokenEnv) reads.add(config.bearerTokenEnv);
29
+ for (const name of config.passthroughEnv ?? []) reads.add(name);
30
+ return [...reads];
31
+ }
32
+ function describeTarget(config) {
33
+ if (typeof config.command === "string") {
34
+ return `runs: ${[config.command, ...config.args ?? []].join(" ")}`;
35
+ }
36
+ if (typeof config.url === "string") return `connects to: ${config.url}`;
37
+ return void 0;
38
+ }
20
39
  function samePath(a, b) {
21
40
  const norm = (p) => {
22
41
  const resolved = path.resolve(p).replace(/[\\/]+$/, "");
@@ -58,10 +77,22 @@ function planClaudeCodeImport(opts) {
58
77
  const exists2 = Object.hasOwn(opts.existingServers, name);
59
78
  const repository = source === "repository";
60
79
  const enabled = !repository || opts.enableProjectServers;
61
- const reads = mcpEnvPlaceholders(config);
80
+ const stripped = [];
81
+ if (repository) {
82
+ for (const field of REPOSITORY_STRIPPED_MCP_FIELDS) {
83
+ if (config[field] === void 0) continue;
84
+ delete config[field];
85
+ stripped.push(field);
86
+ }
87
+ config.origin = "repository";
88
+ }
89
+ const reads = envReads(config);
90
+ const target = describeTarget(config);
62
91
  const notes2 = [
92
+ target,
63
93
  repository && !enabled ? "from the repository \u2014 imported disabled; review, then `/mcp enable`" : void 0,
64
- reads.length > 0 ? `reads environment: ${reads.join(", ")}` : void 0
94
+ reads.length > 0 ? `reads environment: ${reads.join(", ")}` : void 0,
95
+ stripped.length > 0 ? `not imported from the repository: ${stripped.join(", ")} (set them yourself after review)` : void 0
65
96
  ].filter((note) => note !== void 0);
66
97
  mcp.push({
67
98
  name,
@@ -77,8 +108,8 @@ function planClaudeCodeImport(opts) {
77
108
  projectEntry(sources.userState, opts.projectRoot)?.["mcpServers"],
78
109
  "claude-project-local"
79
110
  );
80
- collect(sources.projectMcp?.["mcpServers"] ?? sources.projectMcp, "repository");
81
111
  collect(sources.userState?.["mcpServers"], "claude-user");
112
+ collect(sources.projectMcp?.["mcpServers"] ?? sources.projectMcp, "repository");
82
113
  const notes = [];
83
114
  if (sources.skillDirs.length > 0) {
84
115
  notes.push(
@@ -229,8 +260,9 @@ Wrote ${writes.length} server(s) to ${configPath}.`);
229
260
  return 0;
230
261
  };
231
262
  export {
263
+ REPOSITORY_STRIPPED_MCP_FIELDS,
232
264
  importClaudeCodeCmd,
233
265
  planClaudeCodeImport,
234
266
  readClaudeCodeSources
235
267
  };
236
- //# sourceMappingURL=import-claude-code-32PCSIQI.js.map
268
+ //# sourceMappingURL=import-claude-code-AYG24RG2.js.map
package/dist/index.js CHANGED
@@ -20,14 +20,14 @@ async function main(argv) {
20
20
  applyAsciiMode(earlyFlags);
21
21
  }
22
22
  if (earlyFlags["help"] === true || earlyFlags["version"] === true) {
23
- const { handleHelpVersionShortCircuit } = await import("./short-circuit-flags-74Y5N6CF.js");
23
+ const { handleHelpVersionShortCircuit } = await import("./short-circuit-flags-BSIPTAPD.js");
24
24
  const earlyExit = await handleHelpVersionShortCircuit(argv);
25
25
  if (earlyExit !== null) return earlyExit;
26
26
  }
27
- const { initializeCli } = await import("./cli-context-UVGAN3NO.js");
27
+ const { initializeCli } = await import("./cli-context-O2SHBDFH.js");
28
28
  const cliCtx = await initializeCli(argv);
29
29
  if (typeof cliCtx === "number") return cliCtx;
30
- const { runInteractive } = await import("./cli-main-TN3KZ2P6.js");
30
+ const { runInteractive } = await import("./cli-main-BKG4ZVLN.js");
31
31
  return runInteractive(cliCtx);
32
32
  }
33
33
 
@@ -19,6 +19,7 @@ export interface LiveSettingsInput {
19
19
  featureMemory?: boolean | undefined;
20
20
  featureSkills?: boolean | undefined;
21
21
  featureModelsRegistry?: boolean | undefined;
22
+ featureToolCoach?: boolean | undefined;
22
23
  featureTokenSaving?: TokenSavingTier | undefined;
23
24
  allowOutsideProjectRoot?: boolean | undefined;
24
25
  contextAutoCompact?: boolean | undefined;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  startCliHqConnection
3
- } from "./chunk-KJS5543T.js";
3
+ } from "./chunk-RGFWGUAB.js";
4
4
  import "./chunk-F5DCFAKI.js";
5
5
 
6
6
  // src/subcommands/handlers/mailbox-serve.ts
@@ -361,4 +361,4 @@ function printHelp(deps) {
361
361
  export {
362
362
  mailboxServeCmd
363
363
  };
364
- //# sourceMappingURL=mailbox-serve-NW5VZG7R.js.map
364
+ //# sourceMappingURL=mailbox-serve-GNGXEQ2R.js.map
@@ -20,7 +20,7 @@ import {
20
20
  } from "./chunk-BBHWW6LR.js";
21
21
  import {
22
22
  resolveRawProviderConnection
23
- } from "./chunk-S4FFHDJG.js";
23
+ } from "./chunk-SDJCLEK6.js";
24
24
  import {
25
25
  mutateConfigProviders
26
26
  } from "./chunk-LUMETJFO.js";
@@ -825,4 +825,4 @@ var modeldiagCmd = async (args, deps) => {
825
825
  export {
826
826
  modeldiagCmd
827
827
  };
828
- //# sourceMappingURL=modeldiag-36VODVIH.js.map
828
+ //# sourceMappingURL=modeldiag-W7XAE625.js.map
@@ -28,6 +28,13 @@ import { buildChildEnv, toErrorMessage } from "@wrongstack/core/utils";
28
28
 
29
29
  // src/remote/remote-target.ts
30
30
  function parseRemoteTarget(input) {
31
+ const target = parseRemoteTargetText(input);
32
+ if (target.destination.startsWith("-")) {
33
+ throw new Error(`A remote host cannot start with "-" (got ${target.destination})`);
34
+ }
35
+ return target;
36
+ }
37
+ function parseRemoteTargetText(input) {
31
38
  const text = input.trim();
32
39
  if (text.startsWith("ssh://")) {
33
40
  let url;
@@ -73,22 +80,30 @@ function buildTargetFor(os, arch, musl) {
73
80
  throw new Error(`Remote machines running ${os} are not supported (Linux and macOS are).`);
74
81
  }
75
82
  var REMOTE_BIN_DIR = '"$HOME"/.wrongstack/remote';
83
+ function stateScript(path3) {
84
+ return `dir=${shPath(path3)}
85
+ abs=$(cd "$dir" 2>/dev/null && pwd -P) || abs=
86
+ key=$(printf '%s' "$abs" | cksum | tr ' ' '-')
87
+ state_dir=${REMOTE_BIN_DIR}/servers
88
+ state="$state_dir/$key.json"
89
+ token_file="$state_dir/$key.token"
90
+ log="$state_dir/$key.log"`;
91
+ }
76
92
  function probeScript(path3) {
77
93
  return `set -u
78
94
  printf 'os=%s\\n' "$(uname -s 2>/dev/null)"
79
95
  printf 'arch=%s\\n' "$(uname -m 2>/dev/null)"
80
96
  if ls /lib/ld-musl-* >/dev/null 2>&1; then echo musl=1; else echo musl=0; fi
81
- dir=${shPath(path3)}
97
+ ${stateScript(path3)}
82
98
  if [ -d "$dir" ]; then echo path=1; else echo path=0; fi
83
99
  for f in ${REMOTE_BIN_DIR}/wstack-*; do
84
100
  [ -x "$f" ] && printf 'version=%s\\n' "\${f##*/wstack-}"
85
101
  done
86
- state="$dir/.wrongstack/remote-webui.json"
87
- if [ -f "$state" ] && [ -f "$dir/.wrongstack/remote-webui.token" ]; then
102
+ if [ -n "$abs" ] && [ -f "$state" ] && [ -f "$token_file" ]; then
88
103
  pid=$(sed -n 's/.*"pid":\\([0-9]*\\).*/\\1/p' "$state")
89
104
  if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
90
105
  printf 'server=%s\\n' "$(tr -d '\\n' < "$state")"
91
- printf 'token=%s\\n' "$(cat "$dir/.wrongstack/remote-webui.token")"
106
+ printf 'token=%s\\n' "$(cat "$token_file")"
92
107
  fi
93
108
  fi
94
109
  `;
@@ -141,12 +156,12 @@ var NO_PROVIDER = ["No provider or model configured", "Saved provider/model is n
141
156
  function startScript(options) {
142
157
  const bin = remoteBinaryPath(options.version);
143
158
  return `set -u
144
- dir=${shPath(options.path)}
145
- cd "$dir" || { echo error=path; exit 3; }
146
159
  umask 077
147
- mkdir -p .wrongstack
148
- printf '%s' ${shQuote(options.token)} > .wrongstack/remote-webui.token
149
- log=.wrongstack/remote-webui.log
160
+ ${stateScript(options.path)}
161
+ cd "$dir" || { echo error=path; exit 3; }
162
+ mkdir -p "$state_dir"
163
+ chmod 700 "$state_dir"
164
+ printf '%s' ${shQuote(options.token)} > "$token_file"
150
165
  export WEBUI_TOKEN=${shQuote(options.token)}
151
166
  launch() {
152
167
  : > "$log"
@@ -171,21 +186,21 @@ await_port() {
171
186
  }
172
187
  launch
173
188
  await_port
174
- state=$?
175
- if [ "$state" -eq 1 ] && grep -q ${NO_PROVIDER.map((line) => `-e ${shQuote(line)}`).join(" ")} "$log"; then
189
+ status=$?
190
+ if [ "$status" -eq 1 ] && grep -q ${NO_PROVIDER.map((line) => `-e ${shQuote(line)}`).join(" ")} "$log"; then
176
191
  echo setup=1
177
192
  launch --provider wrongstack-setup --model no-api-key
178
193
  await_port
179
- state=$?
194
+ status=$?
180
195
  fi
181
- if [ "$state" -eq 0 ]; then
182
- printf '{"pid":%s,"port":%s,"version":"%s"}\\n' "$pid" "$port" ${shQuote(options.version)} > .wrongstack/remote-webui.json
196
+ if [ "$status" -eq 0 ]; then
197
+ printf '{"pid":%s,"port":%s,"version":"%s"}\\n' "$pid" "$port" ${shQuote(options.version)} > "$state"
183
198
  echo "port=$port"
184
199
  echo "pid=$pid"
185
200
  exit 0
186
201
  fi
187
- rm -f .wrongstack/remote-webui.token
188
- if [ "$state" -eq 1 ]; then
202
+ rm -f "$token_file"
203
+ if [ "$status" -eq 1 ]; then
189
204
  echo error=exited
190
205
  tail -n 30 "$log" | sed 's/^/log=/'
191
206
  exit 4
@@ -197,12 +212,11 @@ exit 5
197
212
  }
198
213
  function stopScript(path3) {
199
214
  return `set -u
200
- dir=${shPath(path3)}
201
- state="$dir/.wrongstack/remote-webui.json"
202
- [ -f "$state" ] || exit 0
215
+ ${stateScript(path3)}
216
+ [ -n "$abs" ] && [ -f "$state" ] || exit 0
203
217
  pid=$(sed -n 's/.*"pid":\\([0-9]*\\).*/\\1/p' "$state")
204
218
  [ -n "$pid" ] && kill "$pid" 2>/dev/null
205
- rm -f "$state" "$dir/.wrongstack/remote-webui.token"
219
+ rm -f "$state" "$token_file"
206
220
  echo stopped=1
207
221
  `;
208
222
  }
@@ -333,7 +347,7 @@ async function runRemoteSession(opts) {
333
347
  await exited(tunnel);
334
348
  opts.signal.removeEventListener("abort", stopTunnel);
335
349
  throw new Error(
336
- `The WebUI on ${opts.target.destination} did not answer through the SSH tunnel. Check that its sshd allows port forwarding (AllowTcpForwarding) and see ${opts.target.path}/.wrongstack/remote-webui.log there.`
350
+ `The WebUI on ${opts.target.destination} did not answer through the SSH tunnel. Check that its sshd allows port forwarding (AllowTcpForwarding) and see the host log under ~/.wrongstack/remote/servers/ there.`
337
351
  );
338
352
  }
339
353
  }
@@ -406,7 +420,7 @@ function sshCommandLine(target, options) {
406
420
  function systemSsh(target, options) {
407
421
  const base = sshCommandLine(target, options);
408
422
  const run = (remoteCommand, input) => new Promise((resolve2) => {
409
- const child = spawn("ssh", [...base, target.destination, remoteCommand], {
423
+ const child = spawn("ssh", [...base, "--", target.destination, remoteCommand], {
410
424
  stdio: ["pipe", "pipe", "inherit"],
411
425
  env: { ...buildChildEnv(), ...sshAgentEnv() },
412
426
  windowsHide: true
@@ -431,6 +445,7 @@ function systemSsh(target, options) {
431
445
  "ExitOnForwardFailure=yes",
432
446
  "-L",
433
447
  `127.0.0.1:${localPort}:127.0.0.1:${remotePort}`,
448
+ "--",
434
449
  target.destination
435
450
  ],
436
451
  {
@@ -558,4 +573,4 @@ export {
558
573
  remoteCmd,
559
574
  runRemoteCommand
560
575
  };
561
- //# sourceMappingURL=remote-O5WXHLWV.js.map
576
+ //# sourceMappingURL=remote-GB5VXCCT.js.map
@@ -10,7 +10,9 @@
10
10
  * Never rejects on a non-zero exit — the caller inspects `code`. It rejects
11
11
  * only when git could not be spawned at all, or when the 30s timeout fires.
12
12
  */
13
- export declare function runGit(args: string[], cwd: string): Promise<{
13
+ export declare function runGit(args: string[], cwd: string,
14
+ /** Extra environment (e.g. `GIT_INDEX_FILE`), merged over this process's. */
15
+ env?: NodeJS.ProcessEnv): Promise<{
14
16
  stdout: string;
15
17
  stderr: string;
16
18
  code: number;
@@ -33,6 +33,40 @@ function redactKeys(obj) {
33
33
  import * as fsp from "node:fs/promises";
34
34
  import * as path from "node:path";
35
35
  import { color } from "@wrongstack/core/utils";
36
+ var STORE_SIDECAR_JSONL_NAMES = /* @__PURE__ */ new Set(["_index.jsonl", "_mailbox.jsonl"]);
37
+ var SESSION_SIDECAR_JSONL_SUFFIXES = [".replay.jsonl", ".audit.jsonl", ".annotations.jsonl"];
38
+ function isSubagentTranscriptFile(name) {
39
+ const lower = name.toLowerCase();
40
+ if (!lower.endsWith(".jsonl")) return false;
41
+ if (STORE_SIDECAR_JSONL_NAMES.has(lower)) return false;
42
+ return !SESSION_SIDECAR_JSONL_SUFFIXES.some((suffix) => lower.endsWith(suffix));
43
+ }
44
+ async function collectSubagentTranscripts(subagentsDir) {
45
+ let entries;
46
+ try {
47
+ entries = await fsp.readdir(subagentsDir, { withFileTypes: true });
48
+ } catch {
49
+ return [];
50
+ }
51
+ const out = [];
52
+ for (const entry of entries) {
53
+ if (entry.isFile()) {
54
+ if (isSubagentTranscriptFile(entry.name)) out.push(entry.name);
55
+ continue;
56
+ }
57
+ if (!entry.isDirectory() || entry.name === "transcripts" || entry.name === "shared") continue;
58
+ let nested;
59
+ try {
60
+ nested = await fsp.readdir(path.join(subagentsDir, entry.name));
61
+ } catch {
62
+ continue;
63
+ }
64
+ for (const name of nested) {
65
+ if (isSubagentTranscriptFile(name)) out.push(`${entry.name}/${name}`);
66
+ }
67
+ }
68
+ return out;
69
+ }
36
70
  var sessionsFleetCmd = async (args, deps) => {
37
71
  const runId = args.find((a) => !a.startsWith("-"));
38
72
  if (runId) {
@@ -40,10 +74,46 @@ var sessionsFleetCmd = async (args, deps) => {
40
74
  }
41
75
  return listFleetRuns(deps);
42
76
  };
77
+ async function hasFleetRunArtifacts(dir) {
78
+ const markers = await Promise.all(
79
+ ["fleet.json", "checkpoint.json", "subagents"].map(
80
+ (name) => fsp.access(path.join(dir, name)).then(
81
+ () => true,
82
+ () => false
83
+ )
84
+ )
85
+ );
86
+ return markers.some((found) => found);
87
+ }
88
+ async function discoverFleetRunIds(projectSessions) {
89
+ const entries = await fsp.readdir(projectSessions, { withFileTypes: true });
90
+ const ids = [];
91
+ for (const entry of entries) {
92
+ if (!entry.isDirectory()) continue;
93
+ const dir = path.join(projectSessions, entry.name);
94
+ if (await hasFleetRunArtifacts(dir)) {
95
+ ids.push(entry.name);
96
+ continue;
97
+ }
98
+ let children;
99
+ try {
100
+ children = await fsp.readdir(dir, { withFileTypes: true });
101
+ } catch {
102
+ continue;
103
+ }
104
+ for (const child of children) {
105
+ if (!child.isDirectory()) continue;
106
+ if (await hasFleetRunArtifacts(path.join(dir, child.name))) {
107
+ ids.push(`${entry.name}/${child.name}`);
108
+ }
109
+ }
110
+ }
111
+ return ids;
112
+ }
43
113
  async function listFleetRuns(deps) {
44
114
  let entries = [];
45
115
  try {
46
- entries = await fsp.readdir(deps.paths.projectSessions);
116
+ entries = await discoverFleetRunIds(deps.paths.projectSessions);
47
117
  } catch {
48
118
  deps.renderer.writeError(`Cannot read projectSessions: ${deps.paths.projectSessions}
49
119
  `);
@@ -69,8 +139,8 @@ async function listFleetRuns(deps) {
69
139
  () => true,
70
140
  () => false
71
141
  ),
72
- fsp.readdir(path.join(runDir, "subagents")).then(
73
- (files) => files.filter((f) => f.endsWith(".jsonl")).length,
142
+ collectSubagentTranscripts(path.join(runDir, "subagents")).then(
143
+ (files) => files.length,
74
144
  () => 0
75
145
  )
76
146
  ]);
@@ -189,8 +259,7 @@ Fleet Run: ${runId}
189
259
  const subagentsDir = path.join(runDir, "subagents");
190
260
  let subagentFiles = [];
191
261
  try {
192
- subagentFiles = await fsp.readdir(subagentsDir);
193
- subagentFiles = subagentFiles.filter((f) => f.endsWith(".jsonl"));
262
+ subagentFiles = await collectSubagentTranscripts(subagentsDir);
194
263
  } catch {
195
264
  }
196
265
  if (subagentFiles.length > 0) {
@@ -456,4 +525,4 @@ export {
456
525
  configCmd,
457
526
  sessionsCmd
458
527
  };
459
- //# sourceMappingURL=sessions-config-SXTTLNXA.js.map
528
+ //# sourceMappingURL=sessions-config-XHLXJ5C3.js.map
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  handleHelpVersionShortCircuit
3
- } from "./chunk-WQV2NP57.js";
3
+ } from "./chunk-L5TD7UIG.js";
4
4
  import "./chunk-5JYDKG5B.js";
5
5
  import "./chunk-F5DCFAKI.js";
6
6
  import "./chunk-Q4INH2DG.js";
7
7
  export {
8
8
  handleHelpVersionShortCircuit
9
9
  };
10
- //# sourceMappingURL=short-circuit-flags-74Y5N6CF.js.map
10
+ //# sourceMappingURL=short-circuit-flags-BSIPTAPD.js.map
@@ -1,5 +1,18 @@
1
- import type { InputReader, SlashCommand } from '@wrongstack/core/types';
1
+ import type { InputReader, SlashCommand, ThemePresetId } from '@wrongstack/core/types';
2
2
  import type { SlashCommandContext } from './command-context.js';
3
+ interface ThemeOption {
4
+ id: ThemePresetId;
5
+ name: string;
6
+ desc: string;
7
+ }
8
+ /**
9
+ * The CLI's picker rows, exported for the TUI↔CLI agreement test
10
+ * (`packages/cli/tests/theme-metadata-agreement.test.ts`). The TUI derives its
11
+ * own rows from the same `THEME_PRESET_META` record, so this export is the
12
+ * second side of that comparison — it must stay in step with `THEME_OPTIONS`
13
+ * above.
14
+ */
15
+ export declare const cliThemePickerOptions: readonly ThemeOption[];
3
16
  /**
4
17
  * Windowed slice of the theme list for the raw-terminal picker — mirrors the
5
18
  * math in the TUI's `useWindowedPicker` (same centering + marker rules) so
@@ -35,4 +48,5 @@ export declare function truncateDesc(desc: string, columns: number, active: bool
35
48
  export declare function buildThemeCommand(opts: SlashCommandContext & {
36
49
  inputReader?: InputReader | undefined;
37
50
  }): SlashCommand;
51
+ export {};
38
52
  //# sourceMappingURL=theme.d.ts.map
@@ -28,6 +28,16 @@ export interface ClaudeCodeSources {
28
28
  /** Skill directories that exist. */
29
29
  skillDirs: string[];
30
30
  }
31
+ /**
32
+ * Fields a repository entry may not carry into the user's profile. Each one
33
+ * widens what the server gets on enable beyond "run this command / reach this
34
+ * URL": `permission` pre-approves every tool it exposes, `bearerTokenEnv` and
35
+ * `passthroughEnv` send the named environment variables to it, and
36
+ * `allowPrivateNetworks` lifts the internal-network guard. The repository
37
+ * chooses the command and URL, so it must not also choose those
38
+ * (WS-2026-09-26-05). The user can still set them after reviewing.
39
+ */
40
+ export declare const REPOSITORY_STRIPPED_MCP_FIELDS: readonly ['permission', 'bearerTokenEnv', 'passthroughEnv', 'allowPrivateNetworks'];
31
41
  /** Decide what an import would do. Pure: no reads, no writes. */
32
42
  export declare function planClaudeCodeImport(opts: {
33
43
  sources: ClaudeCodeSources;
@@ -1,15 +1,3 @@
1
1
  import type { SubcommandHandler } from '../contracts.js';
2
- /**
3
- * `wrongstack sessions fleet [runId]`
4
- *
5
- * Lists fleet run artifacts under `projectSessions/<runId>/`.
6
- * When runId is omitted, lists all fleet runs discovered under projectSessions.
7
- *
8
- * Artifacts shown:
9
- * - fleet.json (manifest)
10
- * - checkpoint.json (state snapshot, if present)
11
- * - shared/ (scratchpad directory)
12
- * - subagents/ (per-subagent JSONL transcripts)
13
- */
14
2
  export declare const sessionsFleetCmd: SubcommandHandler;
15
3
  //# sourceMappingURL=sessions-fleet.d.ts.map
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  subcommandNames,
3
3
  subcommands
4
- } from "./chunk-BEHGRNOQ.js";
4
+ } from "./chunk-3ZTLPNEQ.js";
5
5
  export {
6
6
  subcommandNames,
7
7
  subcommands
8
8
  };
9
- //# sourceMappingURL=subcommands-Q6ORSB2E.js.map
9
+ //# sourceMappingURL=subcommands-SRRB3RAS.js.map
@@ -278,7 +278,15 @@ async function lintConventions(deps, write) {
278
278
  }
279
279
  }
280
280
  const base = typeof flags["base"] === "string" ? flags["base"] : void 0;
281
- const diffArgs = ["diff", "--no-color", "--no-ext-diff", "-U24"];
281
+ const diffArgs = [
282
+ "diff",
283
+ "--no-color",
284
+ "--no-ext-diff",
285
+ "--no-textconv",
286
+ "--src-prefix=a/",
287
+ "--dst-prefix=b/",
288
+ "-U24"
289
+ ];
282
290
  if (flags["staged"] === true) diffArgs.push("--cached");
283
291
  else if (base) diffArgs.push(`${base}...HEAD`);
284
292
  let diff;
@@ -313,4 +321,4 @@ async function lintConventions(deps, write) {
313
321
  export {
314
322
  typesafeCmd
315
323
  };
316
- //# sourceMappingURL=typesafe-U7YB2RRV.js.map
324
+ //# sourceMappingURL=typesafe-WA5O3KVS.js.map