@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.
- package/dist/{acp-LI665LO2.js → acp-M4565YUW.js} +30 -17
- package/dist/boot/dispatch-singleshot.d.ts +8 -0
- package/dist/boot/dispatch-webui.d.ts +2 -0
- package/dist/boot/goal-tui-default.d.ts +10 -0
- package/dist/{chunk-BEHGRNOQ.js → chunk-3ZTLPNEQ.js} +10 -10
- package/dist/chunk-7IQWQCBH.js +160 -0
- package/dist/{chunk-OAVBM55Q.js → chunk-ENRYW73H.js} +525 -379
- package/dist/{chunk-WQV2NP57.js → chunk-L5TD7UIG.js} +2 -2
- package/dist/{chunk-2EBVTYJR.js → chunk-NRXWOMK7.js} +17 -3
- package/dist/{chunk-5SEYGOCH.js → chunk-RDGGWMTI.js} +2 -2
- package/dist/{chunk-KJS5543T.js → chunk-RGFWGUAB.js} +26 -14
- package/dist/{chunk-S4FFHDJG.js → chunk-SDJCLEK6.js} +6 -2
- package/dist/{cli-context-UVGAN3NO.js → cli-context-O2SHBDFH.js} +33 -6
- package/dist/{cli-main-TN3KZ2P6.js → cli-main-BKG4ZVLN.js} +1079 -616
- package/dist/{execution-7QIP6GRY.js → execution-THXWTHYT.js} +87 -33
- package/dist/execution-chimera-review.d.ts +18 -1
- package/dist/fleet/host-memory-companion.d.ts +43 -0
- package/dist/fleet/host-subagent-factory.d.ts +1 -1
- package/dist/fleet/host.d.ts +1 -0
- package/dist/fleet/memory-companion-evidence.d.ts +12 -0
- package/dist/fleet/memory-companion-policy.d.ts +9 -0
- package/dist/goal-commands.d.ts +10 -0
- package/dist/{hq-GLZ7QESM.js → hq-44F4OQH2.js} +5 -4
- package/dist/hq-fleet-control.d.ts +36 -0
- package/dist/hq-live-status.d.ts +22 -0
- package/dist/hq-publisher.d.ts +18 -0
- package/dist/hq-server/routes/command-handlers.d.ts +12 -1
- package/dist/hq-server/routes/data-handlers.d.ts +1 -1
- package/dist/hq-server/socket-credentials.d.ts +63 -0
- package/dist/hq-server/upgrade-handler.d.ts +2 -0
- package/dist/hq-server/ws.d.ts +24 -0
- package/dist/{hq-server-YTKDVQPY.js → hq-server-UIB24LU6.js} +2 -2
- package/dist/{import-claude-code-32PCSIQI.js → import-claude-code-AYG24RG2.js} +36 -4
- package/dist/index.js +3 -3
- package/dist/live-settings-input.d.ts +1 -0
- package/dist/{mailbox-serve-NW5VZG7R.js → mailbox-serve-GNGXEQ2R.js} +2 -2
- package/dist/{modeldiag-36VODVIH.js → modeldiag-W7XAE625.js} +2 -2
- package/dist/{remote-O5WXHLWV.js → remote-GB5VXCCT.js} +38 -23
- package/dist/services/run-git.d.ts +3 -1
- package/dist/{sessions-config-SXTTLNXA.js → sessions-config-XHLXJ5C3.js} +75 -6
- package/dist/{short-circuit-flags-74Y5N6CF.js → short-circuit-flags-BSIPTAPD.js} +2 -2
- package/dist/slash-commands/theme.d.ts +15 -1
- package/dist/subcommands/handlers/import-claude-code.d.ts +10 -0
- package/dist/subcommands/handlers/sessions-fleet.d.ts +0 -12
- package/dist/{subcommands-Q6ORSB2E.js → subcommands-SRRB3RAS.js} +2 -2
- package/dist/{typesafe-U7YB2RRV.js → typesafe-WA5O3KVS.js} +10 -2
- package/dist/{webui-server-YTHLRFD2.js → webui-server-GCXIO3JY.js} +37 -30
- package/dist/webui-server-options.d.ts +10 -0
- package/dist/wiring/command-host-state.d.ts +2 -0
- package/dist/wiring/hq-telemetry.d.ts +12 -0
- package/package.json +29 -28
- 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>;
|
package/dist/hq-server/ws.d.ts
CHANGED
|
@@ -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-
|
|
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-
|
|
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
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
-
|
|
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
|
-
|
|
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 "$
|
|
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
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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
|
-
|
|
175
|
-
if [ "$
|
|
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
|
-
|
|
194
|
+
status=$?
|
|
180
195
|
fi
|
|
181
|
-
if [ "$
|
|
182
|
-
printf '{"pid":%s,"port":%s,"version":"%s"}\\n' "$pid" "$port" ${shQuote(options.version)} >
|
|
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
|
|
188
|
-
if [ "$
|
|
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
|
-
|
|
201
|
-
|
|
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" "$
|
|
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
|
|
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-
|
|
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
|
|
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
|
|
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
|
-
|
|
73
|
-
(files) => files.
|
|
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
|
|
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-
|
|
528
|
+
//# sourceMappingURL=sessions-config-XHLXJ5C3.js.map
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
handleHelpVersionShortCircuit
|
|
3
|
-
} from "./chunk-
|
|
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-
|
|
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
|
|
@@ -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 = [
|
|
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-
|
|
324
|
+
//# sourceMappingURL=typesafe-WA5O3KVS.js.map
|