@ordewell/cli 0.4.7 → 0.4.9
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 +128 -79
- 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) {
|
|
@@ -1360,7 +1409,8 @@ function normalizeCatalog(result) {
|
|
|
1360
1409
|
(modes ?? []).map((m) => ({
|
|
1361
1410
|
id: String(m.id),
|
|
1362
1411
|
label: String(m.label ?? m.id),
|
|
1363
|
-
description: m.description ? String(m.description) : void 0
|
|
1412
|
+
description: m.description ? String(m.description) : void 0,
|
|
1413
|
+
autonomous: m.autonomous ? true : void 0
|
|
1364
1414
|
}))
|
|
1365
1415
|
])
|
|
1366
1416
|
)
|
|
@@ -1425,7 +1475,7 @@ async function handleModel(subArgs, injectedApi) {
|
|
|
1425
1475
|
if (!modelId) fail(USAGE);
|
|
1426
1476
|
const settings = await api.getSettings();
|
|
1427
1477
|
const provider = typeof settings.aiProvider === "string" ? settings.aiProvider : "";
|
|
1428
|
-
const runner = (0,
|
|
1478
|
+
const runner = (0, import_core4.runnerForProvider)(provider);
|
|
1429
1479
|
if (runner) {
|
|
1430
1480
|
const known = (await fetchCatalog(api)).models.filter((m) => m.runners?.includes(runner));
|
|
1431
1481
|
if (known.length > 0 && !known.some((m) => m.id === modelId)) {
|
|
@@ -1444,7 +1494,7 @@ async function showModels(api) {
|
|
|
1444
1494
|
const [settings, catalog] = await Promise.all([api.getSettings(), fetchCatalog(api)]);
|
|
1445
1495
|
const provider = typeof settings.aiProvider === "string" ? settings.aiProvider : "";
|
|
1446
1496
|
const current = typeof settings.orchestratorModel === "string" ? settings.orchestratorModel : "";
|
|
1447
|
-
const runner = (0,
|
|
1497
|
+
const runner = (0, import_core4.runnerForProvider)(provider);
|
|
1448
1498
|
const options = runner ? catalog.models.filter((m) => m.runners?.includes(runner)) : catalog.orchestratorModels;
|
|
1449
1499
|
console.log(`
|
|
1450
1500
|
Planner model: ${current || "(backend default)"}`);
|
|
@@ -1478,8 +1528,8 @@ async function handleModels(subArgs) {
|
|
|
1478
1528
|
const rest = subArgs.filter((_, i) => i !== setIdx && i !== setIdx + 1);
|
|
1479
1529
|
return handleModel(["set", subArgs[setIdx + 1], ...rest]);
|
|
1480
1530
|
}
|
|
1481
|
-
const config = new
|
|
1482
|
-
const providers = (0,
|
|
1531
|
+
const config = new import_core5.EnvConfig();
|
|
1532
|
+
const providers = (0, import_core5.configuredProviders)(config);
|
|
1483
1533
|
if (providers.length === 0) {
|
|
1484
1534
|
console.error("No providers configured. Set an API key for a provider, e.g.:");
|
|
1485
1535
|
console.error(" OPENROUTER_API_KEY=... (OpenRouter)");
|
|
@@ -1488,19 +1538,19 @@ async function handleModels(subArgs) {
|
|
|
1488
1538
|
console.error(" OPENAI_COMPATIBLE_BASE_URL=... (self-hosted / OpenAI-compatible)");
|
|
1489
1539
|
process.exit(1);
|
|
1490
1540
|
}
|
|
1491
|
-
const { apiKeys, baseUrls } = (0,
|
|
1541
|
+
const { apiKeys, baseUrls } = (0, import_core5.collectProviderCredentials)(config);
|
|
1492
1542
|
let models;
|
|
1493
1543
|
let errors;
|
|
1494
1544
|
try {
|
|
1495
|
-
const result = await (0,
|
|
1496
|
-
models = (0,
|
|
1545
|
+
const result = await (0, import_core5.fetchAllProviderModels)({ apiKeys, baseUrls });
|
|
1546
|
+
models = (0, import_core5.toOrchestratorOptions)(result.models, import_core5.ORCHESTRATOR_SHORTCUTS);
|
|
1497
1547
|
errors = result.errors;
|
|
1498
1548
|
} catch (err) {
|
|
1499
1549
|
console.error(`Failed to fetch models: ${err instanceof Error ? err.message : String(err)}`);
|
|
1500
1550
|
process.exit(1);
|
|
1501
1551
|
return;
|
|
1502
1552
|
}
|
|
1503
|
-
const providerLabel = (p) => (0,
|
|
1553
|
+
const providerLabel = (p) => (0, import_core5.getProviderMeta)(p)?.label ?? p;
|
|
1504
1554
|
console.log(
|
|
1505
1555
|
`
|
|
1506
1556
|
Available models (${models.length}) across ${providers.length} configured provider(s):`
|
|
@@ -1617,9 +1667,9 @@ function handleSetup(subArgs) {
|
|
|
1617
1667
|
}
|
|
1618
1668
|
|
|
1619
1669
|
// src/commands/plugins.ts
|
|
1620
|
-
var
|
|
1670
|
+
var import_core6 = require("@ordewell/core");
|
|
1621
1671
|
function handlePlugins(subArgs) {
|
|
1622
|
-
const registry = new
|
|
1672
|
+
const registry = new import_core6.RunnerRegistry();
|
|
1623
1673
|
registry.loadUserPlugins();
|
|
1624
1674
|
const sub = subArgs[0];
|
|
1625
1675
|
if (sub === "list" || !sub) {
|
|
@@ -1655,13 +1705,8 @@ ${plugins.length} plugin(s):
|
|
|
1655
1705
|
process.exit(1);
|
|
1656
1706
|
}
|
|
1657
1707
|
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
|
-
}
|
|
1708
|
+
const resolved = (0, import_core6.classifyPluginSource)(source);
|
|
1709
|
+
const manifest = resolved.kind === "git" ? registry.installFromGit(resolved.url) : registry.installFromPath(resolved.path);
|
|
1665
1710
|
console.log(`Installed plugin: ${manifest.name} v${manifest.version}`);
|
|
1666
1711
|
} catch (err) {
|
|
1667
1712
|
console.error(`Install failed: ${err.message}`);
|
|
@@ -2132,7 +2177,7 @@ async function handleSessions(subArgs, injectedApi) {
|
|
|
2132
2177
|
}
|
|
2133
2178
|
|
|
2134
2179
|
// src/commands/planner.ts
|
|
2135
|
-
var
|
|
2180
|
+
var import_core7 = require("@ordewell/core");
|
|
2136
2181
|
|
|
2137
2182
|
// src/plannerModelSwitch.ts
|
|
2138
2183
|
function describePlannerSwitch(settings, provider) {
|
|
@@ -2151,7 +2196,7 @@ function rememberedModelFor(settings, provider) {
|
|
|
2151
2196
|
}
|
|
2152
2197
|
|
|
2153
2198
|
// src/commands/planner.ts
|
|
2154
|
-
var KNOWN_PROVIDERS = Object.keys(
|
|
2199
|
+
var KNOWN_PROVIDERS = Object.keys(import_core7.ALL_PROVIDERS);
|
|
2155
2200
|
async function handlePlanner(subArgs, injectedApi) {
|
|
2156
2201
|
const api = await connect(subArgs, injectedApi);
|
|
2157
2202
|
const [wanted] = positionals(subArgs);
|
|
@@ -2166,13 +2211,13 @@ async function handlePlanner(subArgs, injectedApi) {
|
|
|
2166
2211
|
const settings = await persistEnv(api, { AI_PROVIDER: provider });
|
|
2167
2212
|
const recall2 = describePlannerSwitch(settings, provider);
|
|
2168
2213
|
writeEnv({ ORCHESTRATOR_MODEL: recall2.model, ORDEWELL_PLANNER_EFFORT: recall2.effort });
|
|
2169
|
-
const meta =
|
|
2214
|
+
const meta = import_core7.ALL_PROVIDERS[provider];
|
|
2170
2215
|
const catalog = await fetchCatalog(api);
|
|
2171
2216
|
console.log(
|
|
2172
|
-
(0,
|
|
2217
|
+
(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
2218
|
);
|
|
2174
2219
|
console.log(plannerModelLine(recall2));
|
|
2175
|
-
if (!(0,
|
|
2220
|
+
if (!(0, import_core7.isCliProvider)(provider) && !catalog.providers.includes(provider)) {
|
|
2176
2221
|
console.log(` No ${meta.apiKeyEnvVar} configured yet \u2014 set one with \`ordewell key set ${provider} <key>\`.`);
|
|
2177
2222
|
}
|
|
2178
2223
|
}
|
|
@@ -2190,15 +2235,15 @@ async function showPlanners(api) {
|
|
|
2190
2235
|
const [settings, catalog] = await Promise.all([api.getSettings(), fetchCatalog(api)]);
|
|
2191
2236
|
const current = typeof settings.aiProvider === "string" ? settings.aiProvider : "";
|
|
2192
2237
|
console.log("\nCoding agents (no API key \u2014 they use their own subscription)");
|
|
2193
|
-
for (const id of
|
|
2194
|
-
const runner = (0,
|
|
2238
|
+
for (const id of import_core7.CLI_PROVIDERS) {
|
|
2239
|
+
const runner = (0, import_core7.runnerForProvider)(id);
|
|
2195
2240
|
const discovered = runner ? catalog.models.some((m) => m.runners?.includes(runner)) : false;
|
|
2196
|
-
console.log(` ${marker(id === current)} ${id.padEnd(14)} ${
|
|
2241
|
+
console.log(` ${marker(id === current)} ${id.padEnd(14)} ${import_core7.ALL_PROVIDERS[id].label}${discovered ? "" : " (not detected)"}`);
|
|
2197
2242
|
}
|
|
2198
2243
|
console.log("\nAPI providers");
|
|
2199
|
-
for (const id of
|
|
2244
|
+
for (const id of import_core7.PROVIDER_PRIORITY) {
|
|
2200
2245
|
const configured = catalog.providers.includes(id);
|
|
2201
|
-
const meta =
|
|
2246
|
+
const meta = import_core7.ALL_PROVIDERS[id];
|
|
2202
2247
|
console.log(` ${marker(id === current)} ${id.padEnd(14)} ${meta.label}${configured ? "" : ` (no ${meta.apiKeyEnvVar})`}`);
|
|
2203
2248
|
}
|
|
2204
2249
|
console.log(`
|
|
@@ -2215,7 +2260,7 @@ async function handlePlannerEffort(subArgs, injectedApi) {
|
|
|
2215
2260
|
const provider = typeof settings.aiProvider === "string" ? settings.aiProvider : "";
|
|
2216
2261
|
const modelId = typeof settings.orchestratorModel === "string" ? settings.orchestratorModel : "";
|
|
2217
2262
|
const currentEffort = typeof settings.plannerThinkingEffort === "string" ? settings.plannerThinkingEffort : "";
|
|
2218
|
-
const runner = (0,
|
|
2263
|
+
const runner = (0, import_core7.runnerForProvider)(provider);
|
|
2219
2264
|
if (!runner) {
|
|
2220
2265
|
fail(
|
|
2221
2266
|
"Thinking effort applies to a coding-agent planner.",
|
|
@@ -2255,7 +2300,7 @@ async function handlePlannerEffort(subArgs, injectedApi) {
|
|
|
2255
2300
|
}
|
|
2256
2301
|
|
|
2257
2302
|
// src/commands/key.ts
|
|
2258
|
-
var
|
|
2303
|
+
var import_core8 = require("@ordewell/core");
|
|
2259
2304
|
var USAGE4 = "Usage: ordewell key [list | set <provider> <key>]";
|
|
2260
2305
|
async function handleKey(subArgs, injectedApi) {
|
|
2261
2306
|
const [action, provider, ...keyParts] = positionals(subArgs);
|
|
@@ -2266,8 +2311,8 @@ async function handleKey(subArgs, injectedApi) {
|
|
|
2266
2311
|
if (action !== "set") {
|
|
2267
2312
|
const catalog = await fetchCatalog(api);
|
|
2268
2313
|
console.log("\nAPI provider keys\n");
|
|
2269
|
-
for (const id2 of
|
|
2270
|
-
const meta2 =
|
|
2314
|
+
for (const id2 of import_core8.PROVIDER_PRIORITY) {
|
|
2315
|
+
const meta2 = import_core8.ALL_PROVIDERS[id2];
|
|
2271
2316
|
const configured = catalog.providers.includes(id2);
|
|
2272
2317
|
console.log(` ${configured ? "\u2713" : " "} ${id2.padEnd(14)} ${meta2.apiKeyEnvVar.padEnd(28)} ${meta2.label}`);
|
|
2273
2318
|
}
|
|
@@ -2277,7 +2322,7 @@ async function handleKey(subArgs, injectedApi) {
|
|
|
2277
2322
|
}
|
|
2278
2323
|
if (!provider) fail(USAGE4);
|
|
2279
2324
|
const id = provider.toLowerCase();
|
|
2280
|
-
const meta =
|
|
2325
|
+
const meta = import_core8.ALL_PROVIDERS[id];
|
|
2281
2326
|
if (!meta) {
|
|
2282
2327
|
fail(`Unknown provider: ${provider}`, "Run `ordewell key` to see the list.");
|
|
2283
2328
|
}
|
|
@@ -2357,7 +2402,7 @@ async function handleApprove(subArgs, injectedApi) {
|
|
|
2357
2402
|
// src/tui/terminalLauncher.ts
|
|
2358
2403
|
var import_child_process3 = require("child_process");
|
|
2359
2404
|
var import_util = require("util");
|
|
2360
|
-
var
|
|
2405
|
+
var import_core9 = require("@ordewell/core");
|
|
2361
2406
|
var execFileAsync = (0, import_util.promisify)(import_child_process3.execFile);
|
|
2362
2407
|
var defaultExecFile = async (command, args) => {
|
|
2363
2408
|
const { stdout, stderr } = await execFileAsync(command, args);
|
|
@@ -2377,16 +2422,16 @@ var defaultWhich = (bin) => {
|
|
|
2377
2422
|
async function openTaskTerminal(port, planSessionId, taskId, deps = {}) {
|
|
2378
2423
|
const platform = deps.platform ?? process.platform;
|
|
2379
2424
|
const env = deps.env ?? process.env;
|
|
2380
|
-
const hasTmuxImpl = deps.hasTmuxImpl ??
|
|
2425
|
+
const hasTmuxImpl = deps.hasTmuxImpl ?? import_core9.hasTmux;
|
|
2381
2426
|
const execFileImpl = deps.execFileImpl ?? defaultExecFile;
|
|
2382
2427
|
const spawnImpl = deps.spawnImpl ?? defaultSpawn;
|
|
2383
2428
|
const which = deps.which ?? defaultWhich;
|
|
2384
2429
|
if (!hasTmuxImpl()) {
|
|
2385
2430
|
return { ok: false, message: "tmux is not installed \u2014 install it to get a real terminal per task." };
|
|
2386
2431
|
}
|
|
2387
|
-
const session = (0,
|
|
2388
|
-
const socket = (0,
|
|
2389
|
-
const base = (0,
|
|
2432
|
+
const session = (0, import_core9.tmuxSessionName)(port);
|
|
2433
|
+
const socket = (0, import_core9.tmuxSocketName)(port);
|
|
2434
|
+
const base = (0, import_core9.tmuxWindowName)(taskId, planSessionId);
|
|
2390
2435
|
let windows;
|
|
2391
2436
|
try {
|
|
2392
2437
|
const { stdout } = await execFileImpl("tmux", ["-L", socket, "list-windows", "-t", session, "-F", "#{window_name}"]);
|
|
@@ -2680,7 +2725,7 @@ Dependencies \xB7 #${task.order} ${task.title}
|
|
|
2680
2725
|
}
|
|
2681
2726
|
|
|
2682
2727
|
// src/tui/index.ts
|
|
2683
|
-
var
|
|
2728
|
+
var import_core13 = require("@ordewell/core");
|
|
2684
2729
|
|
|
2685
2730
|
// src/tui/ansi.ts
|
|
2686
2731
|
var import_string_width = __toESM(require("string-width"));
|
|
@@ -3212,7 +3257,7 @@ function initialState(overrides = {}) {
|
|
|
3212
3257
|
}
|
|
3213
3258
|
|
|
3214
3259
|
// src/tui/layout.ts
|
|
3215
|
-
var
|
|
3260
|
+
var import_core10 = require("@ordewell/core");
|
|
3216
3261
|
var CHROME_ROWS = 4;
|
|
3217
3262
|
function chatInputWrap(state) {
|
|
3218
3263
|
const active = state.focus === "chat" && !state.overlay;
|
|
@@ -3348,9 +3393,9 @@ function chatScrollMax(state) {
|
|
|
3348
3393
|
}
|
|
3349
3394
|
function plannerSetup(state) {
|
|
3350
3395
|
const provider = state.plannerProvider;
|
|
3351
|
-
const registration =
|
|
3396
|
+
const registration = import_core10.ALL_PROVIDERS[provider];
|
|
3352
3397
|
if (!registration) return { label: "not set", ready: false };
|
|
3353
|
-
const runner = (0,
|
|
3398
|
+
const runner = (0, import_core10.runnerForProvider)(provider);
|
|
3354
3399
|
const ready = runner ? state.runners.some((r) => r.id === runner) : state.configuredProviders.includes(provider);
|
|
3355
3400
|
return { label: registration.label, ready };
|
|
3356
3401
|
}
|
|
@@ -3509,7 +3554,8 @@ function taskLines(state, task, index, cols) {
|
|
|
3509
3554
|
});
|
|
3510
3555
|
const model = task.assignedModel?.modelLabel ?? (task.type === "ai" ? "default model" : "");
|
|
3511
3556
|
const effort = task.type === "ai" ? `effort: ${task.assignedModel?.thinkingEffort ?? "default"}` : "";
|
|
3512
|
-
const
|
|
3557
|
+
const modeInfo = task.type === "ai" ? modesForTask(state.modesByRunner, task).find((m) => m.id === task.taskMode) : void 0;
|
|
3558
|
+
const mode = task.type === "ai" ? `mode: ${task.taskMode ?? "default"}${modeInfo?.autonomous ? style.yellow(" \u26A1") : ""}` : "";
|
|
3513
3559
|
const runner = task.assignedRunner ?? "";
|
|
3514
3560
|
const meta = [running ? "working" : "", runner, model].filter(Boolean).join(" \xB7 ");
|
|
3515
3561
|
if (meta) lines.push(style.grey(truncate(` ${meta}`, cols)));
|
|
@@ -3517,6 +3563,9 @@ function taskLines(state, task, index, cols) {
|
|
|
3517
3563
|
let editorLine;
|
|
3518
3564
|
if (expanded) {
|
|
3519
3565
|
lines.push(style.grey(` ${task.status.replace(/_/g, " ")}`));
|
|
3566
|
+
if (modeInfo?.autonomous) {
|
|
3567
|
+
lines.push(...taskText("Autonomy", "Runs without permission prompts. Toggle with /auto.", cols));
|
|
3568
|
+
}
|
|
3520
3569
|
const editableSeed = task.prompt ?? task.description ?? task.title;
|
|
3521
3570
|
if (task.description && task.description !== task.title && task.description !== editableSeed) {
|
|
3522
3571
|
lines.push(...taskText("Description", task.description, cols));
|
|
@@ -3844,9 +3893,9 @@ function frame(title, body, rows, cols) {
|
|
|
3844
3893
|
}
|
|
3845
3894
|
|
|
3846
3895
|
// src/tui/reducer.ts
|
|
3847
|
-
var
|
|
3896
|
+
var import_core11 = require("@ordewell/core");
|
|
3848
3897
|
var import_plan_utils3 = require("@ordewell/core/plan-utils");
|
|
3849
|
-
var KNOWN_PROVIDERS2 = Object.keys(
|
|
3898
|
+
var KNOWN_PROVIDERS2 = Object.keys(import_core11.ALL_PROVIDERS);
|
|
3850
3899
|
var DEFAULT_EFFORT = "__runner_default__";
|
|
3851
3900
|
function step(state, effects = []) {
|
|
3852
3901
|
return { state, effects };
|
|
@@ -4115,11 +4164,11 @@ function modelDetail(m) {
|
|
|
4115
4164
|
function providerErrorHint(state) {
|
|
4116
4165
|
const failed = Object.keys(state.providerErrors ?? {});
|
|
4117
4166
|
if (failed.length === 0) return void 0;
|
|
4118
|
-
const names = failed.map((p) =>
|
|
4167
|
+
const names = failed.map((p) => import_core11.ALL_PROVIDERS[p]?.label ?? p);
|
|
4119
4168
|
return `\u26A0 Unavailable (key or fetch failed): ${names.join(", ")} \u2014 showing working providers only.`;
|
|
4120
4169
|
}
|
|
4121
4170
|
function plannerModelItems(state) {
|
|
4122
|
-
const runner = (0,
|
|
4171
|
+
const runner = (0, import_core11.runnerForProvider)(state.plannerProvider);
|
|
4123
4172
|
if (!runner) return state.orchestratorModels.map((m) => ({ id: m.id, label: m.label, detail: modelDetail(m) }));
|
|
4124
4173
|
const items = state.models.filter((m) => m.runners?.includes(runner)).map((m) => ({
|
|
4125
4174
|
id: m.id,
|
|
@@ -4130,7 +4179,7 @@ function plannerModelItems(state) {
|
|
|
4130
4179
|
return items.length > 0 ? items : [{ id: "", label: `No ${runner} models discovered yet`, detail: "run /refresh", disabled: true }];
|
|
4131
4180
|
}
|
|
4132
4181
|
function plannerEffortItems(state) {
|
|
4133
|
-
const runner = (0,
|
|
4182
|
+
const runner = (0, import_core11.runnerForProvider)(state.plannerProvider);
|
|
4134
4183
|
if (!runner) {
|
|
4135
4184
|
return [{ id: "", label: "Thinking effort applies to a coding-agent planner", detail: "switch with /planner", disabled: true }];
|
|
4136
4185
|
}
|
|
@@ -4768,7 +4817,7 @@ function newSession(state) {
|
|
|
4768
4817
|
}
|
|
4769
4818
|
function setModel(state, args) {
|
|
4770
4819
|
if (args[0] === "set" && args[1]) {
|
|
4771
|
-
const runner = (0,
|
|
4820
|
+
const runner = (0, import_core11.runnerForProvider)(state.plannerProvider);
|
|
4772
4821
|
const known = runner ? modelsForRunner(state.models, runner) : [];
|
|
4773
4822
|
if (runner && known.length > 0 && !known.some((m) => m.id === args[1])) {
|
|
4774
4823
|
return fail2(state, `${args[1]} was not discovered for ${runner}.`);
|
|
@@ -4790,21 +4839,21 @@ function setModel(state, args) {
|
|
|
4790
4839
|
}
|
|
4791
4840
|
function plannerItems(state) {
|
|
4792
4841
|
const installed = new Set(state.runners.map((r) => r.id));
|
|
4793
|
-
const agents =
|
|
4794
|
-
const runner = (0,
|
|
4842
|
+
const agents = import_core11.CLI_PROVIDERS.map((id) => {
|
|
4843
|
+
const runner = (0, import_core11.runnerForProvider)(id);
|
|
4795
4844
|
const ready = installed.has(runner);
|
|
4796
4845
|
return {
|
|
4797
4846
|
id,
|
|
4798
|
-
label:
|
|
4847
|
+
label: import_core11.ALL_PROVIDERS[id].label,
|
|
4799
4848
|
detail: ready ? "coding agent \xB7 no API key needed" : "CLI not installed or not on PATH",
|
|
4800
4849
|
selected: state.plannerProvider === id,
|
|
4801
4850
|
disabled: !ready
|
|
4802
4851
|
};
|
|
4803
4852
|
});
|
|
4804
|
-
const vendors =
|
|
4853
|
+
const vendors = import_core11.PROVIDER_PRIORITY.filter((id) => state.configuredProviders.includes(id)).map((id) => ({
|
|
4805
4854
|
id,
|
|
4806
|
-
label:
|
|
4807
|
-
detail:
|
|
4855
|
+
label: import_core11.ALL_PROVIDERS[id].label,
|
|
4856
|
+
detail: import_core11.ALL_PROVIDERS[id].apiKeyEnvVar,
|
|
4808
4857
|
selected: state.plannerProvider === id
|
|
4809
4858
|
}));
|
|
4810
4859
|
return vendors.length > 0 ? [...agents, ...vendors] : [...agents, { id: "", label: "No API providers configured", detail: "add a key with /key", disabled: true }];
|
|
@@ -4862,16 +4911,16 @@ function setKey(state, args) {
|
|
|
4862
4911
|
}
|
|
4863
4912
|
return step(state, [{ type: "setApiKey", provider, key: args.slice(2).join(" ") }]);
|
|
4864
4913
|
}
|
|
4865
|
-
const items =
|
|
4914
|
+
const items = import_core11.PROVIDER_PRIORITY.map((id) => ({
|
|
4866
4915
|
id,
|
|
4867
|
-
label:
|
|
4868
|
-
detail:
|
|
4916
|
+
label: import_core11.ALL_PROVIDERS[id].label,
|
|
4917
|
+
detail: import_core11.ALL_PROVIDERS[id].apiKeyEnvVar,
|
|
4869
4918
|
selected: state.configuredProviders.includes(id)
|
|
4870
4919
|
}));
|
|
4871
4920
|
return step({ ...state, overlay: { kind: "picker", picker: picker("API provider key", items, { kind: "set-key" }) } });
|
|
4872
4921
|
}
|
|
4873
4922
|
function keyPrompt(provider) {
|
|
4874
|
-
const meta =
|
|
4923
|
+
const meta = import_core11.ALL_PROVIDERS[provider];
|
|
4875
4924
|
return {
|
|
4876
4925
|
kind: "prompt",
|
|
4877
4926
|
title: `${meta.label} API key`,
|
|
@@ -5229,7 +5278,7 @@ function createApp(deps) {
|
|
|
5229
5278
|
|
|
5230
5279
|
// src/tui/effects.ts
|
|
5231
5280
|
var import_child_process4 = require("child_process");
|
|
5232
|
-
var
|
|
5281
|
+
var import_core12 = require("@ordewell/core");
|
|
5233
5282
|
var import_plan_utils4 = require("@ordewell/core/plan-utils");
|
|
5234
5283
|
var ConversationQueue = class {
|
|
5235
5284
|
tail = Promise.resolve();
|
|
@@ -5396,7 +5445,7 @@ async function perform(effect, deps) {
|
|
|
5396
5445
|
dispatch({ type: "notice", message: `Orchestrator model set to ${effect.modelId}.` });
|
|
5397
5446
|
return;
|
|
5398
5447
|
case "setPlanner": {
|
|
5399
|
-
const meta =
|
|
5448
|
+
const meta = import_core12.ALL_PROVIDERS[effect.provider];
|
|
5400
5449
|
if (!meta) throw new Error(`Unknown planner: ${effect.provider}`);
|
|
5401
5450
|
const env = { AI_PROVIDER: effect.provider };
|
|
5402
5451
|
const settings = await api.updateSettings({ env });
|
|
@@ -5408,7 +5457,7 @@ async function perform(effect, deps) {
|
|
|
5408
5457
|
});
|
|
5409
5458
|
dispatch({
|
|
5410
5459
|
type: "notice",
|
|
5411
|
-
message: `${(0,
|
|
5460
|
+
message: `${(0, import_core12.isCliProvider)(effect.provider) ? `Planning with ${meta.label} \u2014 no API key needed.` : `Planner set to ${meta.label}.`} ${plannerModelNotice(recall2)}`
|
|
5412
5461
|
});
|
|
5413
5462
|
await loadModels(deps);
|
|
5414
5463
|
return;
|
|
@@ -5420,7 +5469,7 @@ async function perform(effect, deps) {
|
|
|
5420
5469
|
dispatch({ type: "notice", message: `Planner effort set to ${effect.effort || "the runner default"}.` });
|
|
5421
5470
|
return;
|
|
5422
5471
|
case "setApiKey": {
|
|
5423
|
-
const meta =
|
|
5472
|
+
const meta = import_core12.ALL_PROVIDERS[effect.provider];
|
|
5424
5473
|
if (!meta) throw new Error(`Unknown provider: ${effect.provider}`);
|
|
5425
5474
|
await api.updateSettings({ env: { [meta.apiKeyEnvVar]: effect.key } });
|
|
5426
5475
|
deps.setEnvVar(meta.apiKeyEnvVar, effect.key);
|
|
@@ -5508,7 +5557,7 @@ function osc52(text) {
|
|
|
5508
5557
|
function copySelection(deps, text) {
|
|
5509
5558
|
if (!text) return;
|
|
5510
5559
|
const lines = text.split("\n").length;
|
|
5511
|
-
const command = (0,
|
|
5560
|
+
const command = (0, import_core12.clipboardCopyCommand)(deps.hasBin);
|
|
5512
5561
|
if (command) {
|
|
5513
5562
|
try {
|
|
5514
5563
|
(deps.pipeToClipboard ?? pipeToClipboardDefault)(command, text);
|
|
@@ -5982,7 +6031,7 @@ async function handleTui(subArgs) {
|
|
|
5982
6031
|
}
|
|
5983
6032
|
const workspace = flag(subArgs, "--workspace") || process.cwd();
|
|
5984
6033
|
try {
|
|
5985
|
-
(0,
|
|
6034
|
+
(0, import_core13.assertWorkspaceExists)(workspace);
|
|
5986
6035
|
} catch {
|
|
5987
6036
|
console.error(
|
|
5988
6037
|
`Workspace "${workspace}" does not exist.
|
|
@@ -6007,7 +6056,7 @@ cd into a directory that exists, or pass --workspace <path> naming one that does
|
|
|
6007
6056
|
conversationQueue,
|
|
6008
6057
|
port,
|
|
6009
6058
|
dispatch: (action) => app.dispatch(action),
|
|
6010
|
-
newSessionId: () =>
|
|
6059
|
+
newSessionId: () => (0, import_core13.mintSessionId)(),
|
|
6011
6060
|
setEnvVar: (key, value) => {
|
|
6012
6061
|
writeEnvVar(findEnvFile(), key, value);
|
|
6013
6062
|
process.env[key] = value;
|
package/package.json
CHANGED