@wrongstack/cli 0.299.0 → 0.301.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.
- package/dist/{acp-S4LZQB66.js → acp-DATHHPNT.js} +36 -17
- package/dist/acp-server-agent.d.ts +1 -1
- package/dist/{audit-2ZSFGNIF.js → audit-QRCLEHHW.js} +5 -1
- package/dist/{auth-G5YKKSRH.js → auth-JASC4K3F.js} +151 -38
- package/dist/auth-menu/loopback-server.d.ts +41 -55
- package/dist/auth-menu/openai-codex-oauth.d.ts +36 -123
- package/dist/auto-discover-providers-DRW4OZHG.js +8 -0
- package/dist/boot/dispatch-webui.d.ts +3 -0
- package/dist/boot/launch-menu.d.ts +2 -4
- package/dist/boot/tool-registry.d.ts +3 -0
- package/dist/chimera-reviewer-policy.d.ts +10 -3
- package/dist/chimera-work-registry.d.ts +19 -0
- package/dist/{chronicle-QQEQFSSE.js → chronicle-63MFCZN6.js} +26 -5
- package/dist/{chunk-YWUPHRGB.js → chunk-263G3FMB.js} +33 -10
- package/dist/{chunk-2SLSUDYS.js → chunk-2KDOFTTM.js} +312 -211
- package/dist/{chunk-TGDHN4LM.js → chunk-4GVH7V3S.js} +4 -24
- package/dist/chunk-CSAPOCBP.js +24 -0
- package/dist/{chunk-66T43Q4Y.js → chunk-ETOEGL3V.js} +6 -9
- package/dist/{chunk-PEKUKUCH.js → chunk-GUHQQG63.js} +32 -14
- package/dist/chunk-KE7E7DPX.js +38 -0
- package/dist/{chunk-ZNZJ34RF.js → chunk-MHF2IJDE.js} +21 -4
- package/dist/{chunk-4HH3YGG4.js → chunk-MRLYDHQ7.js} +8 -5
- package/dist/{chunk-L5CE52XW.js → chunk-O7XNGCRT.js} +317 -309
- package/dist/chunk-PYTFS4MC.js +238 -0
- package/dist/{chunk-DPJZQCVP.js → chunk-YMXXOOFN.js} +1 -1
- package/dist/{chunk-4U3DMA2Y.js → chunk-ZECLGUTF.js} +28 -21
- package/dist/{cli-main-3MQDFSYK.js → cli-main-XWC57MGE.js} +849 -242
- package/dist/{execution-ANOYMWPO.js → execution-LHMSMDHB.js} +174 -55
- package/dist/execution-chimera-cascade.d.ts +3 -4
- package/dist/execution-chimera-review.d.ts +2 -3
- package/dist/execution-cleanup.d.ts +3 -2
- package/dist/execution.d.ts +1 -1
- package/dist/{export-TPORYVRZ.js → export-DOBGPY23.js} +12 -1
- package/dist/fleet/budget-source.d.ts +18 -0
- package/dist/fleet/host-context.d.ts +1 -1
- package/dist/fleet/host-helpers.d.ts +14 -0
- package/dist/fleet/host-status.d.ts +31 -0
- package/dist/fleet/host-types.d.ts +8 -0
- package/dist/fleet/host.d.ts +5 -0
- package/dist/fleet/status-broadcast.d.ts +1 -1
- package/dist/{hq-BDO56CX6.js → hq-LN5CJHCM.js} +22 -3
- package/dist/hq-server/auth-state.d.ts +29 -1
- package/dist/hq-server/auth.d.ts +16 -0
- package/dist/hq-server/client-address.d.ts +56 -0
- package/dist/hq-server/login-attempt-store.d.ts +30 -10
- package/dist/hq-server/routes/auth-handlers.d.ts +66 -26
- package/dist/hq-server/routes.d.ts +23 -1
- package/dist/hq-server/types.d.ts +10 -0
- package/dist/hq-server/ws.d.ts +17 -6
- package/dist/{hq-server-RJLJJZU7.js → hq-server-S7HZG3PA.js} +3 -2
- package/dist/hq-server.d.ts +19 -0
- package/dist/index.js +69 -104
- package/dist/live-settings-input.d.ts +5 -0
- package/dist/{mcp-CYLPUEHC.js → mcp-OHPJH73U.js} +6 -2
- package/dist/{modeldiag-HENYJ4N7.js → modeldiag-3DOK4BWW.js} +3 -3
- package/dist/{plugin-usage-VTL7ZTVC.js → plugin-usage-YEVLOR33.js} +7 -3
- package/dist/{plugins-ETY6W3DC.js → plugins-K3BAUP4D.js} +3 -3
- package/dist/profile-config-path.d.ts +0 -2
- package/dist/provider-helpers.d.ts +0 -5
- package/dist/{providers-models-GDELBHZK.js → providers-models-WEZ4EGLL.js} +38 -12
- package/dist/{replay-KCTXNMZQ.js → replay-FCBNHW3K.js} +5 -1
- package/dist/{rewind-EJMVFVLS.js → rewind-AOD3JIYX.js} +5 -1
- package/dist/{sessions-config-NLCMK3BY.js → sessions-config-XXN7267N.js} +8 -3
- package/dist/slash-commands/command-context.d.ts +19 -0
- package/dist/subcommands/flags.d.ts +23 -0
- package/dist/terminal-format.d.ts +15 -0
- package/dist/webui-server/setup-events.d.ts +17 -0
- package/dist/webui-server/terminal-log-view.d.ts +29 -12
- package/dist/{webui-server-PCLSXX6L.js → webui-server-DD35QFNO.js} +113 -50
- package/dist/webui-server-options.d.ts +16 -0
- package/dist/wiring/brain-and-orchestration.d.ts +4 -1
- package/dist/wiring/director-setup.d.ts +4 -0
- package/dist/wiring/fallback-gate.d.ts +31 -0
- package/dist/wiring/fleet-command-handlers.d.ts +1 -1
- package/dist/wiring/mailbox-bridge-bootstrap.d.ts +3 -1
- package/dist/wiring/management-tools.d.ts +9 -1
- package/dist/wiring/pipeline.d.ts +5 -5
- package/dist/wiring/plugins.d.ts +3 -10
- package/dist/wiring/provider-utility-tools.d.ts +27 -1
- package/dist/wiring/tools.d.ts +4 -5
- package/package.json +23 -23
- package/dist/chunk-GO3TJICK.js +0 -489
|
@@ -3,8 +3,8 @@ import {
|
|
|
3
3
|
loadCachedAcpRegistry,
|
|
4
4
|
refreshAcpRegistry,
|
|
5
5
|
setupProvider
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-MRLYDHQ7.js";
|
|
7
|
+
import "./chunk-PYTFS4MC.js";
|
|
8
8
|
import "./chunk-PJHET45A.js";
|
|
9
9
|
import "./chunk-7OCVIDC7.js";
|
|
10
10
|
|
|
@@ -32,13 +32,14 @@ import { WebSocketServer } from "ws";
|
|
|
32
32
|
|
|
33
33
|
// src/acp-server-agent.ts
|
|
34
34
|
import { Agent, Context, createDefaultPipelines } from "@wrongstack/core/agent";
|
|
35
|
-
import {
|
|
36
|
-
import { DefaultLogger } from "@wrongstack/core/infrastructure";
|
|
35
|
+
import { ToolExecutor } from "@wrongstack/core/execution";
|
|
36
|
+
import { DefaultLogger, DefaultTokenCounter } from "@wrongstack/core/infrastructure";
|
|
37
37
|
import { EventBus, TOKENS } from "@wrongstack/core/kernel";
|
|
38
|
-
import { ToolValidationError } from "@wrongstack/core/types";
|
|
39
38
|
import { ToolRegistry } from "@wrongstack/core/registry";
|
|
40
|
-
import {
|
|
41
|
-
import {
|
|
39
|
+
import { AutoApprovePermissionPolicy, ToolCapabilities } from "@wrongstack/core/security";
|
|
40
|
+
import {
|
|
41
|
+
ToolValidationError
|
|
42
|
+
} from "@wrongstack/core/types";
|
|
42
43
|
import { createDefaultContainer } from "@wrongstack/runtime";
|
|
43
44
|
var AcpServerConfigError = class extends Error {
|
|
44
45
|
constructor(message) {
|
|
@@ -123,7 +124,8 @@ function makeAcpRead(base, api) {
|
|
|
123
124
|
mutating: false,
|
|
124
125
|
execute: async (input) => {
|
|
125
126
|
const i = input ?? {};
|
|
126
|
-
if (!i.path)
|
|
127
|
+
if (!i.path)
|
|
128
|
+
throw new ToolValidationError({ message: "read: path is required", field: "path" });
|
|
127
129
|
const content = await api.readTextFile({
|
|
128
130
|
path: i.path,
|
|
129
131
|
...typeof i.offset === "number" ? { line: i.offset } : {},
|
|
@@ -142,7 +144,8 @@ function makeAcpWrite(base, api) {
|
|
|
142
144
|
...base,
|
|
143
145
|
execute: async (input) => {
|
|
144
146
|
const i = input ?? {};
|
|
145
|
-
if (!i.path)
|
|
147
|
+
if (!i.path)
|
|
148
|
+
throw new ToolValidationError({ message: "write: path is required", field: "path" });
|
|
146
149
|
await api.writeTextFile({ path: i.path, content: i.content ?? "" });
|
|
147
150
|
return { path: i.path, ok: true };
|
|
148
151
|
}
|
|
@@ -153,8 +156,13 @@ function makeAcpEdit(base, api) {
|
|
|
153
156
|
...base,
|
|
154
157
|
execute: async (input) => {
|
|
155
158
|
const i = input ?? {};
|
|
156
|
-
if (!i.path)
|
|
157
|
-
|
|
159
|
+
if (!i.path)
|
|
160
|
+
throw new ToolValidationError({ message: "edit: path is required", field: "path" });
|
|
161
|
+
if (!i.old_string)
|
|
162
|
+
throw new ToolValidationError({
|
|
163
|
+
message: "edit: old_string is required",
|
|
164
|
+
field: "old_string"
|
|
165
|
+
});
|
|
158
166
|
const before = await api.readTextFile({ path: i.path });
|
|
159
167
|
const occurrences = before.split(i.old_string).length - 1;
|
|
160
168
|
if (occurrences === 0) {
|
|
@@ -182,7 +190,8 @@ function makeAcpBash(base, api) {
|
|
|
182
190
|
...base,
|
|
183
191
|
execute: async (input) => {
|
|
184
192
|
const i = input ?? {};
|
|
185
|
-
if (!i.command)
|
|
193
|
+
if (!i.command)
|
|
194
|
+
throw new ToolValidationError({ message: "bash: command is required", field: "command" });
|
|
186
195
|
const { output, exitCode } = await api.runTerminal({
|
|
187
196
|
command: "sh",
|
|
188
197
|
args: ["-c", i.command],
|
|
@@ -219,8 +228,7 @@ function buildAcpServerAgentFactory(deps, options = {}) {
|
|
|
219
228
|
const { provider, providerRegistry } = await bootProvider();
|
|
220
229
|
const events = new EventBus();
|
|
221
230
|
const source = deps.toolRegistry ?? new ToolRegistry();
|
|
222
|
-
const tools =
|
|
223
|
-
for (const t of source.list()) tools.register(t);
|
|
231
|
+
const tools = source.clone();
|
|
224
232
|
if (api) {
|
|
225
233
|
wireClientBackedTools(tools, api);
|
|
226
234
|
}
|
|
@@ -242,7 +250,7 @@ function buildAcpServerAgentFactory(deps, options = {}) {
|
|
|
242
250
|
projectRoot: cwd,
|
|
243
251
|
allowOutsideProjectRoot: config.features?.allowOutsideProjectRoot ?? false,
|
|
244
252
|
model: config.model,
|
|
245
|
-
tools: [...tools.
|
|
253
|
+
tools: [...tools.listForProvider()],
|
|
246
254
|
agentId: "acp-server",
|
|
247
255
|
agentName: "wrongstack-acp"
|
|
248
256
|
});
|
|
@@ -481,7 +489,12 @@ async function runACPWebSocketServer(deps, port) {
|
|
|
481
489
|
return;
|
|
482
490
|
}
|
|
483
491
|
transport.receive(msg);
|
|
484
|
-
void handler.handleMessage(msg)
|
|
492
|
+
void handler.handleMessage(msg).catch((err) => {
|
|
493
|
+
deps.renderer.writeWarning(
|
|
494
|
+
`ACP: failed to handle message: ${err instanceof Error ? err.message : String(err)}
|
|
495
|
+
`
|
|
496
|
+
);
|
|
497
|
+
});
|
|
485
498
|
});
|
|
486
499
|
const teardown = () => {
|
|
487
500
|
handler.close();
|
|
@@ -499,6 +512,12 @@ async function runACPWebSocketServer(deps, port) {
|
|
|
499
512
|
await new Promise((resolve) => {
|
|
500
513
|
const shutdown = () => {
|
|
501
514
|
deps.renderer.writeWarning("\nShutting down ACP WebSocket server...");
|
|
515
|
+
for (const client of wss.clients) {
|
|
516
|
+
try {
|
|
517
|
+
client.terminate();
|
|
518
|
+
} catch {
|
|
519
|
+
}
|
|
520
|
+
}
|
|
502
521
|
wss.close();
|
|
503
522
|
resolve();
|
|
504
523
|
};
|
|
@@ -889,4 +908,4 @@ ${renderAcpBenchText(result)}
|
|
|
889
908
|
export {
|
|
890
909
|
acpCmd
|
|
891
910
|
};
|
|
892
|
-
//# sourceMappingURL=acp-
|
|
911
|
+
//# sourceMappingURL=acp-DATHHPNT.js.map
|
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
* belong in the interactive host. The ACP server is a headless single-turn
|
|
14
14
|
* surface; a future PR can layer richer session behaviour if needed.
|
|
15
15
|
*/
|
|
16
|
+
import type { RunTurnApi } from '@wrongstack/acp/agent';
|
|
16
17
|
import { Agent } from '@wrongstack/core/agent';
|
|
17
18
|
import { type Logger, type PermissionDecision, type PermissionPolicy, type Tool } from '@wrongstack/core/types';
|
|
18
|
-
import type { RunTurnApi } from '@wrongstack/acp/agent';
|
|
19
19
|
import type { SubcommandDeps } from './subcommands/index.js';
|
|
20
20
|
/**
|
|
21
21
|
* Error thrown when the server cannot start because no model provider is
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
restoreFlags
|
|
3
|
+
} from "./chunk-CSAPOCBP.js";
|
|
1
4
|
import "./chunk-7OCVIDC7.js";
|
|
2
5
|
|
|
3
6
|
// src/subcommands/handlers/audit.ts
|
|
4
7
|
import { color, resolveWstackPaths } from "@wrongstack/core/utils";
|
|
5
8
|
import { ToolAuditLog } from "@wrongstack/core/storage";
|
|
6
9
|
var auditCmd = async (args, deps) => {
|
|
10
|
+
args = restoreFlags(args, deps, ["list", "l"]);
|
|
7
11
|
const wpaths = resolveWstackPaths({
|
|
8
12
|
projectRoot: deps.projectRoot,
|
|
9
13
|
userHome: deps.userHome
|
|
@@ -99,4 +103,4 @@ async function listAudits(log, dir, deps) {
|
|
|
99
103
|
export {
|
|
100
104
|
auditCmd
|
|
101
105
|
};
|
|
102
|
-
//# sourceMappingURL=audit-
|
|
106
|
+
//# sourceMappingURL=audit-QRCLEHHW.js.map
|
|
@@ -13,12 +13,12 @@ import {
|
|
|
13
13
|
runOAuthLoginKind,
|
|
14
14
|
runOAuthLoginMenu,
|
|
15
15
|
validateFamily
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-O7XNGCRT.js";
|
|
17
17
|
import {
|
|
18
18
|
parseAuthFlags
|
|
19
|
-
} from "./chunk-
|
|
20
|
-
import "./chunk-
|
|
21
|
-
import "./chunk-
|
|
19
|
+
} from "./chunk-MHF2IJDE.js";
|
|
20
|
+
import "./chunk-ETOEGL3V.js";
|
|
21
|
+
import "./chunk-PYTFS4MC.js";
|
|
22
22
|
import {
|
|
23
23
|
loadConfigProviders,
|
|
24
24
|
maskedKey,
|
|
@@ -27,14 +27,17 @@ import {
|
|
|
27
27
|
nowIso,
|
|
28
28
|
writeKeysBack
|
|
29
29
|
} from "./chunk-PJHET45A.js";
|
|
30
|
-
import
|
|
30
|
+
import {
|
|
31
|
+
restoreFlags
|
|
32
|
+
} from "./chunk-CSAPOCBP.js";
|
|
33
|
+
import "./chunk-263G3FMB.js";
|
|
31
34
|
import {
|
|
32
35
|
activeProfileConfigPath
|
|
33
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-YMXXOOFN.js";
|
|
34
37
|
import "./chunk-7OCVIDC7.js";
|
|
35
38
|
|
|
36
39
|
// src/subcommands/handlers/auth.ts
|
|
37
|
-
import { color as
|
|
40
|
+
import { color as color4 } from "@wrongstack/core/utils";
|
|
38
41
|
|
|
39
42
|
// src/auth-menu/direct.ts
|
|
40
43
|
async function runAuthDirect(deps, opts) {
|
|
@@ -311,8 +314,94 @@ ${color2.amber("?")} Pick: `)).trim().toLowerCase();
|
|
|
311
314
|
}
|
|
312
315
|
}
|
|
313
316
|
|
|
317
|
+
// src/subcommands/handlers/auth-local-help.ts
|
|
318
|
+
import { color as color3 } from "@wrongstack/core/utils";
|
|
319
|
+
var LOCAL_AUTH_FLAGS = [
|
|
320
|
+
{
|
|
321
|
+
flag: "--name <ollama|vllm|lmstudio>",
|
|
322
|
+
description: "Pick a preset (skip the interactive picker). Defaults to the first run; set this for scripting."
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
flag: "--base-url <url>",
|
|
326
|
+
description: "Override the preset default (e.g. `http://gpu-host:8000/v1` for a remote vLLM). Empty falls back to the preset."
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
flag: "--no-key / --skip-key",
|
|
330
|
+
description: "Skip the API-key prompt even for presets that accept one. Use for non-TTY scripted setups."
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
flag: "--no-probe / --skip-probe",
|
|
334
|
+
description: "Skip the health probe. Use when the local server is not running yet but the config must be persisted."
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
flag: "--probe-only",
|
|
338
|
+
description: "Run the probe and report, do not save. Use to re-check a previously-saved provider."
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
flag: "--model <spec> / -m <spec>",
|
|
342
|
+
description: "Pre-populate the saved `models` allowlist. `--model first` / `<N>` consume the probe; `<csv>` is a literal list; bare `--model` clears the allowlist."
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
flag: "--audit [target]",
|
|
346
|
+
description: "Emit JSONL audit events for the save lifecycle. Bare / `stdout` \u2192 stdout; `stderr` \u2192 stderr; `<path>` \u2192 file. Default is silent."
|
|
347
|
+
}
|
|
348
|
+
];
|
|
349
|
+
var LOCAL_FLAG_COLUMN_WIDTH = 38;
|
|
350
|
+
var LOCAL_AUTH_HELP_USAGE = "wstack auth local [--name <id>] [--base-url <url>] [--no-key] [--no-probe|--probe-only] [--model <spec>] [--audit [target]]";
|
|
351
|
+
function wantsLocalHelp(args) {
|
|
352
|
+
return args.includes("--help") || args.includes("-h");
|
|
353
|
+
}
|
|
354
|
+
function renderAuthLocalHelpToString() {
|
|
355
|
+
const lines = [
|
|
356
|
+
color3.bold("wstack auth local \u2014 quick-add Ollama / vLLM / LM Studio"),
|
|
357
|
+
color3.dim(" Pre-fills the base URL, runs a health probe (`GET /v1/models`),"),
|
|
358
|
+
color3.dim(" and persists the allowlist so you can `wstack --provider <id>`"),
|
|
359
|
+
color3.dim(" right away. Use `--no-probe` to skip when the local server is not"),
|
|
360
|
+
color3.dim(" running yet; use `--audit <file>` to capture the save lifecycle."),
|
|
361
|
+
"",
|
|
362
|
+
color3.bold("Usage"),
|
|
363
|
+
` ${LOCAL_AUTH_HELP_USAGE}`,
|
|
364
|
+
"",
|
|
365
|
+
color3.bold("Flags")
|
|
366
|
+
];
|
|
367
|
+
for (const { flag, description } of LOCAL_AUTH_FLAGS) {
|
|
368
|
+
const padded = flag.padEnd(LOCAL_FLAG_COLUMN_WIDTH, " ");
|
|
369
|
+
lines.push(` ${color3.cyan(padded)}${description}`);
|
|
370
|
+
}
|
|
371
|
+
lines.push("");
|
|
372
|
+
lines.push(color3.dim(" See also: `wstack --help` for the top-level command list."));
|
|
373
|
+
lines.push(
|
|
374
|
+
color3.dim(
|
|
375
|
+
" Examples: `wstack auth local --name ollama --no-probe --model 'llama3.1:8b'`"
|
|
376
|
+
)
|
|
377
|
+
);
|
|
378
|
+
lines.push(
|
|
379
|
+
color3.dim(
|
|
380
|
+
" `wstack auth local --name ollama --audit /var/log/wstack-auth.jsonl`"
|
|
381
|
+
)
|
|
382
|
+
);
|
|
383
|
+
return lines.join("\n") + "\n";
|
|
384
|
+
}
|
|
385
|
+
|
|
314
386
|
// src/subcommands/handlers/auth.ts
|
|
315
387
|
var authCmd = async (args, deps) => {
|
|
388
|
+
args = restoreFlags(args, deps, [
|
|
389
|
+
"label",
|
|
390
|
+
"family",
|
|
391
|
+
"base-url",
|
|
392
|
+
"env",
|
|
393
|
+
// `auth local` flags — see the `local` branch below.
|
|
394
|
+
"name",
|
|
395
|
+
"no-key",
|
|
396
|
+
"skip-key",
|
|
397
|
+
"no-probe",
|
|
398
|
+
"skip-probe",
|
|
399
|
+
"probe-only",
|
|
400
|
+
"model",
|
|
401
|
+
"m",
|
|
402
|
+
"help",
|
|
403
|
+
"h"
|
|
404
|
+
]);
|
|
316
405
|
const flags = parseAuthFlags(args);
|
|
317
406
|
const profileConfigPath = activeProfileConfigPath(deps.paths, deps.config);
|
|
318
407
|
const menuDeps = {
|
|
@@ -329,6 +418,30 @@ var authCmd = async (args, deps) => {
|
|
|
329
418
|
if (first === "list" || first === "ls") {
|
|
330
419
|
return runAuthList(menuDeps);
|
|
331
420
|
}
|
|
421
|
+
if (first === "local") {
|
|
422
|
+
if (wantsLocalHelp(args)) {
|
|
423
|
+
deps.renderer.write(`${renderAuthLocalHelpToString()}
|
|
424
|
+
`);
|
|
425
|
+
return 0;
|
|
426
|
+
}
|
|
427
|
+
const value = (name) => {
|
|
428
|
+
const i = args.indexOf(`--${name}`);
|
|
429
|
+
return i >= 0 ? args[i + 1] : void 0;
|
|
430
|
+
};
|
|
431
|
+
const has = (...names) => names.some((n) => args.includes(`--${n}`));
|
|
432
|
+
const modelIdx = args.indexOf("--model") >= 0 ? args.indexOf("--model") : args.indexOf("-m");
|
|
433
|
+
return runAuthLocal(menuDeps, {
|
|
434
|
+
name: flags.positional[1] ?? value("name"),
|
|
435
|
+
baseUrl: flags.baseUrl ?? value("base-url"),
|
|
436
|
+
label: flags.label,
|
|
437
|
+
skipKey: has("no-key", "skip-key"),
|
|
438
|
+
noProbe: has("no-probe", "skip-probe"),
|
|
439
|
+
probeOnly: has("probe-only"),
|
|
440
|
+
// Bare `--model` (no value, or followed by another flag) clears the
|
|
441
|
+
// allowlist, which is why an empty string is meaningful here.
|
|
442
|
+
...modelIdx >= 0 ? { models: args[modelIdx + 1]?.startsWith("-") ? "" : args[modelIdx + 1] ?? "" } : {}
|
|
443
|
+
});
|
|
444
|
+
}
|
|
332
445
|
if (first === "status") {
|
|
333
446
|
const pid = flags.positional[1];
|
|
334
447
|
if (!pid) {
|
|
@@ -352,7 +465,7 @@ var authCmd = async (args, deps) => {
|
|
|
352
465
|
if (kind) return runOAuthLoginKind(menuDeps, kind);
|
|
353
466
|
deps.renderer.writeError("OAuth login is only supported for ChatGPT, Claude, and GitHub Copilot.");
|
|
354
467
|
deps.renderer.write(
|
|
355
|
-
|
|
468
|
+
color4.dim(" Sign in with ChatGPT: ") + color4.bold("wstack auth login chatgpt") + "\n" + color4.dim(" Sign in with Claude: ") + color4.bold("wstack auth login claude") + "\n" + color4.dim(" Sign in with Copilot: ") + color4.bold("wstack auth login copilot") + "\n" + color4.dim(" For an API key instead: ") + color4.bold(`wstack auth ${pid}`) + "\n"
|
|
356
469
|
);
|
|
357
470
|
return 1;
|
|
358
471
|
}
|
|
@@ -375,14 +488,14 @@ async function runAuthList(deps) {
|
|
|
375
488
|
const ids = Object.keys(providers).sort();
|
|
376
489
|
if (ids.length === 0) {
|
|
377
490
|
deps.renderer.write(
|
|
378
|
-
`${
|
|
379
|
-
${
|
|
491
|
+
`${color4.dim("No providers configured.")}
|
|
492
|
+
${color4.dim("Run")} ${color4.bold("wstack auth")} ${color4.dim("to add one.")}
|
|
380
493
|
`
|
|
381
494
|
);
|
|
382
495
|
return 0;
|
|
383
496
|
}
|
|
384
497
|
deps.renderer.write(`
|
|
385
|
-
${
|
|
498
|
+
${color4.bold("Saved providers")} ${color4.dim(`(${ids.length})`)}
|
|
386
499
|
|
|
387
500
|
`);
|
|
388
501
|
for (const id of ids) {
|
|
@@ -390,34 +503,34 @@ ${color3.bold("Saved providers")} ${color3.dim(`(${ids.length})`)}
|
|
|
390
503
|
if (!cfg) continue;
|
|
391
504
|
const keys = normalizeKeys(cfg);
|
|
392
505
|
const active = cfg.activeKey ?? keys[0]?.label;
|
|
393
|
-
const famTag = cfg.family ? `${cfg.family}` :
|
|
394
|
-
const aliasHint = cfg.type && cfg.type !== id ?
|
|
395
|
-
const modelHint = cfg.models && cfg.models.length > 0 ?
|
|
396
|
-
deps.renderer.write(` ${
|
|
506
|
+
const famTag = cfg.family ? `${cfg.family}` : color4.amber("no-family");
|
|
507
|
+
const aliasHint = cfg.type && cfg.type !== id ? color4.dim(` (\u2192 ${cfg.type})`) : "";
|
|
508
|
+
const modelHint = cfg.models && cfg.models.length > 0 ? color4.dim(` [${cfg.models.length} models]`) : "";
|
|
509
|
+
deps.renderer.write(` ${color4.bold(id)}${aliasHint}
|
|
397
510
|
`);
|
|
398
511
|
deps.renderer.write(
|
|
399
|
-
` family: ${famTag} baseUrl: ${cfg.baseUrl ??
|
|
512
|
+
` family: ${famTag} baseUrl: ${cfg.baseUrl ?? color4.dim("unset")}${modelHint}
|
|
400
513
|
`
|
|
401
514
|
);
|
|
402
515
|
if (keys.length === 0) {
|
|
403
|
-
deps.renderer.write(` ${
|
|
516
|
+
deps.renderer.write(` ${color4.amber("no keys")}
|
|
404
517
|
`);
|
|
405
518
|
} else {
|
|
406
519
|
deps.renderer.write(
|
|
407
|
-
` ${
|
|
520
|
+
` ${color4.dim(`${keys.length} key${keys.length === 1 ? "" : "s"}:`)}
|
|
408
521
|
`
|
|
409
522
|
);
|
|
410
523
|
for (const k of keys) {
|
|
411
|
-
const marker = k.label === active ?
|
|
524
|
+
const marker = k.label === active ? color4.green("\u25CF") : color4.dim("\u25CB");
|
|
412
525
|
deps.renderer.write(
|
|
413
|
-
` ${marker} ${k.label.padEnd(18)} ${maskedKey(k.apiKey)} ${
|
|
526
|
+
` ${marker} ${k.label.padEnd(18)} ${maskedKey(k.apiKey)} ${color4.dim(k.createdAt)}
|
|
414
527
|
`
|
|
415
528
|
);
|
|
416
529
|
}
|
|
417
530
|
}
|
|
418
531
|
deps.renderer.write("\n");
|
|
419
532
|
}
|
|
420
|
-
deps.renderer.write(
|
|
533
|
+
deps.renderer.write(color4.dim(`Manage: wstack auth Add key: wstack auth <provider>
|
|
421
534
|
`));
|
|
422
535
|
return 0;
|
|
423
536
|
}
|
|
@@ -433,7 +546,7 @@ async function runAuthStatus(deps, providerId) {
|
|
|
433
546
|
if (!cfg) {
|
|
434
547
|
deps.renderer.writeError(`Provider "${providerId}" not found in config.`);
|
|
435
548
|
deps.renderer.write(
|
|
436
|
-
|
|
549
|
+
color4.dim(`Run ${color4.bold("wstack auth list")} to see saved providers.
|
|
437
550
|
`)
|
|
438
551
|
);
|
|
439
552
|
return 1;
|
|
@@ -442,32 +555,32 @@ async function runAuthStatus(deps, providerId) {
|
|
|
442
555
|
const active = cfg.activeKey ?? keys[0]?.label;
|
|
443
556
|
const lines = [
|
|
444
557
|
`
|
|
445
|
-
${
|
|
558
|
+
${color4.bold(providerId)} ${cfg.family ? color4.dim(`[${cfg.family}]`) : color4.amber("[no family]")}`,
|
|
446
559
|
"",
|
|
447
|
-
` type: ${
|
|
448
|
-
` family: ${cfg.family ?
|
|
449
|
-
` baseUrl: ${cfg.baseUrl ?
|
|
560
|
+
` type: ${color4.cyan(cfg.type ?? providerId)}`,
|
|
561
|
+
` family: ${cfg.family ? color4.cyan(cfg.family) : color4.dim("unset")}`,
|
|
562
|
+
` baseUrl: ${cfg.baseUrl ? color4.cyan(cfg.baseUrl) : color4.dim("unset")}`
|
|
450
563
|
];
|
|
451
564
|
if (cfg.models?.length) {
|
|
452
|
-
lines.push(` models: ${
|
|
565
|
+
lines.push(` models: ${color4.cyan(cfg.models.join(", "))}`);
|
|
453
566
|
}
|
|
454
567
|
if (cfg.envVars?.length) {
|
|
455
|
-
lines.push(` envVars: ${
|
|
568
|
+
lines.push(` envVars: ${color4.cyan(cfg.envVars.join(", "))}`);
|
|
456
569
|
}
|
|
457
570
|
lines.push("");
|
|
458
571
|
if (keys.length === 0) {
|
|
459
|
-
lines.push(
|
|
572
|
+
lines.push(color4.amber(" (no keys saved)"));
|
|
460
573
|
} else {
|
|
461
|
-
lines.push(` ${
|
|
574
|
+
lines.push(` ${color4.dim("Keys:")}`);
|
|
462
575
|
for (const k of keys) {
|
|
463
|
-
const marker = k.label === active ?
|
|
576
|
+
const marker = k.label === active ? color4.green("\u25CF") : color4.dim("\u25CB");
|
|
464
577
|
lines.push(
|
|
465
|
-
` ${marker} ${
|
|
578
|
+
` ${marker} ${color4.bold(k.label.padEnd(18))} ${maskedKey(k.apiKey)} ${color4.dim(k.createdAt)}`
|
|
466
579
|
);
|
|
467
580
|
}
|
|
468
581
|
}
|
|
469
582
|
lines.push("");
|
|
470
|
-
lines.push(
|
|
583
|
+
lines.push(color4.dim(`Manage: wstack auth \u2192 pick ${providerId}`));
|
|
471
584
|
deps.renderer.write(lines.join("\n") + "\n");
|
|
472
585
|
return 0;
|
|
473
586
|
}
|
|
@@ -478,19 +591,19 @@ async function runAuthRemove(deps, providerId) {
|
|
|
478
591
|
return 1;
|
|
479
592
|
}
|
|
480
593
|
deps.renderer.write(
|
|
481
|
-
`${
|
|
594
|
+
`${color4.amber("!")} This will remove "${providerId}" and all its saved keys.
|
|
482
595
|
`
|
|
483
596
|
);
|
|
484
|
-
const answer = (await deps.reader.readLine(` ${
|
|
597
|
+
const answer = (await deps.reader.readLine(` ${color4.amber("?")} Confirm removal? ${color4.dim("[y/N]")} `)).trim().toLowerCase();
|
|
485
598
|
if (answer !== "y" && answer !== "yes") {
|
|
486
|
-
deps.renderer.write(
|
|
599
|
+
deps.renderer.write(color4.dim("Cancelled.\n"));
|
|
487
600
|
return 0;
|
|
488
601
|
}
|
|
489
602
|
try {
|
|
490
603
|
await mutateConfigProviders(deps.profileConfigPath, deps.vault, (all) => {
|
|
491
604
|
delete all[providerId];
|
|
492
605
|
});
|
|
493
|
-
deps.renderer.write(` ${
|
|
606
|
+
deps.renderer.write(` ${color4.green("\u2713")} Removed ${color4.bold(providerId)}.
|
|
494
607
|
`);
|
|
495
608
|
return 0;
|
|
496
609
|
} catch (err) {
|
|
@@ -501,4 +614,4 @@ async function runAuthRemove(deps, providerId) {
|
|
|
501
614
|
export {
|
|
502
615
|
authCmd
|
|
503
616
|
};
|
|
504
|
-
//# sourceMappingURL=auth-
|
|
617
|
+
//# sourceMappingURL=auth-JASC4K3F.js.map
|
|
@@ -1,40 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Terminal-side adapter for the OAuth loopback callback server.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* The server itself — HTTP listener, port fallback, `state` validation, the
|
|
5
|
+
* static callback page and its CSP/anti-framing headers, abort handling — lives
|
|
6
|
+
* in `@wrongstack/providers/oauth`. This file used to carry a second, complete
|
|
7
|
+
* implementation of all of it.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* The copies were not identical, and the difference mattered: this one
|
|
10
|
+
* registered its abort listener with `{ once: true }` and never removed it, so
|
|
11
|
+
* every completed login leaked a listener on the caller's long-lived
|
|
12
|
+
* AbortSignal (the TUI hands the same signal to each attempt). The providers
|
|
13
|
+
* copy had the `detachAbort` cleanup. Neither file had any way to notice the
|
|
14
|
+
* other had drifted.
|
|
13
15
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
16
|
+
* What legitimately stays here is {@link openBrowser}: spawning the platform
|
|
17
|
+
* browser is terminal-only behaviour, and the headless WebUI flows deliberately
|
|
18
|
+
* hand the authorize URL to the client instead of opening anything.
|
|
17
19
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* ```
|
|
20
|
+
* The positional signature below is preserved so the three CLI OAuth flows and
|
|
21
|
+
* their tests keep working unchanged.
|
|
21
22
|
*
|
|
22
23
|
* @module auth-menu/loopback-server
|
|
23
24
|
*/
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
* Shared by all loopback-based OAuth flows so the success/error page styling
|
|
27
|
-
* is consistent and the HTML generation isn't duplicated.
|
|
28
|
-
*/
|
|
29
|
-
export declare function callbackHtml(ok: boolean, message: string): string;
|
|
30
|
-
/**
|
|
31
|
-
* Open a URL in the user's default browser. Best-effort — never throws.
|
|
32
|
-
*
|
|
33
|
-
* - Windows: `cmd /c start "" <url>`
|
|
34
|
-
* - macOS: `open <url>`
|
|
35
|
-
* - Linux: `xdg-open <url>`
|
|
36
|
-
*/
|
|
37
|
-
export declare function openBrowser(url: string): void;
|
|
25
|
+
import { type LoopbackServer } from '@wrongstack/providers/oauth';
|
|
26
|
+
export { callbackHtml, type LoopbackServer } from '@wrongstack/providers/oauth';
|
|
38
27
|
/** Result of waiting for the OAuth callback. */
|
|
39
28
|
export interface LoopbackCallback {
|
|
40
29
|
/** The authorization code from the provider. */
|
|
@@ -42,35 +31,32 @@ export interface LoopbackCallback {
|
|
|
42
31
|
/** The OAuth state parameter from the callback (validated against expected). */
|
|
43
32
|
state: string;
|
|
44
33
|
}
|
|
45
|
-
export interface LoopbackServer {
|
|
46
|
-
/**
|
|
47
|
-
* Wait for the browser to redirect back with the authorization code.
|
|
48
|
-
* Resolves with the code and state, or `null` if cancelled/failed.
|
|
49
|
-
*/
|
|
50
|
-
waitForCode(): Promise<LoopbackCallback | null>;
|
|
51
|
-
/** Close the HTTP server and release the port. */
|
|
52
|
-
close(): void;
|
|
53
|
-
/** True when the server bound to a registered callback port. */
|
|
54
|
-
readonly bound: boolean;
|
|
55
|
-
/** The actual port the server is listening on (matches the authorize URL redirect_uri). */
|
|
56
|
-
readonly port: number;
|
|
57
|
-
}
|
|
58
34
|
/**
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
* The server listens on the first available port from `ports`. If all ports
|
|
62
|
-
* are busy, `bound` is `false` and the caller should fall back to a manual
|
|
63
|
-
* paste prompt.
|
|
35
|
+
* Open a URL in the user's default browser. Best-effort — never throws.
|
|
64
36
|
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
37
|
+
* - Windows: `cmd /c start "" <url>`
|
|
38
|
+
* - macOS: `open <url>`
|
|
39
|
+
* - Linux: `xdg-open <url>`
|
|
68
40
|
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
|
|
41
|
+
* Not `detached`: the CLI flows wait on the loopback callback in the
|
|
42
|
+
* foreground, so the opener is a short-lived handoff. (The WebUI server's
|
|
43
|
+
* `openBrowser` is deliberately different — it detaches and registers the pid
|
|
44
|
+
* as protected because it launches a browser the session must outlive.)
|
|
45
|
+
*/
|
|
46
|
+
export declare function openBrowser(url: string): void;
|
|
47
|
+
/**
|
|
48
|
+
* Start a loopback HTTP server for the OAuth authorization-code callback.
|
|
49
|
+
*
|
|
50
|
+
* Binds the first available port from `ports`. If all are busy, `bound` is
|
|
51
|
+
* `false` and the caller falls back to a manual paste prompt. When `signal`
|
|
52
|
+
* aborts (Ctrl+C, TUI Esc), the pending `waitForCode()` resolves to `null` and
|
|
53
|
+
* the server is torn down.
|
|
54
|
+
*
|
|
55
|
+
* @param expectedState - the OAuth `state` to validate the callback against
|
|
56
|
+
* @param ports - ordered ports to try; first available wins
|
|
57
|
+
* @param signal - optional external cancellation
|
|
58
|
+
* @param callbackPath - path the provider redirects to (default `/auth/callback`)
|
|
59
|
+
* @param redirectHost - hostname to listen on (default `127.0.0.1`)
|
|
74
60
|
*/
|
|
75
61
|
export declare function startLoopbackServer(expectedState: string, ports: readonly number[], signal?: AbortSignal, callbackPath?: string, redirectHost?: string): Promise<LoopbackServer>;
|
|
76
62
|
//# sourceMappingURL=loopback-server.d.ts.map
|