@ordewell/cli 0.4.7 → 0.4.8
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/main.js +121 -77
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -205,15 +205,16 @@ var import_fs2 = require("fs");
|
|
|
205
205
|
var import_os2 = require("os");
|
|
206
206
|
var import_path2 = require("path");
|
|
207
207
|
var import_http = __toESM(require("http"));
|
|
208
|
+
var import_core = require("@ordewell/core");
|
|
208
209
|
var DEFAULT_PORT = 3742;
|
|
209
210
|
var CONFIG_DIR = (0, import_path2.join)((0, import_os2.homedir)(), ".config", "ordewell");
|
|
210
211
|
var LEGACY_PID_FILE = (0, import_path2.join)(CONFIG_DIR, "server.pid");
|
|
211
212
|
function pidFileFor(port) {
|
|
212
213
|
return port === DEFAULT_PORT ? LEGACY_PID_FILE : (0, import_path2.join)(CONFIG_DIR, `server-${port}.pid`);
|
|
213
214
|
}
|
|
214
|
-
function httpGet(url, timeoutMs = 2e3) {
|
|
215
|
+
function httpGet(url, timeoutMs = 2e3, headers = {}) {
|
|
215
216
|
return new Promise((resolve3, reject) => {
|
|
216
|
-
const req = import_http.default.get(url, { timeout: timeoutMs }, (res) => {
|
|
217
|
+
const req = import_http.default.get(url, { timeout: timeoutMs, headers }, (res) => {
|
|
217
218
|
let data = "";
|
|
218
219
|
res.on("data", (chunk) => {
|
|
219
220
|
data += chunk.toString();
|
|
@@ -242,9 +243,14 @@ function getWebServerPath() {
|
|
|
242
243
|
);
|
|
243
244
|
}
|
|
244
245
|
async function isDaemonRunning(port = DEFAULT_PORT) {
|
|
246
|
+
const token = (0, import_core.readDaemonToken)(port);
|
|
245
247
|
try {
|
|
246
|
-
const res = await httpGet(
|
|
247
|
-
|
|
248
|
+
const res = await httpGet(
|
|
249
|
+
`http://127.0.0.1:${port}/api/workspaces`,
|
|
250
|
+
2e3,
|
|
251
|
+
token ? { Authorization: (0, import_core.bearerHeaderValue)(token) } : {}
|
|
252
|
+
);
|
|
253
|
+
return res.status === 200 || res.status === 401;
|
|
248
254
|
} catch {
|
|
249
255
|
return false;
|
|
250
256
|
}
|
|
@@ -292,6 +298,7 @@ async function stopDaemon(port = DEFAULT_PORT) {
|
|
|
292
298
|
const pid = parseInt(pidStr, 10);
|
|
293
299
|
if (!pid || isNaN(pid)) {
|
|
294
300
|
(0, import_fs2.unlinkSync)(pidFile);
|
|
301
|
+
(0, import_core.clearDaemonToken)(port);
|
|
295
302
|
return false;
|
|
296
303
|
}
|
|
297
304
|
process.kill(pid, "SIGTERM");
|
|
@@ -304,6 +311,7 @@ async function stopDaemon(port = DEFAULT_PORT) {
|
|
|
304
311
|
(0, import_fs2.unlinkSync)(pidFile);
|
|
305
312
|
} catch {
|
|
306
313
|
}
|
|
314
|
+
(0, import_core.clearDaemonToken)(port);
|
|
307
315
|
console.log("Server was not running (stale PID removed).");
|
|
308
316
|
return true;
|
|
309
317
|
}
|
|
@@ -344,22 +352,35 @@ function resolvePort(args = []) {
|
|
|
344
352
|
// src/apiClient.ts
|
|
345
353
|
var import_http2 = __toESM(require("http"));
|
|
346
354
|
var import_ws = __toESM(require("ws"));
|
|
355
|
+
var import_core2 = require("@ordewell/core");
|
|
347
356
|
var DEFAULT_HTTP_TIMEOUT_MS = 15 * 60 * 1e3;
|
|
348
357
|
var ApiClient = class {
|
|
349
358
|
port;
|
|
350
359
|
constructor(port) {
|
|
351
360
|
this.port = port || DEFAULT_PORT;
|
|
352
361
|
}
|
|
362
|
+
/**
|
|
363
|
+
* Read at call time rather than at construction: a daemon restarted mid-run
|
|
364
|
+
* mints a new token, and a client built before that restart must pick it up.
|
|
365
|
+
* A missing file is not an error here — the daemon's own 401 names the path.
|
|
366
|
+
*/
|
|
367
|
+
token() {
|
|
368
|
+
return (0, import_core2.readDaemonToken)(this.port);
|
|
369
|
+
}
|
|
353
370
|
httpRequest(method, urlPath, body) {
|
|
354
371
|
return new Promise((resolve3, reject) => {
|
|
355
372
|
const url = new URL(urlPath, `http://127.0.0.1:${this.port}`);
|
|
356
373
|
const configuredTimeout = Number.parseInt(process.env.ORDEWELL_HTTP_TIMEOUT_MS || "", 10);
|
|
374
|
+
const token = this.token();
|
|
357
375
|
const options = {
|
|
358
376
|
hostname: url.hostname,
|
|
359
377
|
port: url.port,
|
|
360
378
|
path: url.pathname + url.search,
|
|
361
379
|
method,
|
|
362
|
-
headers:
|
|
380
|
+
headers: {
|
|
381
|
+
...body ? { "Content-Type": "application/json" } : {},
|
|
382
|
+
...token ? { Authorization: (0, import_core2.bearerHeaderValue)(token) } : {}
|
|
383
|
+
},
|
|
363
384
|
// Planner research on a real repository regularly exceeds two minutes.
|
|
364
385
|
// The benchmark harness uses the same 15-minute default explicitly;
|
|
365
386
|
// keep the env override for callers that need a tighter/looser bound.
|
|
@@ -387,7 +408,7 @@ var ApiClient = class {
|
|
|
387
408
|
req.end();
|
|
388
409
|
});
|
|
389
410
|
}
|
|
390
|
-
async generatePlan(goal, runners2, workspace, sessionId =
|
|
411
|
+
async generatePlan(goal, runners2, workspace, sessionId = (0, import_core2.mintSessionId)()) {
|
|
391
412
|
const res = await this.httpRequest("POST", `/api/plans/${sessionId}/generate`, {
|
|
392
413
|
goal,
|
|
393
414
|
runners: runners2 || void 0,
|
|
@@ -579,10 +600,38 @@ var ApiClient = class {
|
|
|
579
600
|
}
|
|
580
601
|
return res.data;
|
|
581
602
|
}
|
|
603
|
+
/**
|
|
604
|
+
* The one place a session socket is built, so the token travels on both
|
|
605
|
+
* stream paths. It rides as a subprotocol rather than a query parameter, so
|
|
606
|
+
* it never reaches an access log.
|
|
607
|
+
*/
|
|
608
|
+
openSessionSocket(sessionId) {
|
|
609
|
+
const token = this.token();
|
|
610
|
+
const socket = new import_ws.default(
|
|
611
|
+
`ws://127.0.0.1:${this.port}/ws/session/${sessionId}`,
|
|
612
|
+
token ? (0, import_core2.tokenSubprotocols)(token) : void 0
|
|
613
|
+
);
|
|
614
|
+
socket.on("unexpected-response", (_req, res) => {
|
|
615
|
+
let body = "";
|
|
616
|
+
res.on("data", (chunk) => {
|
|
617
|
+
body += chunk.toString();
|
|
618
|
+
});
|
|
619
|
+
res.on("end", () => {
|
|
620
|
+
let reason = "";
|
|
621
|
+
try {
|
|
622
|
+
reason = JSON.parse(body).error ?? "";
|
|
623
|
+
} catch {
|
|
624
|
+
reason = body.trim();
|
|
625
|
+
}
|
|
626
|
+
socket.emit("error", new Error(reason || `Unexpected server response: ${res.statusCode}`));
|
|
627
|
+
socket.emit("close", res.statusCode ?? 1006, Buffer.from(""));
|
|
628
|
+
});
|
|
629
|
+
});
|
|
630
|
+
return socket;
|
|
631
|
+
}
|
|
582
632
|
streamExecution(sessionId, onEvent, onReady) {
|
|
583
633
|
return new Promise((resolve3, reject) => {
|
|
584
|
-
const
|
|
585
|
-
const socket = new import_ws.default(wsUrl);
|
|
634
|
+
const socket = this.openSessionSocket(sessionId);
|
|
586
635
|
let resolved = false;
|
|
587
636
|
let opened = false;
|
|
588
637
|
socket.on("open", () => {
|
|
@@ -633,8 +682,7 @@ var ApiClient = class {
|
|
|
633
682
|
* completion signal, not a terminal WS message like execution has.
|
|
634
683
|
*/
|
|
635
684
|
streamPlanning(sessionId, onEvent) {
|
|
636
|
-
const
|
|
637
|
-
const socket = new import_ws.default(wsUrl);
|
|
685
|
+
const socket = this.openSessionSocket(sessionId);
|
|
638
686
|
socket.on("message", (data) => {
|
|
639
687
|
try {
|
|
640
688
|
onEvent(JSON.parse(data.toString()));
|
|
@@ -866,6 +914,7 @@ function isTransient(event) {
|
|
|
866
914
|
}
|
|
867
915
|
|
|
868
916
|
// src/commands/plan.ts
|
|
917
|
+
var import_core3 = require("@ordewell/core");
|
|
869
918
|
function planTasks(plan) {
|
|
870
919
|
return plan?.tasks || [];
|
|
871
920
|
}
|
|
@@ -987,7 +1036,7 @@ async function handlePlan(subArgs, deps = {}) {
|
|
|
987
1036
|
runners2 = runnerFlags;
|
|
988
1037
|
}
|
|
989
1038
|
console.error(`Generating plan for: "${goal}"...`);
|
|
990
|
-
const sessionId =
|
|
1039
|
+
const sessionId = (0, import_core3.mintSessionId)();
|
|
991
1040
|
const isTty = !!process.stderr.isTTY;
|
|
992
1041
|
let lastLineLength = 0;
|
|
993
1042
|
function renderStep(event) {
|
|
@@ -1318,10 +1367,10 @@ async function handleWeb(subArgs) {
|
|
|
1318
1367
|
}
|
|
1319
1368
|
|
|
1320
1369
|
// src/commands/models.ts
|
|
1321
|
-
var
|
|
1370
|
+
var import_core5 = require("@ordewell/core");
|
|
1322
1371
|
|
|
1323
1372
|
// src/commands/model.ts
|
|
1324
|
-
var
|
|
1373
|
+
var import_core4 = require("@ordewell/core");
|
|
1325
1374
|
|
|
1326
1375
|
// src/catalog.ts
|
|
1327
1376
|
function normalizeCatalog(result) {
|
|
@@ -1425,7 +1474,7 @@ async function handleModel(subArgs, injectedApi) {
|
|
|
1425
1474
|
if (!modelId) fail(USAGE);
|
|
1426
1475
|
const settings = await api.getSettings();
|
|
1427
1476
|
const provider = typeof settings.aiProvider === "string" ? settings.aiProvider : "";
|
|
1428
|
-
const runner = (0,
|
|
1477
|
+
const runner = (0, import_core4.runnerForProvider)(provider);
|
|
1429
1478
|
if (runner) {
|
|
1430
1479
|
const known = (await fetchCatalog(api)).models.filter((m) => m.runners?.includes(runner));
|
|
1431
1480
|
if (known.length > 0 && !known.some((m) => m.id === modelId)) {
|
|
@@ -1444,7 +1493,7 @@ async function showModels(api) {
|
|
|
1444
1493
|
const [settings, catalog] = await Promise.all([api.getSettings(), fetchCatalog(api)]);
|
|
1445
1494
|
const provider = typeof settings.aiProvider === "string" ? settings.aiProvider : "";
|
|
1446
1495
|
const current = typeof settings.orchestratorModel === "string" ? settings.orchestratorModel : "";
|
|
1447
|
-
const runner = (0,
|
|
1496
|
+
const runner = (0, import_core4.runnerForProvider)(provider);
|
|
1448
1497
|
const options = runner ? catalog.models.filter((m) => m.runners?.includes(runner)) : catalog.orchestratorModels;
|
|
1449
1498
|
console.log(`
|
|
1450
1499
|
Planner model: ${current || "(backend default)"}`);
|
|
@@ -1478,8 +1527,8 @@ async function handleModels(subArgs) {
|
|
|
1478
1527
|
const rest = subArgs.filter((_, i) => i !== setIdx && i !== setIdx + 1);
|
|
1479
1528
|
return handleModel(["set", subArgs[setIdx + 1], ...rest]);
|
|
1480
1529
|
}
|
|
1481
|
-
const config = new
|
|
1482
|
-
const providers = (0,
|
|
1530
|
+
const config = new import_core5.EnvConfig();
|
|
1531
|
+
const providers = (0, import_core5.configuredProviders)(config);
|
|
1483
1532
|
if (providers.length === 0) {
|
|
1484
1533
|
console.error("No providers configured. Set an API key for a provider, e.g.:");
|
|
1485
1534
|
console.error(" OPENROUTER_API_KEY=... (OpenRouter)");
|
|
@@ -1488,19 +1537,19 @@ async function handleModels(subArgs) {
|
|
|
1488
1537
|
console.error(" OPENAI_COMPATIBLE_BASE_URL=... (self-hosted / OpenAI-compatible)");
|
|
1489
1538
|
process.exit(1);
|
|
1490
1539
|
}
|
|
1491
|
-
const { apiKeys, baseUrls } = (0,
|
|
1540
|
+
const { apiKeys, baseUrls } = (0, import_core5.collectProviderCredentials)(config);
|
|
1492
1541
|
let models;
|
|
1493
1542
|
let errors;
|
|
1494
1543
|
try {
|
|
1495
|
-
const result = await (0,
|
|
1496
|
-
models = (0,
|
|
1544
|
+
const result = await (0, import_core5.fetchAllProviderModels)({ apiKeys, baseUrls });
|
|
1545
|
+
models = (0, import_core5.toOrchestratorOptions)(result.models, import_core5.ORCHESTRATOR_SHORTCUTS);
|
|
1497
1546
|
errors = result.errors;
|
|
1498
1547
|
} catch (err) {
|
|
1499
1548
|
console.error(`Failed to fetch models: ${err instanceof Error ? err.message : String(err)}`);
|
|
1500
1549
|
process.exit(1);
|
|
1501
1550
|
return;
|
|
1502
1551
|
}
|
|
1503
|
-
const providerLabel = (p) => (0,
|
|
1552
|
+
const providerLabel = (p) => (0, import_core5.getProviderMeta)(p)?.label ?? p;
|
|
1504
1553
|
console.log(
|
|
1505
1554
|
`
|
|
1506
1555
|
Available models (${models.length}) across ${providers.length} configured provider(s):`
|
|
@@ -1617,9 +1666,9 @@ function handleSetup(subArgs) {
|
|
|
1617
1666
|
}
|
|
1618
1667
|
|
|
1619
1668
|
// src/commands/plugins.ts
|
|
1620
|
-
var
|
|
1669
|
+
var import_core6 = require("@ordewell/core");
|
|
1621
1670
|
function handlePlugins(subArgs) {
|
|
1622
|
-
const registry = new
|
|
1671
|
+
const registry = new import_core6.RunnerRegistry();
|
|
1623
1672
|
registry.loadUserPlugins();
|
|
1624
1673
|
const sub = subArgs[0];
|
|
1625
1674
|
if (sub === "list" || !sub) {
|
|
@@ -1655,13 +1704,8 @@ ${plugins.length} plugin(s):
|
|
|
1655
1704
|
process.exit(1);
|
|
1656
1705
|
}
|
|
1657
1706
|
try {
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
const url = source.startsWith("github:") ? `https://github.com/${source.slice(7)}.git` : source;
|
|
1661
|
-
manifest = registry.installFromGit(url);
|
|
1662
|
-
} else {
|
|
1663
|
-
manifest = registry.installFromPath(source);
|
|
1664
|
-
}
|
|
1707
|
+
const resolved = (0, import_core6.classifyPluginSource)(source);
|
|
1708
|
+
const manifest = resolved.kind === "git" ? registry.installFromGit(resolved.url) : registry.installFromPath(resolved.path);
|
|
1665
1709
|
console.log(`Installed plugin: ${manifest.name} v${manifest.version}`);
|
|
1666
1710
|
} catch (err) {
|
|
1667
1711
|
console.error(`Install failed: ${err.message}`);
|
|
@@ -2132,7 +2176,7 @@ async function handleSessions(subArgs, injectedApi) {
|
|
|
2132
2176
|
}
|
|
2133
2177
|
|
|
2134
2178
|
// src/commands/planner.ts
|
|
2135
|
-
var
|
|
2179
|
+
var import_core7 = require("@ordewell/core");
|
|
2136
2180
|
|
|
2137
2181
|
// src/plannerModelSwitch.ts
|
|
2138
2182
|
function describePlannerSwitch(settings, provider) {
|
|
@@ -2151,7 +2195,7 @@ function rememberedModelFor(settings, provider) {
|
|
|
2151
2195
|
}
|
|
2152
2196
|
|
|
2153
2197
|
// src/commands/planner.ts
|
|
2154
|
-
var KNOWN_PROVIDERS = Object.keys(
|
|
2198
|
+
var KNOWN_PROVIDERS = Object.keys(import_core7.ALL_PROVIDERS);
|
|
2155
2199
|
async function handlePlanner(subArgs, injectedApi) {
|
|
2156
2200
|
const api = await connect(subArgs, injectedApi);
|
|
2157
2201
|
const [wanted] = positionals(subArgs);
|
|
@@ -2166,13 +2210,13 @@ async function handlePlanner(subArgs, injectedApi) {
|
|
|
2166
2210
|
const settings = await persistEnv(api, { AI_PROVIDER: provider });
|
|
2167
2211
|
const recall2 = describePlannerSwitch(settings, provider);
|
|
2168
2212
|
writeEnv({ ORCHESTRATOR_MODEL: recall2.model, ORDEWELL_PLANNER_EFFORT: recall2.effort });
|
|
2169
|
-
const meta =
|
|
2213
|
+
const meta = import_core7.ALL_PROVIDERS[provider];
|
|
2170
2214
|
const catalog = await fetchCatalog(api);
|
|
2171
2215
|
console.log(
|
|
2172
|
-
(0,
|
|
2216
|
+
(0, import_core7.isCliProvider)(provider) ? `Planning with ${meta.label} \u2014 no API key needed, it uses that agent's own subscription.` : `Planner set to ${meta.label}.`
|
|
2173
2217
|
);
|
|
2174
2218
|
console.log(plannerModelLine(recall2));
|
|
2175
|
-
if (!(0,
|
|
2219
|
+
if (!(0, import_core7.isCliProvider)(provider) && !catalog.providers.includes(provider)) {
|
|
2176
2220
|
console.log(` No ${meta.apiKeyEnvVar} configured yet \u2014 set one with \`ordewell key set ${provider} <key>\`.`);
|
|
2177
2221
|
}
|
|
2178
2222
|
}
|
|
@@ -2190,15 +2234,15 @@ async function showPlanners(api) {
|
|
|
2190
2234
|
const [settings, catalog] = await Promise.all([api.getSettings(), fetchCatalog(api)]);
|
|
2191
2235
|
const current = typeof settings.aiProvider === "string" ? settings.aiProvider : "";
|
|
2192
2236
|
console.log("\nCoding agents (no API key \u2014 they use their own subscription)");
|
|
2193
|
-
for (const id of
|
|
2194
|
-
const runner = (0,
|
|
2237
|
+
for (const id of import_core7.CLI_PROVIDERS) {
|
|
2238
|
+
const runner = (0, import_core7.runnerForProvider)(id);
|
|
2195
2239
|
const discovered = runner ? catalog.models.some((m) => m.runners?.includes(runner)) : false;
|
|
2196
|
-
console.log(` ${marker(id === current)} ${id.padEnd(14)} ${
|
|
2240
|
+
console.log(` ${marker(id === current)} ${id.padEnd(14)} ${import_core7.ALL_PROVIDERS[id].label}${discovered ? "" : " (not detected)"}`);
|
|
2197
2241
|
}
|
|
2198
2242
|
console.log("\nAPI providers");
|
|
2199
|
-
for (const id of
|
|
2243
|
+
for (const id of import_core7.PROVIDER_PRIORITY) {
|
|
2200
2244
|
const configured = catalog.providers.includes(id);
|
|
2201
|
-
const meta =
|
|
2245
|
+
const meta = import_core7.ALL_PROVIDERS[id];
|
|
2202
2246
|
console.log(` ${marker(id === current)} ${id.padEnd(14)} ${meta.label}${configured ? "" : ` (no ${meta.apiKeyEnvVar})`}`);
|
|
2203
2247
|
}
|
|
2204
2248
|
console.log(`
|
|
@@ -2215,7 +2259,7 @@ async function handlePlannerEffort(subArgs, injectedApi) {
|
|
|
2215
2259
|
const provider = typeof settings.aiProvider === "string" ? settings.aiProvider : "";
|
|
2216
2260
|
const modelId = typeof settings.orchestratorModel === "string" ? settings.orchestratorModel : "";
|
|
2217
2261
|
const currentEffort = typeof settings.plannerThinkingEffort === "string" ? settings.plannerThinkingEffort : "";
|
|
2218
|
-
const runner = (0,
|
|
2262
|
+
const runner = (0, import_core7.runnerForProvider)(provider);
|
|
2219
2263
|
if (!runner) {
|
|
2220
2264
|
fail(
|
|
2221
2265
|
"Thinking effort applies to a coding-agent planner.",
|
|
@@ -2255,7 +2299,7 @@ async function handlePlannerEffort(subArgs, injectedApi) {
|
|
|
2255
2299
|
}
|
|
2256
2300
|
|
|
2257
2301
|
// src/commands/key.ts
|
|
2258
|
-
var
|
|
2302
|
+
var import_core8 = require("@ordewell/core");
|
|
2259
2303
|
var USAGE4 = "Usage: ordewell key [list | set <provider> <key>]";
|
|
2260
2304
|
async function handleKey(subArgs, injectedApi) {
|
|
2261
2305
|
const [action, provider, ...keyParts] = positionals(subArgs);
|
|
@@ -2266,8 +2310,8 @@ async function handleKey(subArgs, injectedApi) {
|
|
|
2266
2310
|
if (action !== "set") {
|
|
2267
2311
|
const catalog = await fetchCatalog(api);
|
|
2268
2312
|
console.log("\nAPI provider keys\n");
|
|
2269
|
-
for (const id2 of
|
|
2270
|
-
const meta2 =
|
|
2313
|
+
for (const id2 of import_core8.PROVIDER_PRIORITY) {
|
|
2314
|
+
const meta2 = import_core8.ALL_PROVIDERS[id2];
|
|
2271
2315
|
const configured = catalog.providers.includes(id2);
|
|
2272
2316
|
console.log(` ${configured ? "\u2713" : " "} ${id2.padEnd(14)} ${meta2.apiKeyEnvVar.padEnd(28)} ${meta2.label}`);
|
|
2273
2317
|
}
|
|
@@ -2277,7 +2321,7 @@ async function handleKey(subArgs, injectedApi) {
|
|
|
2277
2321
|
}
|
|
2278
2322
|
if (!provider) fail(USAGE4);
|
|
2279
2323
|
const id = provider.toLowerCase();
|
|
2280
|
-
const meta =
|
|
2324
|
+
const meta = import_core8.ALL_PROVIDERS[id];
|
|
2281
2325
|
if (!meta) {
|
|
2282
2326
|
fail(`Unknown provider: ${provider}`, "Run `ordewell key` to see the list.");
|
|
2283
2327
|
}
|
|
@@ -2357,7 +2401,7 @@ async function handleApprove(subArgs, injectedApi) {
|
|
|
2357
2401
|
// src/tui/terminalLauncher.ts
|
|
2358
2402
|
var import_child_process3 = require("child_process");
|
|
2359
2403
|
var import_util = require("util");
|
|
2360
|
-
var
|
|
2404
|
+
var import_core9 = require("@ordewell/core");
|
|
2361
2405
|
var execFileAsync = (0, import_util.promisify)(import_child_process3.execFile);
|
|
2362
2406
|
var defaultExecFile = async (command, args) => {
|
|
2363
2407
|
const { stdout, stderr } = await execFileAsync(command, args);
|
|
@@ -2377,16 +2421,16 @@ var defaultWhich = (bin) => {
|
|
|
2377
2421
|
async function openTaskTerminal(port, planSessionId, taskId, deps = {}) {
|
|
2378
2422
|
const platform = deps.platform ?? process.platform;
|
|
2379
2423
|
const env = deps.env ?? process.env;
|
|
2380
|
-
const hasTmuxImpl = deps.hasTmuxImpl ??
|
|
2424
|
+
const hasTmuxImpl = deps.hasTmuxImpl ?? import_core9.hasTmux;
|
|
2381
2425
|
const execFileImpl = deps.execFileImpl ?? defaultExecFile;
|
|
2382
2426
|
const spawnImpl = deps.spawnImpl ?? defaultSpawn;
|
|
2383
2427
|
const which = deps.which ?? defaultWhich;
|
|
2384
2428
|
if (!hasTmuxImpl()) {
|
|
2385
2429
|
return { ok: false, message: "tmux is not installed \u2014 install it to get a real terminal per task." };
|
|
2386
2430
|
}
|
|
2387
|
-
const session = (0,
|
|
2388
|
-
const socket = (0,
|
|
2389
|
-
const base = (0,
|
|
2431
|
+
const session = (0, import_core9.tmuxSessionName)(port);
|
|
2432
|
+
const socket = (0, import_core9.tmuxSocketName)(port);
|
|
2433
|
+
const base = (0, import_core9.tmuxWindowName)(taskId, planSessionId);
|
|
2390
2434
|
let windows;
|
|
2391
2435
|
try {
|
|
2392
2436
|
const { stdout } = await execFileImpl("tmux", ["-L", socket, "list-windows", "-t", session, "-F", "#{window_name}"]);
|
|
@@ -2680,7 +2724,7 @@ Dependencies \xB7 #${task.order} ${task.title}
|
|
|
2680
2724
|
}
|
|
2681
2725
|
|
|
2682
2726
|
// src/tui/index.ts
|
|
2683
|
-
var
|
|
2727
|
+
var import_core13 = require("@ordewell/core");
|
|
2684
2728
|
|
|
2685
2729
|
// src/tui/ansi.ts
|
|
2686
2730
|
var import_string_width = __toESM(require("string-width"));
|
|
@@ -3212,7 +3256,7 @@ function initialState(overrides = {}) {
|
|
|
3212
3256
|
}
|
|
3213
3257
|
|
|
3214
3258
|
// src/tui/layout.ts
|
|
3215
|
-
var
|
|
3259
|
+
var import_core10 = require("@ordewell/core");
|
|
3216
3260
|
var CHROME_ROWS = 4;
|
|
3217
3261
|
function chatInputWrap(state) {
|
|
3218
3262
|
const active = state.focus === "chat" && !state.overlay;
|
|
@@ -3348,9 +3392,9 @@ function chatScrollMax(state) {
|
|
|
3348
3392
|
}
|
|
3349
3393
|
function plannerSetup(state) {
|
|
3350
3394
|
const provider = state.plannerProvider;
|
|
3351
|
-
const registration =
|
|
3395
|
+
const registration = import_core10.ALL_PROVIDERS[provider];
|
|
3352
3396
|
if (!registration) return { label: "not set", ready: false };
|
|
3353
|
-
const runner = (0,
|
|
3397
|
+
const runner = (0, import_core10.runnerForProvider)(provider);
|
|
3354
3398
|
const ready = runner ? state.runners.some((r) => r.id === runner) : state.configuredProviders.includes(provider);
|
|
3355
3399
|
return { label: registration.label, ready };
|
|
3356
3400
|
}
|
|
@@ -3844,9 +3888,9 @@ function frame(title, body, rows, cols) {
|
|
|
3844
3888
|
}
|
|
3845
3889
|
|
|
3846
3890
|
// src/tui/reducer.ts
|
|
3847
|
-
var
|
|
3891
|
+
var import_core11 = require("@ordewell/core");
|
|
3848
3892
|
var import_plan_utils3 = require("@ordewell/core/plan-utils");
|
|
3849
|
-
var KNOWN_PROVIDERS2 = Object.keys(
|
|
3893
|
+
var KNOWN_PROVIDERS2 = Object.keys(import_core11.ALL_PROVIDERS);
|
|
3850
3894
|
var DEFAULT_EFFORT = "__runner_default__";
|
|
3851
3895
|
function step(state, effects = []) {
|
|
3852
3896
|
return { state, effects };
|
|
@@ -4115,11 +4159,11 @@ function modelDetail(m) {
|
|
|
4115
4159
|
function providerErrorHint(state) {
|
|
4116
4160
|
const failed = Object.keys(state.providerErrors ?? {});
|
|
4117
4161
|
if (failed.length === 0) return void 0;
|
|
4118
|
-
const names = failed.map((p) =>
|
|
4162
|
+
const names = failed.map((p) => import_core11.ALL_PROVIDERS[p]?.label ?? p);
|
|
4119
4163
|
return `\u26A0 Unavailable (key or fetch failed): ${names.join(", ")} \u2014 showing working providers only.`;
|
|
4120
4164
|
}
|
|
4121
4165
|
function plannerModelItems(state) {
|
|
4122
|
-
const runner = (0,
|
|
4166
|
+
const runner = (0, import_core11.runnerForProvider)(state.plannerProvider);
|
|
4123
4167
|
if (!runner) return state.orchestratorModels.map((m) => ({ id: m.id, label: m.label, detail: modelDetail(m) }));
|
|
4124
4168
|
const items = state.models.filter((m) => m.runners?.includes(runner)).map((m) => ({
|
|
4125
4169
|
id: m.id,
|
|
@@ -4130,7 +4174,7 @@ function plannerModelItems(state) {
|
|
|
4130
4174
|
return items.length > 0 ? items : [{ id: "", label: `No ${runner} models discovered yet`, detail: "run /refresh", disabled: true }];
|
|
4131
4175
|
}
|
|
4132
4176
|
function plannerEffortItems(state) {
|
|
4133
|
-
const runner = (0,
|
|
4177
|
+
const runner = (0, import_core11.runnerForProvider)(state.plannerProvider);
|
|
4134
4178
|
if (!runner) {
|
|
4135
4179
|
return [{ id: "", label: "Thinking effort applies to a coding-agent planner", detail: "switch with /planner", disabled: true }];
|
|
4136
4180
|
}
|
|
@@ -4768,7 +4812,7 @@ function newSession(state) {
|
|
|
4768
4812
|
}
|
|
4769
4813
|
function setModel(state, args) {
|
|
4770
4814
|
if (args[0] === "set" && args[1]) {
|
|
4771
|
-
const runner = (0,
|
|
4815
|
+
const runner = (0, import_core11.runnerForProvider)(state.plannerProvider);
|
|
4772
4816
|
const known = runner ? modelsForRunner(state.models, runner) : [];
|
|
4773
4817
|
if (runner && known.length > 0 && !known.some((m) => m.id === args[1])) {
|
|
4774
4818
|
return fail2(state, `${args[1]} was not discovered for ${runner}.`);
|
|
@@ -4790,21 +4834,21 @@ function setModel(state, args) {
|
|
|
4790
4834
|
}
|
|
4791
4835
|
function plannerItems(state) {
|
|
4792
4836
|
const installed = new Set(state.runners.map((r) => r.id));
|
|
4793
|
-
const agents =
|
|
4794
|
-
const runner = (0,
|
|
4837
|
+
const agents = import_core11.CLI_PROVIDERS.map((id) => {
|
|
4838
|
+
const runner = (0, import_core11.runnerForProvider)(id);
|
|
4795
4839
|
const ready = installed.has(runner);
|
|
4796
4840
|
return {
|
|
4797
4841
|
id,
|
|
4798
|
-
label:
|
|
4842
|
+
label: import_core11.ALL_PROVIDERS[id].label,
|
|
4799
4843
|
detail: ready ? "coding agent \xB7 no API key needed" : "CLI not installed or not on PATH",
|
|
4800
4844
|
selected: state.plannerProvider === id,
|
|
4801
4845
|
disabled: !ready
|
|
4802
4846
|
};
|
|
4803
4847
|
});
|
|
4804
|
-
const vendors =
|
|
4848
|
+
const vendors = import_core11.PROVIDER_PRIORITY.filter((id) => state.configuredProviders.includes(id)).map((id) => ({
|
|
4805
4849
|
id,
|
|
4806
|
-
label:
|
|
4807
|
-
detail:
|
|
4850
|
+
label: import_core11.ALL_PROVIDERS[id].label,
|
|
4851
|
+
detail: import_core11.ALL_PROVIDERS[id].apiKeyEnvVar,
|
|
4808
4852
|
selected: state.plannerProvider === id
|
|
4809
4853
|
}));
|
|
4810
4854
|
return vendors.length > 0 ? [...agents, ...vendors] : [...agents, { id: "", label: "No API providers configured", detail: "add a key with /key", disabled: true }];
|
|
@@ -4862,16 +4906,16 @@ function setKey(state, args) {
|
|
|
4862
4906
|
}
|
|
4863
4907
|
return step(state, [{ type: "setApiKey", provider, key: args.slice(2).join(" ") }]);
|
|
4864
4908
|
}
|
|
4865
|
-
const items =
|
|
4909
|
+
const items = import_core11.PROVIDER_PRIORITY.map((id) => ({
|
|
4866
4910
|
id,
|
|
4867
|
-
label:
|
|
4868
|
-
detail:
|
|
4911
|
+
label: import_core11.ALL_PROVIDERS[id].label,
|
|
4912
|
+
detail: import_core11.ALL_PROVIDERS[id].apiKeyEnvVar,
|
|
4869
4913
|
selected: state.configuredProviders.includes(id)
|
|
4870
4914
|
}));
|
|
4871
4915
|
return step({ ...state, overlay: { kind: "picker", picker: picker("API provider key", items, { kind: "set-key" }) } });
|
|
4872
4916
|
}
|
|
4873
4917
|
function keyPrompt(provider) {
|
|
4874
|
-
const meta =
|
|
4918
|
+
const meta = import_core11.ALL_PROVIDERS[provider];
|
|
4875
4919
|
return {
|
|
4876
4920
|
kind: "prompt",
|
|
4877
4921
|
title: `${meta.label} API key`,
|
|
@@ -5229,7 +5273,7 @@ function createApp(deps) {
|
|
|
5229
5273
|
|
|
5230
5274
|
// src/tui/effects.ts
|
|
5231
5275
|
var import_child_process4 = require("child_process");
|
|
5232
|
-
var
|
|
5276
|
+
var import_core12 = require("@ordewell/core");
|
|
5233
5277
|
var import_plan_utils4 = require("@ordewell/core/plan-utils");
|
|
5234
5278
|
var ConversationQueue = class {
|
|
5235
5279
|
tail = Promise.resolve();
|
|
@@ -5396,7 +5440,7 @@ async function perform(effect, deps) {
|
|
|
5396
5440
|
dispatch({ type: "notice", message: `Orchestrator model set to ${effect.modelId}.` });
|
|
5397
5441
|
return;
|
|
5398
5442
|
case "setPlanner": {
|
|
5399
|
-
const meta =
|
|
5443
|
+
const meta = import_core12.ALL_PROVIDERS[effect.provider];
|
|
5400
5444
|
if (!meta) throw new Error(`Unknown planner: ${effect.provider}`);
|
|
5401
5445
|
const env = { AI_PROVIDER: effect.provider };
|
|
5402
5446
|
const settings = await api.updateSettings({ env });
|
|
@@ -5408,7 +5452,7 @@ async function perform(effect, deps) {
|
|
|
5408
5452
|
});
|
|
5409
5453
|
dispatch({
|
|
5410
5454
|
type: "notice",
|
|
5411
|
-
message: `${(0,
|
|
5455
|
+
message: `${(0, import_core12.isCliProvider)(effect.provider) ? `Planning with ${meta.label} \u2014 no API key needed.` : `Planner set to ${meta.label}.`} ${plannerModelNotice(recall2)}`
|
|
5412
5456
|
});
|
|
5413
5457
|
await loadModels(deps);
|
|
5414
5458
|
return;
|
|
@@ -5420,7 +5464,7 @@ async function perform(effect, deps) {
|
|
|
5420
5464
|
dispatch({ type: "notice", message: `Planner effort set to ${effect.effort || "the runner default"}.` });
|
|
5421
5465
|
return;
|
|
5422
5466
|
case "setApiKey": {
|
|
5423
|
-
const meta =
|
|
5467
|
+
const meta = import_core12.ALL_PROVIDERS[effect.provider];
|
|
5424
5468
|
if (!meta) throw new Error(`Unknown provider: ${effect.provider}`);
|
|
5425
5469
|
await api.updateSettings({ env: { [meta.apiKeyEnvVar]: effect.key } });
|
|
5426
5470
|
deps.setEnvVar(meta.apiKeyEnvVar, effect.key);
|
|
@@ -5508,7 +5552,7 @@ function osc52(text) {
|
|
|
5508
5552
|
function copySelection(deps, text) {
|
|
5509
5553
|
if (!text) return;
|
|
5510
5554
|
const lines = text.split("\n").length;
|
|
5511
|
-
const command = (0,
|
|
5555
|
+
const command = (0, import_core12.clipboardCopyCommand)(deps.hasBin);
|
|
5512
5556
|
if (command) {
|
|
5513
5557
|
try {
|
|
5514
5558
|
(deps.pipeToClipboard ?? pipeToClipboardDefault)(command, text);
|
|
@@ -5982,7 +6026,7 @@ async function handleTui(subArgs) {
|
|
|
5982
6026
|
}
|
|
5983
6027
|
const workspace = flag(subArgs, "--workspace") || process.cwd();
|
|
5984
6028
|
try {
|
|
5985
|
-
(0,
|
|
6029
|
+
(0, import_core13.assertWorkspaceExists)(workspace);
|
|
5986
6030
|
} catch {
|
|
5987
6031
|
console.error(
|
|
5988
6032
|
`Workspace "${workspace}" does not exist.
|
|
@@ -6007,7 +6051,7 @@ cd into a directory that exists, or pass --workspace <path> naming one that does
|
|
|
6007
6051
|
conversationQueue,
|
|
6008
6052
|
port,
|
|
6009
6053
|
dispatch: (action) => app.dispatch(action),
|
|
6010
|
-
newSessionId: () =>
|
|
6054
|
+
newSessionId: () => (0, import_core13.mintSessionId)(),
|
|
6011
6055
|
setEnvVar: (key, value) => {
|
|
6012
6056
|
writeEnvVar(findEnvFile(), key, value);
|
|
6013
6057
|
process.env[key] = value;
|
package/package.json
CHANGED