@ordewell/core 0.4.19 → 0.4.21
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/{ITerminalRunner-C-HlFxuS.d.mts → ITerminalRunner-CuNYBnqK.d.mts} +10 -0
- package/dist/{ITerminalRunner-BVU7TfT3.d.ts → ITerminalRunner-Da1gIAFX.d.ts} +10 -0
- package/dist/index.d.mts +9 -2
- package/dist/index.d.ts +9 -2
- package/dist/index.js +324 -128
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +317 -121
- package/dist/index.mjs.map +1 -1
- package/dist/testing.d.mts +1 -1
- package/dist/testing.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6671,9 +6671,9 @@ function summarizeToolCall(tool, argsJson, toolLabel) {
|
|
|
6671
6671
|
const scope = args.include ? ` in ${args.include}` : "";
|
|
6672
6672
|
return `grep ${ellipsize(String(args.pattern), 40)}${scope}${mode}`;
|
|
6673
6673
|
}
|
|
6674
|
-
const
|
|
6675
|
-
if (
|
|
6676
|
-
const basename = String(
|
|
6674
|
+
const path21 = args.filePath || args.file_path || args.path;
|
|
6675
|
+
if (path21) {
|
|
6676
|
+
const basename = String(path21).split("/").pop() || String(path21);
|
|
6677
6677
|
return `${display} ${basename}`;
|
|
6678
6678
|
}
|
|
6679
6679
|
if (args.pattern) {
|
|
@@ -8058,6 +8058,19 @@ function renderTerminalOutput(raw) {
|
|
|
8058
8058
|
}
|
|
8059
8059
|
var MARKER_SCAN_TAIL = 16384;
|
|
8060
8060
|
var IDLE_TIMEOUT_MS = 6e4;
|
|
8061
|
+
function renderCleanCapture(raw, doneToken) {
|
|
8062
|
+
const rendered = renderTerminalOutput(raw).replace(/[\s─-▟]+$/gm, "");
|
|
8063
|
+
if (!doneToken) return rendered.trim();
|
|
8064
|
+
const lines = rendered.split("\n");
|
|
8065
|
+
const flat = (s) => flattenTerminalOutput(s);
|
|
8066
|
+
for (let i = 0; i < lines.length; i++) {
|
|
8067
|
+
const own = flat(lines[i]).includes(doneToken);
|
|
8068
|
+
if (own) return lines.slice(0, i).join("\n").trim();
|
|
8069
|
+
const window = flat(lines[i]) + (i + 1 < lines.length ? flat(lines[i + 1]) : "");
|
|
8070
|
+
if (window.includes(doneToken)) return lines.slice(0, i + 1).join("\n").trim();
|
|
8071
|
+
}
|
|
8072
|
+
return rendered.trim();
|
|
8073
|
+
}
|
|
8061
8074
|
var VerdictEngine = class {
|
|
8062
8075
|
markerSeen = /* @__PURE__ */ new Set();
|
|
8063
8076
|
buffers = /* @__PURE__ */ new Map();
|
|
@@ -8285,6 +8298,167 @@ ${line}
|
|
|
8285
8298
|
}
|
|
8286
8299
|
};
|
|
8287
8300
|
|
|
8301
|
+
// src/services/transcriptCapture.ts
|
|
8302
|
+
var import_fs = require("fs");
|
|
8303
|
+
var os2 = __toESM(require("os"));
|
|
8304
|
+
var path4 = __toESM(require("path"));
|
|
8305
|
+
function homeDir() {
|
|
8306
|
+
return process.env.HOME || os2.homedir();
|
|
8307
|
+
}
|
|
8308
|
+
async function readFinalAssistantText(query, maxChars = 4e3) {
|
|
8309
|
+
try {
|
|
8310
|
+
if (query.runner === "claude-code") return claudeFinal(query, maxChars);
|
|
8311
|
+
if (query.runner === "opencode") return await opencodeFinal(query, maxChars);
|
|
8312
|
+
if (query.runner === "codex") return codexFinal(query, maxChars);
|
|
8313
|
+
} catch {
|
|
8314
|
+
}
|
|
8315
|
+
return null;
|
|
8316
|
+
}
|
|
8317
|
+
function claudeFinal(query, maxChars) {
|
|
8318
|
+
const munged = query.cwd.replaceAll("/", "-").replaceAll("_", "-");
|
|
8319
|
+
const dir = path4.join(homeDir(), ".claude", "projects", munged);
|
|
8320
|
+
if (!(0, import_fs.existsSync)(dir)) return null;
|
|
8321
|
+
const cutoff = query.startedAt ? Date.parse(query.startedAt) : 0;
|
|
8322
|
+
const candidates = (0, import_fs.readdirSync)(dir).filter((f) => f.endsWith(".jsonl")).map((f) => path4.join(dir, f)).filter((f) => cutoff ? (0, import_fs.statSync)(f).mtimeMs >= cutoff - 5e3 : true).sort((a, b) => (0, import_fs.statSync)(b).mtimeMs - (0, import_fs.statSync)(a).mtimeMs);
|
|
8323
|
+
for (const file of candidates) {
|
|
8324
|
+
const text = claudeLastAssistant(file);
|
|
8325
|
+
if (text) return clamp(text, maxChars);
|
|
8326
|
+
}
|
|
8327
|
+
return null;
|
|
8328
|
+
}
|
|
8329
|
+
function claudeLastAssistant(file) {
|
|
8330
|
+
let last = null;
|
|
8331
|
+
let buf = "";
|
|
8332
|
+
const fd = (0, import_fs.statSync)(file);
|
|
8333
|
+
const start = Math.max(0, fd.size - 512 * 1024);
|
|
8334
|
+
buf = (0, import_fs.readFileSync)(file, { encoding: "utf8" }).toString();
|
|
8335
|
+
if (start > 0) buf = buf.slice(buf.indexOf("\n", Math.min(start, buf.length - 1)) + 1);
|
|
8336
|
+
for (const line of buf.split("\n")) {
|
|
8337
|
+
if (!line.trim()) continue;
|
|
8338
|
+
let rec;
|
|
8339
|
+
try {
|
|
8340
|
+
rec = JSON.parse(line);
|
|
8341
|
+
} catch {
|
|
8342
|
+
continue;
|
|
8343
|
+
}
|
|
8344
|
+
if (rec.type !== "assistant" || rec.isSidechain) continue;
|
|
8345
|
+
const content = rec.message?.content;
|
|
8346
|
+
if (!Array.isArray(content)) continue;
|
|
8347
|
+
const texts = content.filter((b) => typeof b === "object" && b !== null && b.type === "text").map((b) => b.text).join("\n").trim();
|
|
8348
|
+
if (texts) last = texts;
|
|
8349
|
+
}
|
|
8350
|
+
return last;
|
|
8351
|
+
}
|
|
8352
|
+
async function opencodeFinal(query, maxChars) {
|
|
8353
|
+
let DatabaseSync;
|
|
8354
|
+
try {
|
|
8355
|
+
({ DatabaseSync } = await import("sqlite"));
|
|
8356
|
+
} catch {
|
|
8357
|
+
return null;
|
|
8358
|
+
}
|
|
8359
|
+
const dbPath = path4.join(homeDir(), ".local", "share", "opencode", "opencode.db");
|
|
8360
|
+
if (!(0, import_fs.existsSync)(dbPath)) return null;
|
|
8361
|
+
let db;
|
|
8362
|
+
try {
|
|
8363
|
+
db = new DatabaseSync(dbPath, { open: true });
|
|
8364
|
+
} catch {
|
|
8365
|
+
return null;
|
|
8366
|
+
}
|
|
8367
|
+
try {
|
|
8368
|
+
const cutoff = query.startedAt ? Date.parse(query.startedAt) : 0;
|
|
8369
|
+
const rows = db.prepare(
|
|
8370
|
+
`select s.id, s.time_updated from session s
|
|
8371
|
+
join project p on p.id = s.project_id
|
|
8372
|
+
where s.directory = ?
|
|
8373
|
+
order by s.time_updated desc limit 5`
|
|
8374
|
+
).all(query.cwd);
|
|
8375
|
+
for (const row of rows) {
|
|
8376
|
+
if (cutoff && row.time_updated < cutoff - 5e3) continue;
|
|
8377
|
+
const parts = db.prepare(
|
|
8378
|
+
`select pt.data from part pt
|
|
8379
|
+
join message m on m.id = pt.message_id
|
|
8380
|
+
where m.session_id = ? and m.data like '%"role":"assistant"%'
|
|
8381
|
+
order by pt.id asc`
|
|
8382
|
+
).all(row.id);
|
|
8383
|
+
let text = null;
|
|
8384
|
+
for (const p of parts) {
|
|
8385
|
+
try {
|
|
8386
|
+
const d = JSON.parse(p.data);
|
|
8387
|
+
if (d.type === "text" && d.text && d.text.trim()) text = d.text.trim();
|
|
8388
|
+
} catch {
|
|
8389
|
+
continue;
|
|
8390
|
+
}
|
|
8391
|
+
}
|
|
8392
|
+
if (text) return clamp(text, maxChars);
|
|
8393
|
+
}
|
|
8394
|
+
return null;
|
|
8395
|
+
} catch {
|
|
8396
|
+
return null;
|
|
8397
|
+
} finally {
|
|
8398
|
+
try {
|
|
8399
|
+
db.close();
|
|
8400
|
+
} catch {
|
|
8401
|
+
}
|
|
8402
|
+
}
|
|
8403
|
+
}
|
|
8404
|
+
function codexFinal(query, maxChars) {
|
|
8405
|
+
const root = path4.join(homeDir(), ".codex", "sessions");
|
|
8406
|
+
if (!(0, import_fs.existsSync)(root)) return null;
|
|
8407
|
+
const cutoff = query.startedAt ? Date.parse(query.startedAt) : 0;
|
|
8408
|
+
const files = [];
|
|
8409
|
+
const stack = [root];
|
|
8410
|
+
while (stack.length) {
|
|
8411
|
+
const dir = stack.pop();
|
|
8412
|
+
let entries;
|
|
8413
|
+
try {
|
|
8414
|
+
entries = (0, import_fs.readdirSync)(dir);
|
|
8415
|
+
} catch {
|
|
8416
|
+
continue;
|
|
8417
|
+
}
|
|
8418
|
+
for (const e of entries) {
|
|
8419
|
+
const full = path4.join(dir, e);
|
|
8420
|
+
let st;
|
|
8421
|
+
try {
|
|
8422
|
+
st = (0, import_fs.statSync)(full);
|
|
8423
|
+
} catch {
|
|
8424
|
+
continue;
|
|
8425
|
+
}
|
|
8426
|
+
if (st.isDirectory()) stack.push(full);
|
|
8427
|
+
else if (e.startsWith("rollout-") && e.endsWith(".jsonl") && (!cutoff || st.mtimeMs >= cutoff - 5e3)) files.push(full);
|
|
8428
|
+
}
|
|
8429
|
+
}
|
|
8430
|
+
files.sort((a, b) => (0, import_fs.statSync)(b).mtimeMs - (0, import_fs.statSync)(a).mtimeMs);
|
|
8431
|
+
for (const file of files.slice(0, 10)) {
|
|
8432
|
+
const text = codexLastAssistant(file, query.cwd);
|
|
8433
|
+
if (text) return clamp(text, maxChars);
|
|
8434
|
+
}
|
|
8435
|
+
return null;
|
|
8436
|
+
}
|
|
8437
|
+
function codexLastAssistant(file, cwd) {
|
|
8438
|
+
const raw = (0, import_fs.readFileSync)(file, "utf8");
|
|
8439
|
+
const lines = raw.split("\n").filter((l) => l.trim());
|
|
8440
|
+
let sawCwd = false;
|
|
8441
|
+
let last = null;
|
|
8442
|
+
for (const line of lines) {
|
|
8443
|
+
let rec;
|
|
8444
|
+
try {
|
|
8445
|
+
rec = JSON.parse(line);
|
|
8446
|
+
} catch {
|
|
8447
|
+
continue;
|
|
8448
|
+
}
|
|
8449
|
+
if (rec.type === "session_meta" && rec.payload?.cwd === cwd) sawCwd = true;
|
|
8450
|
+
if (rec.type !== "response_item") continue;
|
|
8451
|
+
const p = rec.payload;
|
|
8452
|
+
if (p?.role !== "assistant" || p.type !== "message") continue;
|
|
8453
|
+
const texts = (Array.isArray(p.content) ? p.content : []).map((c) => typeof c === "object" && c !== null && c.text || "").join("\n").trim();
|
|
8454
|
+
if (texts) last = texts;
|
|
8455
|
+
}
|
|
8456
|
+
return sawCwd ? last : null;
|
|
8457
|
+
}
|
|
8458
|
+
function clamp(text, maxChars) {
|
|
8459
|
+
return text.length <= maxChars ? text : text.slice(-maxChars);
|
|
8460
|
+
}
|
|
8461
|
+
|
|
8288
8462
|
// src/services/PlanStore.ts
|
|
8289
8463
|
var PlanStore = class {
|
|
8290
8464
|
_planTasks = [];
|
|
@@ -8666,6 +8840,11 @@ var TaskOrchestrator = class {
|
|
|
8666
8840
|
workspaceRootFn = () => process.cwd();
|
|
8667
8841
|
observers = [];
|
|
8668
8842
|
tddEnabled = () => false;
|
|
8843
|
+
/**
|
|
8844
|
+
* Spawn context per active task, for locating the agent's own session
|
|
8845
|
+
* transcript at verdict time (issue #16). Cleared with the session entry.
|
|
8846
|
+
*/
|
|
8847
|
+
taskSpawnContext = /* @__PURE__ */ new Map();
|
|
8669
8848
|
/** Advisory silence timestamp for a task's live runner, or null if not idle. */
|
|
8670
8849
|
getIdleSince(taskId) {
|
|
8671
8850
|
return this.verifier.getIdleSince(taskId);
|
|
@@ -8828,6 +9007,8 @@ var TaskOrchestrator = class {
|
|
|
8828
9007
|
const task = this.store.get(taskId);
|
|
8829
9008
|
if (!task) return;
|
|
8830
9009
|
this.activeTaskSessions.delete(taskId);
|
|
9010
|
+
const spawnContext = this.taskSpawnContext.get(taskId);
|
|
9011
|
+
this.taskSpawnContext.delete(taskId);
|
|
8831
9012
|
console.error(`[TaskOrchestrator] Task #${task.order} "${task.title}" verdict=${verdict.outcome}`);
|
|
8832
9013
|
console.error(`[TaskOrchestrator] Runner: ${task.assignedRunner}, Model: ${task.assignedModel?.modelId ?? "default"}`);
|
|
8833
9014
|
console.error(`[TaskOrchestrator] Prompt preview: ${(task.prompt ?? "").slice(0, 200)}`);
|
|
@@ -8838,6 +9019,10 @@ ${output.slice(-3e3)}`);
|
|
|
8838
9019
|
console.error(`[TaskOrchestrator] Output: (empty \u2014 no stdout/stderr captured)`);
|
|
8839
9020
|
}
|
|
8840
9021
|
this.store.setTaskVerdict(taskId, verdict);
|
|
9022
|
+
const doneToken = `<<<ORDEWELL_DONE_${task.completionMarker}>>>`;
|
|
9023
|
+
const transcript = spawnContext ? await readFinalAssistantText(spawnContext) : null;
|
|
9024
|
+
const cleaned = transcript ?? renderCleanCapture(output, doneToken);
|
|
9025
|
+
const effective = cleaned.length > 0 ? cleaned : output;
|
|
8841
9026
|
if (verdict.outcome === "pass") {
|
|
8842
9027
|
this.store.markCompleted(taskId);
|
|
8843
9028
|
this.notifications.info(`Task "${task.title}" completed.`);
|
|
@@ -8847,7 +9032,7 @@ ${output.slice(-3e3)}`);
|
|
|
8847
9032
|
this.planStatus = "approved";
|
|
8848
9033
|
this.notifications.error(`Task "${task.title}" failed verification: ${verdict.reason}`);
|
|
8849
9034
|
}
|
|
8850
|
-
this.store.setTaskOutputSummary(taskId, summarizeOutput(verdict.reason,
|
|
9035
|
+
this.store.setTaskOutputSummary(taskId, summarizeOutput(verdict.reason, effective));
|
|
8851
9036
|
this.logAndArchive(task, verdict);
|
|
8852
9037
|
this.emit("onTaskChanged");
|
|
8853
9038
|
if (!this.running) {
|
|
@@ -9087,6 +9272,8 @@ ${output.slice(-3e3)}`);
|
|
|
9087
9272
|
try {
|
|
9088
9273
|
const cwd = this.workspaceRootFn();
|
|
9089
9274
|
const runner = this.store.resolveTaskRunner(task);
|
|
9275
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9276
|
+
this.taskSpawnContext.set(task.id, { runner, cwd, startedAt });
|
|
9090
9277
|
const finalPrompt = composeAugmentedPrompt(task, this.store.planTasks, {
|
|
9091
9278
|
planMapEnabled: this.config.planMapEnabled,
|
|
9092
9279
|
tddEnabled: this.tddEnabled()
|
|
@@ -9251,7 +9438,7 @@ ${errors.map((e) => `- ${e}`).join("\n")}`
|
|
|
9251
9438
|
};
|
|
9252
9439
|
|
|
9253
9440
|
// src/services/ModelDiscovery.ts
|
|
9254
|
-
var
|
|
9441
|
+
var path8 = __toESM(require("path"));
|
|
9255
9442
|
var import_child_process3 = require("child_process");
|
|
9256
9443
|
var import_util2 = require("util");
|
|
9257
9444
|
var fsSync3 = __toESM(require("fs"));
|
|
@@ -9260,8 +9447,8 @@ var osMod = __toESM(require("os"));
|
|
|
9260
9447
|
// src/utils/shellPath.ts
|
|
9261
9448
|
var import_child_process = require("child_process");
|
|
9262
9449
|
var import_util = require("util");
|
|
9263
|
-
var
|
|
9264
|
-
var
|
|
9450
|
+
var os3 = __toESM(require("os"));
|
|
9451
|
+
var path5 = __toESM(require("path"));
|
|
9265
9452
|
var execAsync = (0, import_util.promisify)(import_child_process.exec);
|
|
9266
9453
|
var LOGIN_SHELL_TIMEOUT_MS = 5e3;
|
|
9267
9454
|
var PATH_MARKER = "__ORDEWELL_PATH__";
|
|
@@ -9270,42 +9457,42 @@ var defaultExec = async (command, options) => {
|
|
|
9270
9457
|
return { stdout: String(stdout) };
|
|
9271
9458
|
};
|
|
9272
9459
|
function posixBinDirs() {
|
|
9273
|
-
const home =
|
|
9460
|
+
const home = os3.homedir();
|
|
9274
9461
|
return [
|
|
9275
|
-
|
|
9276
|
-
|
|
9277
|
-
|
|
9278
|
-
|
|
9279
|
-
|
|
9280
|
-
|
|
9281
|
-
|
|
9462
|
+
path5.join(home, ".local", "bin"),
|
|
9463
|
+
path5.join(home, ".opencode", "bin"),
|
|
9464
|
+
path5.join(home, ".claude", "bin"),
|
|
9465
|
+
path5.join(home, ".bun", "bin"),
|
|
9466
|
+
path5.join(home, ".volta", "bin"),
|
|
9467
|
+
path5.join(home, ".npm-global", "bin"),
|
|
9468
|
+
path5.join(home, "bin"),
|
|
9282
9469
|
"/usr/local/bin",
|
|
9283
9470
|
"/opt/homebrew/bin"
|
|
9284
9471
|
];
|
|
9285
9472
|
}
|
|
9286
9473
|
function windowsBinDirs(env, home) {
|
|
9287
|
-
const
|
|
9288
|
-
const under = (base, ...parts) => base ? [
|
|
9474
|
+
const join20 = (...parts) => path5.win32.join(...parts);
|
|
9475
|
+
const under = (base, ...parts) => base ? [join20(base, ...parts)] : [];
|
|
9289
9476
|
const appData = env.APPDATA;
|
|
9290
9477
|
const localAppData = env.LOCALAPPDATA;
|
|
9291
9478
|
const programData = env.ProgramData;
|
|
9292
9479
|
return [
|
|
9293
9480
|
// Native per-user installers, PowerShell-driven and otherwise.
|
|
9294
|
-
|
|
9295
|
-
|
|
9296
|
-
|
|
9297
|
-
|
|
9481
|
+
join20(home, ".local", "bin"),
|
|
9482
|
+
join20(home, ".opencode", "bin"),
|
|
9483
|
+
join20(home, ".claude", "bin"),
|
|
9484
|
+
join20(home, ".codex", "bin"),
|
|
9298
9485
|
...under(localAppData, "Programs", "claude"),
|
|
9299
9486
|
// Node package managers. npm's global prefix is `%APPDATA%\npm`; the
|
|
9300
9487
|
// literal spelling is kept as a fallback for a host that does not export
|
|
9301
9488
|
// APPDATA (a service account, a stripped CI container).
|
|
9302
9489
|
...under(appData, "npm"),
|
|
9303
|
-
|
|
9490
|
+
join20(home, "AppData", "Roaming", "npm"),
|
|
9304
9491
|
...under(localAppData, "pnpm"),
|
|
9305
9492
|
...under(localAppData, "Yarn", "bin"),
|
|
9306
|
-
|
|
9493
|
+
join20(home, ".bun", "bin"),
|
|
9307
9494
|
// Windows package managers.
|
|
9308
|
-
|
|
9495
|
+
join20(home, "scoop", "shims"),
|
|
9309
9496
|
...under(env.SCOOP, "shims"),
|
|
9310
9497
|
...under(env.SCOOP_GLOBAL ?? programData, "scoop", "shims"),
|
|
9311
9498
|
...under(programData, "chocolatey", "bin"),
|
|
@@ -9315,13 +9502,13 @@ function windowsBinDirs(env, home) {
|
|
|
9315
9502
|
...under(localAppData, "Microsoft", "WindowsApps"),
|
|
9316
9503
|
// Version managers. Volta's Windows home is not the POSIX `~/.volta`.
|
|
9317
9504
|
...under(localAppData, "Volta", "bin"),
|
|
9318
|
-
|
|
9505
|
+
join20(home, ".volta", "bin")
|
|
9319
9506
|
];
|
|
9320
9507
|
}
|
|
9321
9508
|
function wellKnownBinDirs(deps = {}) {
|
|
9322
9509
|
const platform = deps.platform ?? process.platform;
|
|
9323
9510
|
if (platform !== "win32") return posixBinDirs();
|
|
9324
|
-
return [...new Set(windowsBinDirs(deps.env ?? process.env, deps.home ??
|
|
9511
|
+
return [...new Set(windowsBinDirs(deps.env ?? process.env, deps.home ?? os3.homedir()))];
|
|
9325
9512
|
}
|
|
9326
9513
|
async function loginShellPath(execImpl) {
|
|
9327
9514
|
if (process.platform === "win32") return null;
|
|
@@ -9344,14 +9531,14 @@ function augmentedPath(execImpl = defaultExec) {
|
|
|
9344
9531
|
const segments = [];
|
|
9345
9532
|
const push = (p) => {
|
|
9346
9533
|
if (!p) return;
|
|
9347
|
-
for (const seg of p.split(
|
|
9534
|
+
for (const seg of p.split(path5.delimiter)) {
|
|
9348
9535
|
if (seg && !segments.includes(seg)) segments.push(seg);
|
|
9349
9536
|
}
|
|
9350
9537
|
};
|
|
9351
9538
|
push(process.env.PATH);
|
|
9352
9539
|
push(await loginShellPath(execImpl));
|
|
9353
9540
|
for (const dir of wellKnownBinDirs()) push(dir);
|
|
9354
|
-
return segments.join(
|
|
9541
|
+
return segments.join(path5.delimiter);
|
|
9355
9542
|
})();
|
|
9356
9543
|
}
|
|
9357
9544
|
return cachedPath;
|
|
@@ -9373,17 +9560,17 @@ function withPath(base, resolvedPath, overrides = {}) {
|
|
|
9373
9560
|
|
|
9374
9561
|
// src/utils/globalDataDir.ts
|
|
9375
9562
|
var fs = __toESM(require("fs"));
|
|
9376
|
-
var
|
|
9377
|
-
var
|
|
9563
|
+
var path6 = __toESM(require("path"));
|
|
9564
|
+
var os4 = __toESM(require("os"));
|
|
9378
9565
|
function globalDataDir() {
|
|
9379
|
-
return
|
|
9566
|
+
return path6.join(os4.homedir(), ".ordewell");
|
|
9380
9567
|
}
|
|
9381
9568
|
function copyDirSync(src, dest) {
|
|
9382
9569
|
fs.mkdirSync(dest, { recursive: true });
|
|
9383
9570
|
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
9384
9571
|
for (const entry of entries) {
|
|
9385
|
-
const srcPath =
|
|
9386
|
-
const destPath =
|
|
9572
|
+
const srcPath = path6.join(src, entry.name);
|
|
9573
|
+
const destPath = path6.join(dest, entry.name);
|
|
9387
9574
|
if (entry.isDirectory()) {
|
|
9388
9575
|
copyDirSync(srcPath, destPath);
|
|
9389
9576
|
} else {
|
|
@@ -9395,12 +9582,12 @@ var migrated = false;
|
|
|
9395
9582
|
function migrateOldConfigDir() {
|
|
9396
9583
|
if (migrated) return;
|
|
9397
9584
|
migrated = true;
|
|
9398
|
-
const oldDir =
|
|
9585
|
+
const oldDir = path6.join(os4.homedir(), ".config", "ordewell");
|
|
9399
9586
|
if (!fs.existsSync(oldDir)) return;
|
|
9400
9587
|
const newDir = globalDataDir();
|
|
9401
9588
|
const liftFile = (name) => {
|
|
9402
|
-
const oldFile =
|
|
9403
|
-
const newFile =
|
|
9589
|
+
const oldFile = path6.join(oldDir, name);
|
|
9590
|
+
const newFile = path6.join(newDir, name);
|
|
9404
9591
|
if (fs.existsSync(oldFile) && !fs.existsSync(newFile)) {
|
|
9405
9592
|
fs.mkdirSync(newDir, { recursive: true });
|
|
9406
9593
|
fs.copyFileSync(oldFile, newFile);
|
|
@@ -9408,8 +9595,8 @@ function migrateOldConfigDir() {
|
|
|
9408
9595
|
};
|
|
9409
9596
|
liftFile("settings.json");
|
|
9410
9597
|
liftFile(".env");
|
|
9411
|
-
const oldPlugins =
|
|
9412
|
-
const newPlugins =
|
|
9598
|
+
const oldPlugins = path6.join(oldDir, "plugins");
|
|
9599
|
+
const newPlugins = path6.join(newDir, "plugins");
|
|
9413
9600
|
if (fs.existsSync(oldPlugins) && !fs.existsSync(newPlugins)) {
|
|
9414
9601
|
copyDirSync(oldPlugins, newPlugins);
|
|
9415
9602
|
}
|
|
@@ -9417,7 +9604,7 @@ function migrateOldConfigDir() {
|
|
|
9417
9604
|
|
|
9418
9605
|
// src/utils/launch.ts
|
|
9419
9606
|
var fsSync2 = __toESM(require("fs"));
|
|
9420
|
-
var
|
|
9607
|
+
var path7 = __toESM(require("path"));
|
|
9421
9608
|
|
|
9422
9609
|
// src/utils/shell.ts
|
|
9423
9610
|
var ANSI_RE = /\x1b\[[0-9;]*[A-Za-z]|\x1b\][^\x07]*\x07|\x1b[()][AB012]|\r/g;
|
|
@@ -9446,7 +9633,7 @@ var CMD_EXE_MAX_COMMAND_LINE = 8191;
|
|
|
9446
9633
|
var WINDOWS_MAX_COMMAND_LINE = 32767;
|
|
9447
9634
|
function defaultPowerShell() {
|
|
9448
9635
|
const root = process.env.SystemRoot || process.env.windir;
|
|
9449
|
-
return root ?
|
|
9636
|
+
return root ? path7.win32.join(root, "System32", "WindowsPowerShell", "v1.0", "powershell.exe") : "powershell.exe";
|
|
9450
9637
|
}
|
|
9451
9638
|
var POWERSHELL_FLAGS = ["-NoLogo", "-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File"];
|
|
9452
9639
|
var CommandLineTooLongError = class extends Error {
|
|
@@ -9498,7 +9685,7 @@ Searched: ${searchedPath || "(empty PATH)"}`);
|
|
|
9498
9685
|
};
|
|
9499
9686
|
function isResolvableOnPosixPath(command, PATH, exists) {
|
|
9500
9687
|
if (command.includes("/")) return exists(command);
|
|
9501
|
-
return PATH.split(
|
|
9688
|
+
return PATH.split(path7.delimiter).map((d) => d.trim()).filter(Boolean).some((dir) => exists(path7.join(dir, command)));
|
|
9502
9689
|
}
|
|
9503
9690
|
function isExecutableResolved(command, plan, PATH, deps = {}) {
|
|
9504
9691
|
if ((deps.platform ?? process.platform) === "win32") return plan.file !== command;
|
|
@@ -9538,9 +9725,9 @@ function cmdArgs(line) {
|
|
|
9538
9725
|
return ["/d", "/s", "/c", `"${line}"`];
|
|
9539
9726
|
}
|
|
9540
9727
|
function candidateExtensions(command, pathExt) {
|
|
9541
|
-
const declared = pathExt.split(
|
|
9728
|
+
const declared = pathExt.split(path7.win32.delimiter).map((e) => e.trim().toLowerCase()).filter(Boolean);
|
|
9542
9729
|
const known = /* @__PURE__ */ new Set([...DIRECT_EXTENSIONS, ...BATCH_EXTENSIONS, ...POWERSHELL_EXTENSIONS, ...declared]);
|
|
9543
|
-
const ext =
|
|
9730
|
+
const ext = path7.win32.extname(command).toLowerCase();
|
|
9544
9731
|
if (ext && known.has(ext)) {
|
|
9545
9732
|
const route = BATCH_EXTENSIONS.includes(ext) ? "cmd" : POWERSHELL_EXTENSIONS.includes(ext) ? "powershell" : "direct";
|
|
9546
9733
|
return { direct: [], cmd: [], powershell: [], [route]: [""] };
|
|
@@ -9561,13 +9748,13 @@ async function findWindowsExecutables(command, deps) {
|
|
|
9561
9748
|
const exists = deps.exists ?? defaultExists2;
|
|
9562
9749
|
const pathExt = (deps.pathExt ?? (() => process.env.PATHEXT ?? ""))();
|
|
9563
9750
|
const byRoute = candidateExtensions(command, pathExt);
|
|
9564
|
-
const dirs =
|
|
9565
|
-
const base =
|
|
9751
|
+
const dirs = path7.win32.basename(command) !== command ? [path7.win32.dirname(path7.win32.resolve(command))] : (await (deps.resolvePath ?? augmentedPath)() || "").split(path7.win32.delimiter).map((d) => d.trim().replace(/^"|"$/g, "")).filter(Boolean);
|
|
9752
|
+
const base = path7.win32.basename(command);
|
|
9566
9753
|
const found = [];
|
|
9567
9754
|
for (const route of ROUTES) {
|
|
9568
9755
|
outer: for (const ext of byRoute[route]) {
|
|
9569
9756
|
for (const dir of dirs) {
|
|
9570
|
-
const candidate =
|
|
9757
|
+
const candidate = path7.win32.join(dir, `${base}${ext}`);
|
|
9571
9758
|
if (exists(candidate)) {
|
|
9572
9759
|
found.push({ file: candidate, route });
|
|
9573
9760
|
break outer;
|
|
@@ -9747,7 +9934,7 @@ function geminiDiscoveryCacheKey(apiKey) {
|
|
|
9747
9934
|
return {
|
|
9748
9935
|
key: `gemini-models:${hash}`,
|
|
9749
9936
|
dir,
|
|
9750
|
-
file:
|
|
9937
|
+
file: path8.join(dir, `gemini_models_${hash}.json`)
|
|
9751
9938
|
};
|
|
9752
9939
|
}
|
|
9753
9940
|
function readGeminiCache(apiKey) {
|
|
@@ -10271,7 +10458,7 @@ var ModelDiscovery = class {
|
|
|
10271
10458
|
|
|
10272
10459
|
// src/services/ModelCatalog.ts
|
|
10273
10460
|
var fs2 = __toESM(require("fs"));
|
|
10274
|
-
var
|
|
10461
|
+
var path9 = __toESM(require("path"));
|
|
10275
10462
|
var CACHE_KEY = "model-catalog";
|
|
10276
10463
|
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
10277
10464
|
function storageKey(baseUrl) {
|
|
@@ -10323,7 +10510,7 @@ var ModelCatalog = class {
|
|
|
10323
10510
|
const url = (baseUrl || "https://openrouter.ai/api/v1").replace(/\/+$/, "");
|
|
10324
10511
|
const key = storageKey(url);
|
|
10325
10512
|
const cacheDir = globalCacheDir();
|
|
10326
|
-
const cacheFile =
|
|
10513
|
+
const cacheFile = path9.join(cacheDir, `${key.replace(/[:/]/g, "_")}.json`);
|
|
10327
10514
|
if (fs2.existsSync(cacheFile)) fs2.rmSync(cacheFile);
|
|
10328
10515
|
} catch {
|
|
10329
10516
|
}
|
|
@@ -10331,7 +10518,7 @@ var ModelCatalog = class {
|
|
|
10331
10518
|
static readCache(key) {
|
|
10332
10519
|
try {
|
|
10333
10520
|
const cacheDir = globalCacheDir();
|
|
10334
|
-
const cacheFile =
|
|
10521
|
+
const cacheFile = path9.join(cacheDir, `${key.replace(/[:/]/g, "_")}.json`);
|
|
10335
10522
|
if (!fs2.existsSync(cacheFile)) return null;
|
|
10336
10523
|
const raw = fs2.readFileSync(cacheFile, "utf8");
|
|
10337
10524
|
const data = JSON.parse(raw);
|
|
@@ -10345,7 +10532,7 @@ var ModelCatalog = class {
|
|
|
10345
10532
|
try {
|
|
10346
10533
|
const cacheDir = globalCacheDir();
|
|
10347
10534
|
fs2.mkdirSync(cacheDir, { recursive: true });
|
|
10348
|
-
const cacheFile =
|
|
10535
|
+
const cacheFile = path9.join(cacheDir, `${key.replace(/[:/]/g, "_")}.json`);
|
|
10349
10536
|
fs2.writeFileSync(
|
|
10350
10537
|
cacheFile,
|
|
10351
10538
|
JSON.stringify({ models, cachedAt: Date.now() }, null, 2)
|
|
@@ -10786,7 +10973,7 @@ var import_child_process5 = require("child_process");
|
|
|
10786
10973
|
|
|
10787
10974
|
// src/utils/workspace.ts
|
|
10788
10975
|
var fs3 = __toESM(require("fs"));
|
|
10789
|
-
var
|
|
10976
|
+
var path10 = __toESM(require("path"));
|
|
10790
10977
|
var WorkspaceNotFoundError = class extends Error {
|
|
10791
10978
|
constructor(workspace) {
|
|
10792
10979
|
super(`Workspace "${workspace}" does not exist.`);
|
|
@@ -10842,7 +11029,7 @@ function assertWorkspaceIsProject(workspace, deps = {}) {
|
|
|
10842
11029
|
throw new WorkspaceNotAProjectError(workspace);
|
|
10843
11030
|
}
|
|
10844
11031
|
const hasMarker = [...PROJECT_MARKER_DIRS, ...PROJECT_MARKER_FILES].some(
|
|
10845
|
-
(marker2) => exists(
|
|
11032
|
+
(marker2) => exists(path10.join(resolved, marker2))
|
|
10846
11033
|
);
|
|
10847
11034
|
if (!hasMarker) throw new WorkspaceNotAProjectError(workspace);
|
|
10848
11035
|
}
|
|
@@ -11874,14 +12061,14 @@ ${part.text}` : part.text });
|
|
|
11874
12061
|
}
|
|
11875
12062
|
}
|
|
11876
12063
|
}
|
|
11877
|
-
async json(method,
|
|
11878
|
-
const response = await this.deps.fetch(`${this.baseUrl}${
|
|
12064
|
+
async json(method, path21, body, signal) {
|
|
12065
|
+
const response = await this.deps.fetch(`${this.baseUrl}${path21}`, {
|
|
11879
12066
|
method,
|
|
11880
12067
|
headers: { "content-type": "application/json" },
|
|
11881
12068
|
...body === void 0 ? {} : { body: JSON.stringify(body) },
|
|
11882
12069
|
...signal ? { signal } : {}
|
|
11883
12070
|
});
|
|
11884
|
-
if (!response.ok) throw new Error(`${method} ${
|
|
12071
|
+
if (!response.ok) throw new Error(`${method} ${path21} failed: ${response.status} ${response.statusText}`);
|
|
11885
12072
|
return await response.json().catch(() => null);
|
|
11886
12073
|
}
|
|
11887
12074
|
nativeSessionId() {
|
|
@@ -12661,18 +12848,18 @@ function retargetTaskRunner(task, runner, catalog) {
|
|
|
12661
12848
|
|
|
12662
12849
|
// src/services/SkillsService.ts
|
|
12663
12850
|
var fs4 = __toESM(require("fs"));
|
|
12664
|
-
var
|
|
12851
|
+
var path12 = __toESM(require("path"));
|
|
12665
12852
|
|
|
12666
12853
|
// src/services/builtinSkills.ts
|
|
12667
|
-
var
|
|
12854
|
+
var path11 = __toESM(require("path"));
|
|
12668
12855
|
var import_url = require("url");
|
|
12669
12856
|
var import_meta = {};
|
|
12670
12857
|
function builtinSkillsDir() {
|
|
12671
|
-
const dir = typeof __dirname !== "undefined" && __dirname ? __dirname :
|
|
12858
|
+
const dir = typeof __dirname !== "undefined" && __dirname ? __dirname : path11.dirname((0, import_url.fileURLToPath)(
|
|
12672
12859
|
// @ts-expect-error - import.meta is only valid under an ESM module setting
|
|
12673
12860
|
import_meta.url
|
|
12674
12861
|
));
|
|
12675
|
-
return
|
|
12862
|
+
return path11.join(dir, "..", "skills");
|
|
12676
12863
|
}
|
|
12677
12864
|
|
|
12678
12865
|
// src/services/SkillsService.ts
|
|
@@ -12711,8 +12898,8 @@ function copyDirSync2(src, dest) {
|
|
|
12711
12898
|
fs4.mkdirSync(dest, { recursive: true });
|
|
12712
12899
|
const entries = fs4.readdirSync(src, { withFileTypes: true });
|
|
12713
12900
|
for (const entry of entries) {
|
|
12714
|
-
const srcPath =
|
|
12715
|
-
const destPath =
|
|
12901
|
+
const srcPath = path12.join(src, entry.name);
|
|
12902
|
+
const destPath = path12.join(dest, entry.name);
|
|
12716
12903
|
if (entry.isDirectory()) copyDirSync2(srcPath, destPath);
|
|
12717
12904
|
else fs4.copyFileSync(srcPath, destPath);
|
|
12718
12905
|
}
|
|
@@ -12723,7 +12910,7 @@ function readDir(dir, source) {
|
|
|
12723
12910
|
const skills = [];
|
|
12724
12911
|
for (const entry of entries) {
|
|
12725
12912
|
if (!entry.isDirectory()) continue;
|
|
12726
|
-
const skillFile =
|
|
12913
|
+
const skillFile = path12.join(dir, entry.name, "SKILL.md");
|
|
12727
12914
|
if (!fs4.existsSync(skillFile)) continue;
|
|
12728
12915
|
const parsed = parseSkillFile(skillFile, entry.name, source);
|
|
12729
12916
|
if (parsed) skills.push(parsed);
|
|
@@ -12736,17 +12923,17 @@ var SkillsService = class {
|
|
|
12736
12923
|
}
|
|
12737
12924
|
workspaceRoot;
|
|
12738
12925
|
localDir() {
|
|
12739
|
-
return this.workspaceRoot ?
|
|
12926
|
+
return this.workspaceRoot ? path12.join(this.workspaceRoot, ".ordewell", "skills") : void 0;
|
|
12740
12927
|
}
|
|
12741
12928
|
globalDir() {
|
|
12742
|
-
return
|
|
12929
|
+
return path12.join(globalDataDir(), "skills");
|
|
12743
12930
|
}
|
|
12744
12931
|
seed(name) {
|
|
12745
|
-
const dest =
|
|
12932
|
+
const dest = path12.join(this.globalDir(), name);
|
|
12746
12933
|
if (fs4.existsSync(dest)) return false;
|
|
12747
12934
|
let srcDir;
|
|
12748
12935
|
try {
|
|
12749
|
-
srcDir =
|
|
12936
|
+
srcDir = path12.join(builtinSkillsDir(), name);
|
|
12750
12937
|
} catch (err) {
|
|
12751
12938
|
console.warn(`Could not locate built-in skills dir: ${String(err)}`);
|
|
12752
12939
|
return false;
|
|
@@ -12772,7 +12959,7 @@ var SkillsService = class {
|
|
|
12772
12959
|
if (entries.length !== 1 || entries[0].name !== "SKILL.md" || !entries[0].isFile()) return false;
|
|
12773
12960
|
let raw;
|
|
12774
12961
|
try {
|
|
12775
|
-
raw = fs4.readFileSync(
|
|
12962
|
+
raw = fs4.readFileSync(path12.join(dir, "SKILL.md"), "utf8");
|
|
12776
12963
|
} catch {
|
|
12777
12964
|
return false;
|
|
12778
12965
|
}
|
|
@@ -12789,7 +12976,7 @@ var SkillsService = class {
|
|
|
12789
12976
|
}
|
|
12790
12977
|
pruneRetired() {
|
|
12791
12978
|
for (const name of RETIRED_BUILTIN_SKILL_NAMES) {
|
|
12792
|
-
const dest =
|
|
12979
|
+
const dest = path12.join(this.globalDir(), name);
|
|
12793
12980
|
if (!fs4.existsSync(dest)) continue;
|
|
12794
12981
|
if (!this.isUnmodifiedRetiredSeed(dest, name)) continue;
|
|
12795
12982
|
try {
|
|
@@ -12804,10 +12991,10 @@ var SkillsService = class {
|
|
|
12804
12991
|
if (BUILTIN_SKILL_NAMES.includes(name)) this.seed(name);
|
|
12805
12992
|
const localDir = this.localDir();
|
|
12806
12993
|
if (localDir) {
|
|
12807
|
-
const localFile =
|
|
12994
|
+
const localFile = path12.join(localDir, name, "SKILL.md");
|
|
12808
12995
|
if (fs4.existsSync(localFile)) return parseSkillFile(localFile, name, "local");
|
|
12809
12996
|
}
|
|
12810
|
-
const globalFile =
|
|
12997
|
+
const globalFile = path12.join(this.globalDir(), name, "SKILL.md");
|
|
12811
12998
|
if (fs4.existsSync(globalFile)) return parseSkillFile(globalFile, name, "global");
|
|
12812
12999
|
return void 0;
|
|
12813
13000
|
}
|
|
@@ -12889,11 +13076,11 @@ function truncateCheckpointSummary(summary) {
|
|
|
12889
13076
|
|
|
12890
13077
|
// src/utils/sessionStore.ts
|
|
12891
13078
|
var fs6 = __toESM(require("fs"));
|
|
12892
|
-
var
|
|
13079
|
+
var path14 = __toESM(require("path"));
|
|
12893
13080
|
|
|
12894
13081
|
// src/utils/fsHelpers.ts
|
|
12895
13082
|
var fs5 = __toESM(require("fs"));
|
|
12896
|
-
var
|
|
13083
|
+
var path13 = __toESM(require("path"));
|
|
12897
13084
|
var STATE_DIR = ".ordewell";
|
|
12898
13085
|
function ensureDir(dir) {
|
|
12899
13086
|
if (!fs5.existsSync(dir)) {
|
|
@@ -12901,14 +13088,14 @@ function ensureDir(dir) {
|
|
|
12901
13088
|
}
|
|
12902
13089
|
}
|
|
12903
13090
|
function getStateDir(baseDir) {
|
|
12904
|
-
return
|
|
13091
|
+
return path13.join(baseDir ?? process.cwd(), STATE_DIR);
|
|
12905
13092
|
}
|
|
12906
13093
|
var IGNORE_FILE = ".gitignore";
|
|
12907
13094
|
function ensureStateDirIgnored(baseDir) {
|
|
12908
13095
|
const dir = getStateDir(baseDir);
|
|
12909
13096
|
ensureDir(dir);
|
|
12910
13097
|
try {
|
|
12911
|
-
fs5.writeFileSync(
|
|
13098
|
+
fs5.writeFileSync(path13.join(dir, IGNORE_FILE), "*\n", { flag: "wx" });
|
|
12912
13099
|
} catch (err) {
|
|
12913
13100
|
if (err.code !== "EEXIST") throw err;
|
|
12914
13101
|
}
|
|
@@ -12923,7 +13110,7 @@ function mintSessionId() {
|
|
|
12923
13110
|
// src/utils/sessionStore.ts
|
|
12924
13111
|
var SESSIONS_SUBDIR = "sessions";
|
|
12925
13112
|
function getSessionsDir(baseDir) {
|
|
12926
|
-
return
|
|
13113
|
+
return path14.join(getStateDir(baseDir), SESSIONS_SUBDIR);
|
|
12927
13114
|
}
|
|
12928
13115
|
var REJECTION_MESSAGE = "This session was created with an older version of Ordewell. Please re-plan.";
|
|
12929
13116
|
function hasScalarRunner(parsed) {
|
|
@@ -12958,7 +13145,7 @@ function saveSession(plan, goal, baseDir, id) {
|
|
|
12958
13145
|
plan: JSON.parse(JSON.stringify(plan))
|
|
12959
13146
|
};
|
|
12960
13147
|
const filename = sessionFilename(meta);
|
|
12961
|
-
const filePath =
|
|
13148
|
+
const filePath = path14.join(sessionsDir, filename);
|
|
12962
13149
|
fs6.writeFileSync(filePath, JSON.stringify(session, null, 2));
|
|
12963
13150
|
return meta;
|
|
12964
13151
|
}
|
|
@@ -12968,7 +13155,7 @@ function listSessions(baseDir, logger = defaultLogger) {
|
|
|
12968
13155
|
const files = fs6.readdirSync(sessionsDir).filter((f) => f.endsWith(".json"));
|
|
12969
13156
|
return files.map((f) => {
|
|
12970
13157
|
try {
|
|
12971
|
-
const raw = fs6.readFileSync(
|
|
13158
|
+
const raw = fs6.readFileSync(path14.join(sessionsDir, f), "utf-8");
|
|
12972
13159
|
const parsed = JSON.parse(raw);
|
|
12973
13160
|
if (hasScalarRunner(parsed)) {
|
|
12974
13161
|
logger.warn("sessionStore", `session file ${f}: ${REJECTION_MESSAGE}`);
|
|
@@ -12986,7 +13173,7 @@ function findSessionFile(sessionsDir, sessionId, logger) {
|
|
|
12986
13173
|
const files = fs6.readdirSync(sessionsDir).filter((f) => f.endsWith(".json"));
|
|
12987
13174
|
for (const f of files) {
|
|
12988
13175
|
try {
|
|
12989
|
-
const raw = fs6.readFileSync(
|
|
13176
|
+
const raw = fs6.readFileSync(path14.join(sessionsDir, f), "utf-8");
|
|
12990
13177
|
const session = JSON.parse(raw);
|
|
12991
13178
|
if (session.meta.id === sessionId) return f;
|
|
12992
13179
|
} catch (err) {
|
|
@@ -13001,7 +13188,7 @@ function loadSession(sessionId, baseDir, logger = defaultLogger) {
|
|
|
13001
13188
|
try {
|
|
13002
13189
|
const file = findSessionFile(sessionsDir, sessionId, logger);
|
|
13003
13190
|
if (file) {
|
|
13004
|
-
const raw = fs6.readFileSync(
|
|
13191
|
+
const raw = fs6.readFileSync(path14.join(sessionsDir, file), "utf-8");
|
|
13005
13192
|
const parsed = JSON.parse(raw);
|
|
13006
13193
|
if (hasScalarRunner(parsed)) {
|
|
13007
13194
|
logger.warn("sessionStore", `session file ${file}: ${REJECTION_MESSAGE}`);
|
|
@@ -13035,7 +13222,7 @@ function deleteSession(sessionId, baseDir, logger = defaultLogger) {
|
|
|
13035
13222
|
try {
|
|
13036
13223
|
const file = findSessionFile(sessionsDir, sessionId, logger);
|
|
13037
13224
|
if (file) {
|
|
13038
|
-
fs6.unlinkSync(
|
|
13225
|
+
fs6.unlinkSync(path14.join(sessionsDir, file));
|
|
13039
13226
|
return true;
|
|
13040
13227
|
}
|
|
13041
13228
|
} catch (err) {
|
|
@@ -13046,7 +13233,7 @@ function deleteSession(sessionId, baseDir, logger = defaultLogger) {
|
|
|
13046
13233
|
|
|
13047
13234
|
// src/utils/prdStore.ts
|
|
13048
13235
|
var fs7 = __toESM(require("fs"));
|
|
13049
|
-
var
|
|
13236
|
+
var path15 = __toESM(require("path"));
|
|
13050
13237
|
var PRD_BLOCK_RE = /<!--\s*ORDEWELL_PRD_START\s+slug="([^"]+)"\s*-->\s*([\s\S]*?)\s*<!--\s*ORDEWELL_PRD_END\s*-->/;
|
|
13051
13238
|
function extractPrdBlock(text) {
|
|
13052
13239
|
const match = PRD_BLOCK_RE.exec(text);
|
|
@@ -13060,9 +13247,9 @@ function sanitizeSlug(raw) {
|
|
|
13060
13247
|
return raw.toLowerCase().replace(/[^a-z0-9-_]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
13061
13248
|
}
|
|
13062
13249
|
function savePrdMarkdown(workspace, slug2, markdown) {
|
|
13063
|
-
const dir =
|
|
13250
|
+
const dir = path15.join(workspace, ".scratch", sanitizeSlug(slug2));
|
|
13064
13251
|
fs7.mkdirSync(dir, { recursive: true });
|
|
13065
|
-
const file =
|
|
13252
|
+
const file = path15.join(dir, "PRD.md");
|
|
13066
13253
|
fs7.writeFileSync(file, markdown.endsWith("\n") ? markdown : markdown + "\n", "utf8");
|
|
13067
13254
|
return file;
|
|
13068
13255
|
}
|
|
@@ -14402,7 +14589,8 @@ function resolveArgs(manifest, ctx) {
|
|
|
14402
14589
|
command: manifest.runner.command,
|
|
14403
14590
|
args,
|
|
14404
14591
|
env,
|
|
14405
|
-
promptInArgs: manifest.runner.promptInArgs
|
|
14592
|
+
promptInArgs: manifest.runner.promptInArgs,
|
|
14593
|
+
submitPromptKey: manifest.runner.submitPromptKey === true && isInteractive(ctx)
|
|
14406
14594
|
};
|
|
14407
14595
|
}
|
|
14408
14596
|
function parseBlockOpen(raw) {
|
|
@@ -14756,7 +14944,8 @@ var HeadlessRunner = class extends AbstractRunner {
|
|
|
14756
14944
|
launch: await planDirectLaunch(command, args, this.launchDeps),
|
|
14757
14945
|
resolvedPath,
|
|
14758
14946
|
env: invocation.env,
|
|
14759
|
-
pty
|
|
14947
|
+
pty,
|
|
14948
|
+
submitPromptKey: invocation.submitPromptKey
|
|
14760
14949
|
};
|
|
14761
14950
|
}
|
|
14762
14951
|
async spawn(opts) {
|
|
@@ -14766,6 +14955,7 @@ var HeadlessRunner = class extends AbstractRunner {
|
|
|
14766
14955
|
const modeStr = opts.mode === "plan" ? "plan" : "build";
|
|
14767
14956
|
console.error(`[headless] Starting ${opts.runner} [${modeStr}] (${opts.modelId || "default"}) for task ${opts.taskId.slice(0, 8)}${prepared.pty ? " (PTY)" : ""}`);
|
|
14768
14957
|
session.start(prepared.launch, opts.cwd, prepared.resolvedPath, prepared.env);
|
|
14958
|
+
if (prepared.submitPromptKey) session.write("\r");
|
|
14769
14959
|
this.registerSession(id, session);
|
|
14770
14960
|
return session;
|
|
14771
14961
|
}
|
|
@@ -14776,7 +14966,7 @@ var import_child_process8 = require("child_process");
|
|
|
14776
14966
|
var import_util4 = require("util");
|
|
14777
14967
|
var import_os = require("os");
|
|
14778
14968
|
var import_path = require("path");
|
|
14779
|
-
var
|
|
14969
|
+
var import_fs2 = require("fs");
|
|
14780
14970
|
|
|
14781
14971
|
// src/utils/tmux.ts
|
|
14782
14972
|
var import_child_process7 = require("child_process");
|
|
@@ -14869,7 +15059,7 @@ var TmuxSession = class extends AbstractTerminalSession {
|
|
|
14869
15059
|
* lets the user keep poking at a finished task's terminal.
|
|
14870
15060
|
*/
|
|
14871
15061
|
async start(command, args, cwd, env) {
|
|
14872
|
-
(0,
|
|
15062
|
+
(0, import_fs2.writeFileSync)(this.logPath, "");
|
|
14873
15063
|
const envAssignments = Object.entries(env ?? {}).map(([k, v]) => `${k}=${posixShellQuote(v)}`).join(" ");
|
|
14874
15064
|
const inner = [command, ...args].map(posixShellQuote).join(" ");
|
|
14875
15065
|
const prefix = envAssignments ? `env ${envAssignments} ` : "";
|
|
@@ -14883,7 +15073,7 @@ var TmuxSession = class extends AbstractTerminalSession {
|
|
|
14883
15073
|
if (this.exited) return;
|
|
14884
15074
|
let content;
|
|
14885
15075
|
try {
|
|
14886
|
-
content = (0,
|
|
15076
|
+
content = (0, import_fs2.existsSync)(this.logPath) ? (0, import_fs2.readFileSync)(this.logPath, "utf8") : "";
|
|
14887
15077
|
} catch {
|
|
14888
15078
|
return;
|
|
14889
15079
|
}
|
|
@@ -14910,7 +15100,7 @@ var TmuxSession = class extends AbstractTerminalSession {
|
|
|
14910
15100
|
this.tmux(["pipe-pane", "-t", this.target]).catch(() => {
|
|
14911
15101
|
});
|
|
14912
15102
|
try {
|
|
14913
|
-
(0,
|
|
15103
|
+
(0, import_fs2.unlinkSync)(this.logPath);
|
|
14914
15104
|
} catch {
|
|
14915
15105
|
}
|
|
14916
15106
|
this.baseHandleExit(code);
|
|
@@ -15067,6 +15257,7 @@ var TmuxRunner = class extends AbstractRunner {
|
|
|
15067
15257
|
);
|
|
15068
15258
|
invocation.env = { ...invocation.env, PATH: await this.resolvePath() };
|
|
15069
15259
|
await session.start(invocation.command, invocation.args, opts.cwd, invocation.env);
|
|
15260
|
+
if (invocation.submitPromptKey) session.write("\r");
|
|
15070
15261
|
this.registerSession(id, session);
|
|
15071
15262
|
return session;
|
|
15072
15263
|
}
|
|
@@ -15074,7 +15265,7 @@ var TmuxRunner = class extends AbstractRunner {
|
|
|
15074
15265
|
|
|
15075
15266
|
// src/utils/daemonToken.ts
|
|
15076
15267
|
var import_crypto2 = require("crypto");
|
|
15077
|
-
var
|
|
15268
|
+
var import_fs3 = require("fs");
|
|
15078
15269
|
var import_path2 = require("path");
|
|
15079
15270
|
var BEARER_PREFIX = "bearer ";
|
|
15080
15271
|
var DAEMON_TOKEN_SUBPROTOCOL_PREFIX = "ordewell.token.";
|
|
@@ -15088,22 +15279,22 @@ function daemonTokenPath(port) {
|
|
|
15088
15279
|
function mintDaemonToken(port) {
|
|
15089
15280
|
const token = (0, import_crypto2.randomBytes)(32).toString("base64url");
|
|
15090
15281
|
const file = daemonTokenPath(port);
|
|
15091
|
-
(0,
|
|
15282
|
+
(0, import_fs3.mkdirSync)(configDir(), { recursive: true });
|
|
15092
15283
|
try {
|
|
15093
|
-
(0,
|
|
15284
|
+
(0, import_fs3.unlinkSync)(file);
|
|
15094
15285
|
} catch {
|
|
15095
15286
|
}
|
|
15096
|
-
const fd = (0,
|
|
15287
|
+
const fd = (0, import_fs3.openSync)(file, "wx", 384);
|
|
15097
15288
|
try {
|
|
15098
|
-
(0,
|
|
15289
|
+
(0, import_fs3.writeSync)(fd, token);
|
|
15099
15290
|
} finally {
|
|
15100
|
-
(0,
|
|
15291
|
+
(0, import_fs3.closeSync)(fd);
|
|
15101
15292
|
}
|
|
15102
15293
|
return { token, file };
|
|
15103
15294
|
}
|
|
15104
15295
|
function readDaemonToken(port) {
|
|
15105
15296
|
try {
|
|
15106
|
-
const token = (0,
|
|
15297
|
+
const token = (0, import_fs3.readFileSync)(daemonTokenPath(port), "utf8").trim();
|
|
15107
15298
|
return token === "" ? void 0 : token;
|
|
15108
15299
|
} catch {
|
|
15109
15300
|
return void 0;
|
|
@@ -15111,7 +15302,7 @@ function readDaemonToken(port) {
|
|
|
15111
15302
|
}
|
|
15112
15303
|
function clearDaemonToken(port) {
|
|
15113
15304
|
try {
|
|
15114
|
-
(0,
|
|
15305
|
+
(0, import_fs3.unlinkSync)(daemonTokenPath(port));
|
|
15115
15306
|
} catch {
|
|
15116
15307
|
}
|
|
15117
15308
|
}
|
|
@@ -15145,17 +15336,17 @@ function tokensMatch(presented, expected) {
|
|
|
15145
15336
|
|
|
15146
15337
|
// src/plugins/RunnerRegistry.ts
|
|
15147
15338
|
var fs9 = __toESM(require("fs"));
|
|
15148
|
-
var
|
|
15149
|
-
var
|
|
15339
|
+
var path18 = __toESM(require("path"));
|
|
15340
|
+
var os5 = __toESM(require("os"));
|
|
15150
15341
|
var import_child_process9 = require("child_process");
|
|
15151
15342
|
var import_crypto3 = require("crypto");
|
|
15152
15343
|
|
|
15153
15344
|
// src/plugins/FsPluginStore.ts
|
|
15154
15345
|
var fs8 = __toESM(require("fs"));
|
|
15155
|
-
var
|
|
15346
|
+
var path17 = __toESM(require("path"));
|
|
15156
15347
|
|
|
15157
15348
|
// src/plugins/pluginNames.ts
|
|
15158
|
-
var
|
|
15349
|
+
var path16 = __toESM(require("path"));
|
|
15159
15350
|
var PLUGIN_NAME_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
|
|
15160
15351
|
var MAX_PLUGIN_NAME_LENGTH = 64;
|
|
15161
15352
|
function isPlainPluginName(name) {
|
|
@@ -15170,10 +15361,10 @@ function assertPlainPluginName(name) {
|
|
|
15170
15361
|
}
|
|
15171
15362
|
function resolvePluginInstallDir(pluginsDir, name) {
|
|
15172
15363
|
assertPlainPluginName(name);
|
|
15173
|
-
const root =
|
|
15174
|
-
const dest =
|
|
15175
|
-
const relative3 =
|
|
15176
|
-
if (relative3 !== name || relative3 === "" ||
|
|
15364
|
+
const root = path16.resolve(pluginsDir);
|
|
15365
|
+
const dest = path16.resolve(root, name);
|
|
15366
|
+
const relative3 = path16.relative(root, dest);
|
|
15367
|
+
if (relative3 !== name || relative3 === "" || path16.isAbsolute(relative3)) {
|
|
15177
15368
|
throw new Error(`Plugin install path escapes the plugins directory: ${JSON.stringify(name)}`);
|
|
15178
15369
|
}
|
|
15179
15370
|
return dest;
|
|
@@ -15188,10 +15379,10 @@ function isValidManifest(obj) {
|
|
|
15188
15379
|
|
|
15189
15380
|
// src/plugins/FsPluginStore.ts
|
|
15190
15381
|
function userPluginsDir() {
|
|
15191
|
-
return
|
|
15382
|
+
return path17.join(globalDataDir(), "plugins");
|
|
15192
15383
|
}
|
|
15193
15384
|
function loadManifestFromDir(dir) {
|
|
15194
|
-
const manifestPath =
|
|
15385
|
+
const manifestPath = path17.join(dir, "manifest.json");
|
|
15195
15386
|
if (!fs8.existsSync(manifestPath)) return null;
|
|
15196
15387
|
try {
|
|
15197
15388
|
const raw = fs8.readFileSync(manifestPath, "utf8");
|
|
@@ -15206,8 +15397,8 @@ function copyDirSync3(src, dest) {
|
|
|
15206
15397
|
ensureDir(dest);
|
|
15207
15398
|
const entries = fs8.readdirSync(src, { withFileTypes: true });
|
|
15208
15399
|
for (const entry of entries) {
|
|
15209
|
-
const srcPath =
|
|
15210
|
-
const destPath =
|
|
15400
|
+
const srcPath = path17.join(src, entry.name);
|
|
15401
|
+
const destPath = path17.join(dest, entry.name);
|
|
15211
15402
|
if (entry.isDirectory()) {
|
|
15212
15403
|
copyDirSync3(srcPath, destPath);
|
|
15213
15404
|
} else {
|
|
@@ -15219,7 +15410,7 @@ function rmDirSync(dir) {
|
|
|
15219
15410
|
if (!fs8.existsSync(dir)) return;
|
|
15220
15411
|
const entries = fs8.readdirSync(dir, { withFileTypes: true });
|
|
15221
15412
|
for (const entry of entries) {
|
|
15222
|
-
const p =
|
|
15413
|
+
const p = path17.join(dir, entry.name);
|
|
15223
15414
|
if (entry.isDirectory()) {
|
|
15224
15415
|
rmDirSync(p);
|
|
15225
15416
|
} else {
|
|
@@ -15272,11 +15463,11 @@ var FsPluginStore = class {
|
|
|
15272
15463
|
return null;
|
|
15273
15464
|
}
|
|
15274
15465
|
}
|
|
15275
|
-
dirExists(
|
|
15276
|
-
return fs8.existsSync(
|
|
15466
|
+
dirExists(path21) {
|
|
15467
|
+
return fs8.existsSync(path21) && fs8.statSync(path21).isDirectory();
|
|
15277
15468
|
}
|
|
15278
|
-
exists(
|
|
15279
|
-
return fs8.existsSync(
|
|
15469
|
+
exists(path21) {
|
|
15470
|
+
return fs8.existsSync(path21);
|
|
15280
15471
|
}
|
|
15281
15472
|
};
|
|
15282
15473
|
|
|
@@ -15535,7 +15726,12 @@ var OPENCODE_MANIFEST = {
|
|
|
15535
15726
|
OPENCODE_CONFIG_CONTENT: "{{if interactiveVariant}}{{opencodeVariantConfig}}{{/if}}"
|
|
15536
15727
|
},
|
|
15537
15728
|
promptInArgs: true,
|
|
15538
|
-
requiresTty: true
|
|
15729
|
+
requiresTty: true,
|
|
15730
|
+
// `--prompt` only pre-fills the TUI's composer; it does not submit it.
|
|
15731
|
+
// (`opencode run` — the headless subcommand — has no such gap: its
|
|
15732
|
+
// message is a positional arg that runs immediately.) An unattended
|
|
15733
|
+
// surface driving the TUI must press Enter itself.
|
|
15734
|
+
submitPromptKey: true
|
|
15539
15735
|
},
|
|
15540
15736
|
features: {
|
|
15541
15737
|
modelSelection: true,
|
|
@@ -15703,7 +15899,7 @@ var RunnerRegistry = class {
|
|
|
15703
15899
|
return entry?.source === "builtin";
|
|
15704
15900
|
}
|
|
15705
15901
|
installFromPath(sourcePath) {
|
|
15706
|
-
const absPath =
|
|
15902
|
+
const absPath = path18.resolve(sourcePath);
|
|
15707
15903
|
if (!this.store.dirExists(absPath)) {
|
|
15708
15904
|
throw new Error(`Plugin source must be a directory: ${absPath}`);
|
|
15709
15905
|
}
|
|
@@ -15715,7 +15911,7 @@ var RunnerRegistry = class {
|
|
|
15715
15911
|
}
|
|
15716
15912
|
installFromGit(url) {
|
|
15717
15913
|
const validated = assertInstallablePluginUrl(url);
|
|
15718
|
-
const tmpDir =
|
|
15914
|
+
const tmpDir = path18.join(os5.tmpdir(), `ordewell-plugin-${(0, import_crypto3.randomBytes)(12).toString("hex")}`);
|
|
15719
15915
|
this.store.ensureDir(tmpDir);
|
|
15720
15916
|
try {
|
|
15721
15917
|
try {
|
|
@@ -15728,7 +15924,7 @@ var RunnerRegistry = class {
|
|
|
15728
15924
|
const hasManifest = contents.some((f) => f === "manifest.json");
|
|
15729
15925
|
let sourceDir = tmpDir;
|
|
15730
15926
|
if (!hasManifest) {
|
|
15731
|
-
const onlyEntry = contents.length === 1 ?
|
|
15927
|
+
const onlyEntry = contents.length === 1 ? path18.join(tmpDir, contents[0]) : void 0;
|
|
15732
15928
|
if (!onlyEntry || !this.store.dirExists(onlyEntry)) {
|
|
15733
15929
|
throw new Error(`No manifest.json found in repository: ${validated.toString()}`);
|
|
15734
15930
|
}
|
|
@@ -15776,7 +15972,7 @@ var RunnerRegistry = class {
|
|
|
15776
15972
|
}
|
|
15777
15973
|
createSkeleton(name, outputDir) {
|
|
15778
15974
|
assertPlainPluginName(name);
|
|
15779
|
-
const dir =
|
|
15975
|
+
const dir = path18.resolve(outputDir, name);
|
|
15780
15976
|
this.store.ensureDir(dir);
|
|
15781
15977
|
const manifest = {
|
|
15782
15978
|
name,
|
|
@@ -15808,8 +16004,8 @@ var RunnerRegistry = class {
|
|
|
15808
16004
|
]
|
|
15809
16005
|
}
|
|
15810
16006
|
};
|
|
15811
|
-
this.store.writeFile(
|
|
15812
|
-
const runSh =
|
|
16007
|
+
this.store.writeFile(path18.join(dir, "manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
|
|
16008
|
+
const runSh = path18.join(dir, "run.sh");
|
|
15813
16009
|
const scriptContent = `#!/usr/bin/env bash
|
|
15814
16010
|
# Custom runner script for ${name}
|
|
15815
16011
|
# Receives:
|
|
@@ -15842,14 +16038,14 @@ function fsChmodSync(fpath, mode) {
|
|
|
15842
16038
|
|
|
15843
16039
|
// src/utils/stateStore.ts
|
|
15844
16040
|
var fs10 = __toESM(require("fs"));
|
|
15845
|
-
var
|
|
16041
|
+
var path19 = __toESM(require("path"));
|
|
15846
16042
|
var STATE_FILE = "state.json";
|
|
15847
16043
|
function getStatePath(baseDir) {
|
|
15848
|
-
return
|
|
16044
|
+
return path19.join(getStateDir(baseDir), STATE_FILE);
|
|
15849
16045
|
}
|
|
15850
16046
|
function saveState(plan, baseDir) {
|
|
15851
16047
|
const statePath = getStatePath(baseDir ?? process.cwd());
|
|
15852
|
-
ensureDir(
|
|
16048
|
+
ensureDir(path19.dirname(statePath));
|
|
15853
16049
|
plan.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
|
|
15854
16050
|
fs10.writeFileSync(statePath, JSON.stringify(plan, null, 2));
|
|
15855
16051
|
}
|
|
@@ -15882,7 +16078,7 @@ function stateExists(baseDir) {
|
|
|
15882
16078
|
|
|
15883
16079
|
// src/services/SettingsService.ts
|
|
15884
16080
|
var fs11 = __toESM(require("fs"));
|
|
15885
|
-
var
|
|
16081
|
+
var path20 = __toESM(require("path"));
|
|
15886
16082
|
var DEFAULTS = {
|
|
15887
16083
|
tdd: { enabled: true },
|
|
15888
16084
|
verification: { enabled: false }
|
|
@@ -15890,7 +16086,7 @@ var DEFAULTS = {
|
|
|
15890
16086
|
function getSettingsPath() {
|
|
15891
16087
|
const override = process.env.ORDEWELL_SETTINGS_PATH;
|
|
15892
16088
|
if (override && override.trim()) return override.trim();
|
|
15893
|
-
return
|
|
16089
|
+
return path20.join(globalDataDir(), "settings.json");
|
|
15894
16090
|
}
|
|
15895
16091
|
function readPlannerModels(raw) {
|
|
15896
16092
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
@@ -16018,7 +16214,7 @@ var SettingsService = class {
|
|
|
16018
16214
|
return { ...DEFAULTS, tdd: { ...DEFAULTS.tdd }, verification: { ...DEFAULTS.verification } };
|
|
16019
16215
|
}
|
|
16020
16216
|
persist() {
|
|
16021
|
-
const dir =
|
|
16217
|
+
const dir = path20.dirname(this.filePath);
|
|
16022
16218
|
if (!fs11.existsSync(dir)) {
|
|
16023
16219
|
fs11.mkdirSync(dir, { recursive: true });
|
|
16024
16220
|
}
|