@ordewell/core 0.4.20 → 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/index.d.mts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +312 -125
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +305 -118
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -6225,6 +6225,19 @@ function renderTerminalOutput(raw) {
|
|
|
6225
6225
|
}
|
|
6226
6226
|
var MARKER_SCAN_TAIL = 16384;
|
|
6227
6227
|
var IDLE_TIMEOUT_MS = 6e4;
|
|
6228
|
+
function renderCleanCapture(raw, doneToken) {
|
|
6229
|
+
const rendered = renderTerminalOutput(raw).replace(/[\s─-▟]+$/gm, "");
|
|
6230
|
+
if (!doneToken) return rendered.trim();
|
|
6231
|
+
const lines = rendered.split("\n");
|
|
6232
|
+
const flat = (s) => flattenTerminalOutput(s);
|
|
6233
|
+
for (let i = 0; i < lines.length; i++) {
|
|
6234
|
+
const own = flat(lines[i]).includes(doneToken);
|
|
6235
|
+
if (own) return lines.slice(0, i).join("\n").trim();
|
|
6236
|
+
const window = flat(lines[i]) + (i + 1 < lines.length ? flat(lines[i + 1]) : "");
|
|
6237
|
+
if (window.includes(doneToken)) return lines.slice(0, i + 1).join("\n").trim();
|
|
6238
|
+
}
|
|
6239
|
+
return rendered.trim();
|
|
6240
|
+
}
|
|
6228
6241
|
var VerdictEngine = class {
|
|
6229
6242
|
markerSeen = /* @__PURE__ */ new Set();
|
|
6230
6243
|
buffers = /* @__PURE__ */ new Map();
|
|
@@ -6452,6 +6465,167 @@ ${line}
|
|
|
6452
6465
|
}
|
|
6453
6466
|
};
|
|
6454
6467
|
|
|
6468
|
+
// src/services/transcriptCapture.ts
|
|
6469
|
+
import { readFileSync, readdirSync, statSync as statSync2, existsSync } from "fs";
|
|
6470
|
+
import * as os2 from "os";
|
|
6471
|
+
import * as path4 from "path";
|
|
6472
|
+
function homeDir() {
|
|
6473
|
+
return process.env.HOME || os2.homedir();
|
|
6474
|
+
}
|
|
6475
|
+
async function readFinalAssistantText(query, maxChars = 4e3) {
|
|
6476
|
+
try {
|
|
6477
|
+
if (query.runner === "claude-code") return claudeFinal(query, maxChars);
|
|
6478
|
+
if (query.runner === "opencode") return await opencodeFinal(query, maxChars);
|
|
6479
|
+
if (query.runner === "codex") return codexFinal(query, maxChars);
|
|
6480
|
+
} catch {
|
|
6481
|
+
}
|
|
6482
|
+
return null;
|
|
6483
|
+
}
|
|
6484
|
+
function claudeFinal(query, maxChars) {
|
|
6485
|
+
const munged = query.cwd.replaceAll("/", "-").replaceAll("_", "-");
|
|
6486
|
+
const dir = path4.join(homeDir(), ".claude", "projects", munged);
|
|
6487
|
+
if (!existsSync(dir)) return null;
|
|
6488
|
+
const cutoff = query.startedAt ? Date.parse(query.startedAt) : 0;
|
|
6489
|
+
const candidates = readdirSync(dir).filter((f) => f.endsWith(".jsonl")).map((f) => path4.join(dir, f)).filter((f) => cutoff ? statSync2(f).mtimeMs >= cutoff - 5e3 : true).sort((a, b) => statSync2(b).mtimeMs - statSync2(a).mtimeMs);
|
|
6490
|
+
for (const file of candidates) {
|
|
6491
|
+
const text = claudeLastAssistant(file);
|
|
6492
|
+
if (text) return clamp(text, maxChars);
|
|
6493
|
+
}
|
|
6494
|
+
return null;
|
|
6495
|
+
}
|
|
6496
|
+
function claudeLastAssistant(file) {
|
|
6497
|
+
let last = null;
|
|
6498
|
+
let buf = "";
|
|
6499
|
+
const fd = statSync2(file);
|
|
6500
|
+
const start = Math.max(0, fd.size - 512 * 1024);
|
|
6501
|
+
buf = readFileSync(file, { encoding: "utf8" }).toString();
|
|
6502
|
+
if (start > 0) buf = buf.slice(buf.indexOf("\n", Math.min(start, buf.length - 1)) + 1);
|
|
6503
|
+
for (const line of buf.split("\n")) {
|
|
6504
|
+
if (!line.trim()) continue;
|
|
6505
|
+
let rec;
|
|
6506
|
+
try {
|
|
6507
|
+
rec = JSON.parse(line);
|
|
6508
|
+
} catch {
|
|
6509
|
+
continue;
|
|
6510
|
+
}
|
|
6511
|
+
if (rec.type !== "assistant" || rec.isSidechain) continue;
|
|
6512
|
+
const content = rec.message?.content;
|
|
6513
|
+
if (!Array.isArray(content)) continue;
|
|
6514
|
+
const texts = content.filter((b) => typeof b === "object" && b !== null && b.type === "text").map((b) => b.text).join("\n").trim();
|
|
6515
|
+
if (texts) last = texts;
|
|
6516
|
+
}
|
|
6517
|
+
return last;
|
|
6518
|
+
}
|
|
6519
|
+
async function opencodeFinal(query, maxChars) {
|
|
6520
|
+
let DatabaseSync;
|
|
6521
|
+
try {
|
|
6522
|
+
({ DatabaseSync } = await import("sqlite"));
|
|
6523
|
+
} catch {
|
|
6524
|
+
return null;
|
|
6525
|
+
}
|
|
6526
|
+
const dbPath = path4.join(homeDir(), ".local", "share", "opencode", "opencode.db");
|
|
6527
|
+
if (!existsSync(dbPath)) return null;
|
|
6528
|
+
let db;
|
|
6529
|
+
try {
|
|
6530
|
+
db = new DatabaseSync(dbPath, { open: true });
|
|
6531
|
+
} catch {
|
|
6532
|
+
return null;
|
|
6533
|
+
}
|
|
6534
|
+
try {
|
|
6535
|
+
const cutoff = query.startedAt ? Date.parse(query.startedAt) : 0;
|
|
6536
|
+
const rows = db.prepare(
|
|
6537
|
+
`select s.id, s.time_updated from session s
|
|
6538
|
+
join project p on p.id = s.project_id
|
|
6539
|
+
where s.directory = ?
|
|
6540
|
+
order by s.time_updated desc limit 5`
|
|
6541
|
+
).all(query.cwd);
|
|
6542
|
+
for (const row of rows) {
|
|
6543
|
+
if (cutoff && row.time_updated < cutoff - 5e3) continue;
|
|
6544
|
+
const parts = db.prepare(
|
|
6545
|
+
`select pt.data from part pt
|
|
6546
|
+
join message m on m.id = pt.message_id
|
|
6547
|
+
where m.session_id = ? and m.data like '%"role":"assistant"%'
|
|
6548
|
+
order by pt.id asc`
|
|
6549
|
+
).all(row.id);
|
|
6550
|
+
let text = null;
|
|
6551
|
+
for (const p of parts) {
|
|
6552
|
+
try {
|
|
6553
|
+
const d = JSON.parse(p.data);
|
|
6554
|
+
if (d.type === "text" && d.text && d.text.trim()) text = d.text.trim();
|
|
6555
|
+
} catch {
|
|
6556
|
+
continue;
|
|
6557
|
+
}
|
|
6558
|
+
}
|
|
6559
|
+
if (text) return clamp(text, maxChars);
|
|
6560
|
+
}
|
|
6561
|
+
return null;
|
|
6562
|
+
} catch {
|
|
6563
|
+
return null;
|
|
6564
|
+
} finally {
|
|
6565
|
+
try {
|
|
6566
|
+
db.close();
|
|
6567
|
+
} catch {
|
|
6568
|
+
}
|
|
6569
|
+
}
|
|
6570
|
+
}
|
|
6571
|
+
function codexFinal(query, maxChars) {
|
|
6572
|
+
const root = path4.join(homeDir(), ".codex", "sessions");
|
|
6573
|
+
if (!existsSync(root)) return null;
|
|
6574
|
+
const cutoff = query.startedAt ? Date.parse(query.startedAt) : 0;
|
|
6575
|
+
const files = [];
|
|
6576
|
+
const stack = [root];
|
|
6577
|
+
while (stack.length) {
|
|
6578
|
+
const dir = stack.pop();
|
|
6579
|
+
let entries;
|
|
6580
|
+
try {
|
|
6581
|
+
entries = readdirSync(dir);
|
|
6582
|
+
} catch {
|
|
6583
|
+
continue;
|
|
6584
|
+
}
|
|
6585
|
+
for (const e of entries) {
|
|
6586
|
+
const full = path4.join(dir, e);
|
|
6587
|
+
let st;
|
|
6588
|
+
try {
|
|
6589
|
+
st = statSync2(full);
|
|
6590
|
+
} catch {
|
|
6591
|
+
continue;
|
|
6592
|
+
}
|
|
6593
|
+
if (st.isDirectory()) stack.push(full);
|
|
6594
|
+
else if (e.startsWith("rollout-") && e.endsWith(".jsonl") && (!cutoff || st.mtimeMs >= cutoff - 5e3)) files.push(full);
|
|
6595
|
+
}
|
|
6596
|
+
}
|
|
6597
|
+
files.sort((a, b) => statSync2(b).mtimeMs - statSync2(a).mtimeMs);
|
|
6598
|
+
for (const file of files.slice(0, 10)) {
|
|
6599
|
+
const text = codexLastAssistant(file, query.cwd);
|
|
6600
|
+
if (text) return clamp(text, maxChars);
|
|
6601
|
+
}
|
|
6602
|
+
return null;
|
|
6603
|
+
}
|
|
6604
|
+
function codexLastAssistant(file, cwd) {
|
|
6605
|
+
const raw = readFileSync(file, "utf8");
|
|
6606
|
+
const lines = raw.split("\n").filter((l) => l.trim());
|
|
6607
|
+
let sawCwd = false;
|
|
6608
|
+
let last = null;
|
|
6609
|
+
for (const line of lines) {
|
|
6610
|
+
let rec;
|
|
6611
|
+
try {
|
|
6612
|
+
rec = JSON.parse(line);
|
|
6613
|
+
} catch {
|
|
6614
|
+
continue;
|
|
6615
|
+
}
|
|
6616
|
+
if (rec.type === "session_meta" && rec.payload?.cwd === cwd) sawCwd = true;
|
|
6617
|
+
if (rec.type !== "response_item") continue;
|
|
6618
|
+
const p = rec.payload;
|
|
6619
|
+
if (p?.role !== "assistant" || p.type !== "message") continue;
|
|
6620
|
+
const texts = (Array.isArray(p.content) ? p.content : []).map((c) => typeof c === "object" && c !== null && c.text || "").join("\n").trim();
|
|
6621
|
+
if (texts) last = texts;
|
|
6622
|
+
}
|
|
6623
|
+
return sawCwd ? last : null;
|
|
6624
|
+
}
|
|
6625
|
+
function clamp(text, maxChars) {
|
|
6626
|
+
return text.length <= maxChars ? text : text.slice(-maxChars);
|
|
6627
|
+
}
|
|
6628
|
+
|
|
6455
6629
|
// src/services/PlanStore.ts
|
|
6456
6630
|
var PlanStore = class {
|
|
6457
6631
|
_planTasks = [];
|
|
@@ -6833,6 +7007,11 @@ var TaskOrchestrator = class {
|
|
|
6833
7007
|
workspaceRootFn = () => process.cwd();
|
|
6834
7008
|
observers = [];
|
|
6835
7009
|
tddEnabled = () => false;
|
|
7010
|
+
/**
|
|
7011
|
+
* Spawn context per active task, for locating the agent's own session
|
|
7012
|
+
* transcript at verdict time (issue #16). Cleared with the session entry.
|
|
7013
|
+
*/
|
|
7014
|
+
taskSpawnContext = /* @__PURE__ */ new Map();
|
|
6836
7015
|
/** Advisory silence timestamp for a task's live runner, or null if not idle. */
|
|
6837
7016
|
getIdleSince(taskId) {
|
|
6838
7017
|
return this.verifier.getIdleSince(taskId);
|
|
@@ -6995,6 +7174,8 @@ var TaskOrchestrator = class {
|
|
|
6995
7174
|
const task = this.store.get(taskId);
|
|
6996
7175
|
if (!task) return;
|
|
6997
7176
|
this.activeTaskSessions.delete(taskId);
|
|
7177
|
+
const spawnContext = this.taskSpawnContext.get(taskId);
|
|
7178
|
+
this.taskSpawnContext.delete(taskId);
|
|
6998
7179
|
console.error(`[TaskOrchestrator] Task #${task.order} "${task.title}" verdict=${verdict.outcome}`);
|
|
6999
7180
|
console.error(`[TaskOrchestrator] Runner: ${task.assignedRunner}, Model: ${task.assignedModel?.modelId ?? "default"}`);
|
|
7000
7181
|
console.error(`[TaskOrchestrator] Prompt preview: ${(task.prompt ?? "").slice(0, 200)}`);
|
|
@@ -7005,6 +7186,10 @@ ${output.slice(-3e3)}`);
|
|
|
7005
7186
|
console.error(`[TaskOrchestrator] Output: (empty \u2014 no stdout/stderr captured)`);
|
|
7006
7187
|
}
|
|
7007
7188
|
this.store.setTaskVerdict(taskId, verdict);
|
|
7189
|
+
const doneToken = `<<<ORDEWELL_DONE_${task.completionMarker}>>>`;
|
|
7190
|
+
const transcript = spawnContext ? await readFinalAssistantText(spawnContext) : null;
|
|
7191
|
+
const cleaned = transcript ?? renderCleanCapture(output, doneToken);
|
|
7192
|
+
const effective = cleaned.length > 0 ? cleaned : output;
|
|
7008
7193
|
if (verdict.outcome === "pass") {
|
|
7009
7194
|
this.store.markCompleted(taskId);
|
|
7010
7195
|
this.notifications.info(`Task "${task.title}" completed.`);
|
|
@@ -7014,7 +7199,7 @@ ${output.slice(-3e3)}`);
|
|
|
7014
7199
|
this.planStatus = "approved";
|
|
7015
7200
|
this.notifications.error(`Task "${task.title}" failed verification: ${verdict.reason}`);
|
|
7016
7201
|
}
|
|
7017
|
-
this.store.setTaskOutputSummary(taskId, summarizeOutput(verdict.reason,
|
|
7202
|
+
this.store.setTaskOutputSummary(taskId, summarizeOutput(verdict.reason, effective));
|
|
7018
7203
|
this.logAndArchive(task, verdict);
|
|
7019
7204
|
this.emit("onTaskChanged");
|
|
7020
7205
|
if (!this.running) {
|
|
@@ -7254,6 +7439,8 @@ ${output.slice(-3e3)}`);
|
|
|
7254
7439
|
try {
|
|
7255
7440
|
const cwd = this.workspaceRootFn();
|
|
7256
7441
|
const runner = this.store.resolveTaskRunner(task);
|
|
7442
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7443
|
+
this.taskSpawnContext.set(task.id, { runner, cwd, startedAt });
|
|
7257
7444
|
const finalPrompt = composeAugmentedPrompt(task, this.store.planTasks, {
|
|
7258
7445
|
planMapEnabled: this.config.planMapEnabled,
|
|
7259
7446
|
tddEnabled: this.tddEnabled()
|
|
@@ -7418,7 +7605,7 @@ ${errors.map((e) => `- ${e}`).join("\n")}`
|
|
|
7418
7605
|
};
|
|
7419
7606
|
|
|
7420
7607
|
// src/services/ModelDiscovery.ts
|
|
7421
|
-
import * as
|
|
7608
|
+
import * as path8 from "path";
|
|
7422
7609
|
import { exec as exec2, spawn } from "child_process";
|
|
7423
7610
|
import { promisify as promisify2 } from "util";
|
|
7424
7611
|
import * as fsSync3 from "fs";
|
|
@@ -7427,8 +7614,8 @@ import * as osMod from "os";
|
|
|
7427
7614
|
// src/utils/shellPath.ts
|
|
7428
7615
|
import { exec } from "child_process";
|
|
7429
7616
|
import { promisify } from "util";
|
|
7430
|
-
import * as
|
|
7431
|
-
import * as
|
|
7617
|
+
import * as os3 from "os";
|
|
7618
|
+
import * as path5 from "path";
|
|
7432
7619
|
var execAsync = promisify(exec);
|
|
7433
7620
|
var LOGIN_SHELL_TIMEOUT_MS = 5e3;
|
|
7434
7621
|
var PATH_MARKER = "__ORDEWELL_PATH__";
|
|
@@ -7437,42 +7624,42 @@ var defaultExec = async (command, options) => {
|
|
|
7437
7624
|
return { stdout: String(stdout) };
|
|
7438
7625
|
};
|
|
7439
7626
|
function posixBinDirs() {
|
|
7440
|
-
const home =
|
|
7627
|
+
const home = os3.homedir();
|
|
7441
7628
|
return [
|
|
7442
|
-
|
|
7443
|
-
|
|
7444
|
-
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
|
|
7448
|
-
|
|
7629
|
+
path5.join(home, ".local", "bin"),
|
|
7630
|
+
path5.join(home, ".opencode", "bin"),
|
|
7631
|
+
path5.join(home, ".claude", "bin"),
|
|
7632
|
+
path5.join(home, ".bun", "bin"),
|
|
7633
|
+
path5.join(home, ".volta", "bin"),
|
|
7634
|
+
path5.join(home, ".npm-global", "bin"),
|
|
7635
|
+
path5.join(home, "bin"),
|
|
7449
7636
|
"/usr/local/bin",
|
|
7450
7637
|
"/opt/homebrew/bin"
|
|
7451
7638
|
];
|
|
7452
7639
|
}
|
|
7453
7640
|
function windowsBinDirs(env, home) {
|
|
7454
|
-
const
|
|
7455
|
-
const under = (base, ...parts) => base ? [
|
|
7641
|
+
const join20 = (...parts) => path5.win32.join(...parts);
|
|
7642
|
+
const under = (base, ...parts) => base ? [join20(base, ...parts)] : [];
|
|
7456
7643
|
const appData = env.APPDATA;
|
|
7457
7644
|
const localAppData = env.LOCALAPPDATA;
|
|
7458
7645
|
const programData = env.ProgramData;
|
|
7459
7646
|
return [
|
|
7460
7647
|
// Native per-user installers, PowerShell-driven and otherwise.
|
|
7461
|
-
|
|
7462
|
-
|
|
7463
|
-
|
|
7464
|
-
|
|
7648
|
+
join20(home, ".local", "bin"),
|
|
7649
|
+
join20(home, ".opencode", "bin"),
|
|
7650
|
+
join20(home, ".claude", "bin"),
|
|
7651
|
+
join20(home, ".codex", "bin"),
|
|
7465
7652
|
...under(localAppData, "Programs", "claude"),
|
|
7466
7653
|
// Node package managers. npm's global prefix is `%APPDATA%\npm`; the
|
|
7467
7654
|
// literal spelling is kept as a fallback for a host that does not export
|
|
7468
7655
|
// APPDATA (a service account, a stripped CI container).
|
|
7469
7656
|
...under(appData, "npm"),
|
|
7470
|
-
|
|
7657
|
+
join20(home, "AppData", "Roaming", "npm"),
|
|
7471
7658
|
...under(localAppData, "pnpm"),
|
|
7472
7659
|
...under(localAppData, "Yarn", "bin"),
|
|
7473
|
-
|
|
7660
|
+
join20(home, ".bun", "bin"),
|
|
7474
7661
|
// Windows package managers.
|
|
7475
|
-
|
|
7662
|
+
join20(home, "scoop", "shims"),
|
|
7476
7663
|
...under(env.SCOOP, "shims"),
|
|
7477
7664
|
...under(env.SCOOP_GLOBAL ?? programData, "scoop", "shims"),
|
|
7478
7665
|
...under(programData, "chocolatey", "bin"),
|
|
@@ -7482,13 +7669,13 @@ function windowsBinDirs(env, home) {
|
|
|
7482
7669
|
...under(localAppData, "Microsoft", "WindowsApps"),
|
|
7483
7670
|
// Version managers. Volta's Windows home is not the POSIX `~/.volta`.
|
|
7484
7671
|
...under(localAppData, "Volta", "bin"),
|
|
7485
|
-
|
|
7672
|
+
join20(home, ".volta", "bin")
|
|
7486
7673
|
];
|
|
7487
7674
|
}
|
|
7488
7675
|
function wellKnownBinDirs(deps = {}) {
|
|
7489
7676
|
const platform = deps.platform ?? process.platform;
|
|
7490
7677
|
if (platform !== "win32") return posixBinDirs();
|
|
7491
|
-
return [...new Set(windowsBinDirs(deps.env ?? process.env, deps.home ??
|
|
7678
|
+
return [...new Set(windowsBinDirs(deps.env ?? process.env, deps.home ?? os3.homedir()))];
|
|
7492
7679
|
}
|
|
7493
7680
|
async function loginShellPath(execImpl) {
|
|
7494
7681
|
if (process.platform === "win32") return null;
|
|
@@ -7511,14 +7698,14 @@ function augmentedPath(execImpl = defaultExec) {
|
|
|
7511
7698
|
const segments = [];
|
|
7512
7699
|
const push = (p) => {
|
|
7513
7700
|
if (!p) return;
|
|
7514
|
-
for (const seg of p.split(
|
|
7701
|
+
for (const seg of p.split(path5.delimiter)) {
|
|
7515
7702
|
if (seg && !segments.includes(seg)) segments.push(seg);
|
|
7516
7703
|
}
|
|
7517
7704
|
};
|
|
7518
7705
|
push(process.env.PATH);
|
|
7519
7706
|
push(await loginShellPath(execImpl));
|
|
7520
7707
|
for (const dir of wellKnownBinDirs()) push(dir);
|
|
7521
|
-
return segments.join(
|
|
7708
|
+
return segments.join(path5.delimiter);
|
|
7522
7709
|
})();
|
|
7523
7710
|
}
|
|
7524
7711
|
return cachedPath;
|
|
@@ -7540,17 +7727,17 @@ function withPath(base, resolvedPath, overrides = {}) {
|
|
|
7540
7727
|
|
|
7541
7728
|
// src/utils/globalDataDir.ts
|
|
7542
7729
|
import * as fs from "fs";
|
|
7543
|
-
import * as
|
|
7544
|
-
import * as
|
|
7730
|
+
import * as path6 from "path";
|
|
7731
|
+
import * as os4 from "os";
|
|
7545
7732
|
function globalDataDir() {
|
|
7546
|
-
return
|
|
7733
|
+
return path6.join(os4.homedir(), ".ordewell");
|
|
7547
7734
|
}
|
|
7548
7735
|
function copyDirSync(src, dest) {
|
|
7549
7736
|
fs.mkdirSync(dest, { recursive: true });
|
|
7550
7737
|
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
7551
7738
|
for (const entry of entries) {
|
|
7552
|
-
const srcPath =
|
|
7553
|
-
const destPath =
|
|
7739
|
+
const srcPath = path6.join(src, entry.name);
|
|
7740
|
+
const destPath = path6.join(dest, entry.name);
|
|
7554
7741
|
if (entry.isDirectory()) {
|
|
7555
7742
|
copyDirSync(srcPath, destPath);
|
|
7556
7743
|
} else {
|
|
@@ -7562,12 +7749,12 @@ var migrated = false;
|
|
|
7562
7749
|
function migrateOldConfigDir() {
|
|
7563
7750
|
if (migrated) return;
|
|
7564
7751
|
migrated = true;
|
|
7565
|
-
const oldDir =
|
|
7752
|
+
const oldDir = path6.join(os4.homedir(), ".config", "ordewell");
|
|
7566
7753
|
if (!fs.existsSync(oldDir)) return;
|
|
7567
7754
|
const newDir = globalDataDir();
|
|
7568
7755
|
const liftFile = (name) => {
|
|
7569
|
-
const oldFile =
|
|
7570
|
-
const newFile =
|
|
7756
|
+
const oldFile = path6.join(oldDir, name);
|
|
7757
|
+
const newFile = path6.join(newDir, name);
|
|
7571
7758
|
if (fs.existsSync(oldFile) && !fs.existsSync(newFile)) {
|
|
7572
7759
|
fs.mkdirSync(newDir, { recursive: true });
|
|
7573
7760
|
fs.copyFileSync(oldFile, newFile);
|
|
@@ -7575,8 +7762,8 @@ function migrateOldConfigDir() {
|
|
|
7575
7762
|
};
|
|
7576
7763
|
liftFile("settings.json");
|
|
7577
7764
|
liftFile(".env");
|
|
7578
|
-
const oldPlugins =
|
|
7579
|
-
const newPlugins =
|
|
7765
|
+
const oldPlugins = path6.join(oldDir, "plugins");
|
|
7766
|
+
const newPlugins = path6.join(newDir, "plugins");
|
|
7580
7767
|
if (fs.existsSync(oldPlugins) && !fs.existsSync(newPlugins)) {
|
|
7581
7768
|
copyDirSync(oldPlugins, newPlugins);
|
|
7582
7769
|
}
|
|
@@ -7584,7 +7771,7 @@ function migrateOldConfigDir() {
|
|
|
7584
7771
|
|
|
7585
7772
|
// src/utils/launch.ts
|
|
7586
7773
|
import * as fsSync2 from "fs";
|
|
7587
|
-
import * as
|
|
7774
|
+
import * as path7 from "path";
|
|
7588
7775
|
|
|
7589
7776
|
// src/utils/shell.ts
|
|
7590
7777
|
var ANSI_RE = /\x1b\[[0-9;]*[A-Za-z]|\x1b\][^\x07]*\x07|\x1b[()][AB012]|\r/g;
|
|
@@ -7613,7 +7800,7 @@ var CMD_EXE_MAX_COMMAND_LINE = 8191;
|
|
|
7613
7800
|
var WINDOWS_MAX_COMMAND_LINE = 32767;
|
|
7614
7801
|
function defaultPowerShell() {
|
|
7615
7802
|
const root = process.env.SystemRoot || process.env.windir;
|
|
7616
|
-
return root ?
|
|
7803
|
+
return root ? path7.win32.join(root, "System32", "WindowsPowerShell", "v1.0", "powershell.exe") : "powershell.exe";
|
|
7617
7804
|
}
|
|
7618
7805
|
var POWERSHELL_FLAGS = ["-NoLogo", "-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File"];
|
|
7619
7806
|
var CommandLineTooLongError = class extends Error {
|
|
@@ -7665,7 +7852,7 @@ Searched: ${searchedPath || "(empty PATH)"}`);
|
|
|
7665
7852
|
};
|
|
7666
7853
|
function isResolvableOnPosixPath(command, PATH, exists) {
|
|
7667
7854
|
if (command.includes("/")) return exists(command);
|
|
7668
|
-
return PATH.split(
|
|
7855
|
+
return PATH.split(path7.delimiter).map((d) => d.trim()).filter(Boolean).some((dir) => exists(path7.join(dir, command)));
|
|
7669
7856
|
}
|
|
7670
7857
|
function isExecutableResolved(command, plan, PATH, deps = {}) {
|
|
7671
7858
|
if ((deps.platform ?? process.platform) === "win32") return plan.file !== command;
|
|
@@ -7705,9 +7892,9 @@ function cmdArgs(line) {
|
|
|
7705
7892
|
return ["/d", "/s", "/c", `"${line}"`];
|
|
7706
7893
|
}
|
|
7707
7894
|
function candidateExtensions(command, pathExt) {
|
|
7708
|
-
const declared = pathExt.split(
|
|
7895
|
+
const declared = pathExt.split(path7.win32.delimiter).map((e) => e.trim().toLowerCase()).filter(Boolean);
|
|
7709
7896
|
const known = /* @__PURE__ */ new Set([...DIRECT_EXTENSIONS, ...BATCH_EXTENSIONS, ...POWERSHELL_EXTENSIONS, ...declared]);
|
|
7710
|
-
const ext =
|
|
7897
|
+
const ext = path7.win32.extname(command).toLowerCase();
|
|
7711
7898
|
if (ext && known.has(ext)) {
|
|
7712
7899
|
const route = BATCH_EXTENSIONS.includes(ext) ? "cmd" : POWERSHELL_EXTENSIONS.includes(ext) ? "powershell" : "direct";
|
|
7713
7900
|
return { direct: [], cmd: [], powershell: [], [route]: [""] };
|
|
@@ -7728,13 +7915,13 @@ async function findWindowsExecutables(command, deps) {
|
|
|
7728
7915
|
const exists = deps.exists ?? defaultExists2;
|
|
7729
7916
|
const pathExt = (deps.pathExt ?? (() => process.env.PATHEXT ?? ""))();
|
|
7730
7917
|
const byRoute = candidateExtensions(command, pathExt);
|
|
7731
|
-
const dirs =
|
|
7732
|
-
const base =
|
|
7918
|
+
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);
|
|
7919
|
+
const base = path7.win32.basename(command);
|
|
7733
7920
|
const found = [];
|
|
7734
7921
|
for (const route of ROUTES) {
|
|
7735
7922
|
outer: for (const ext of byRoute[route]) {
|
|
7736
7923
|
for (const dir of dirs) {
|
|
7737
|
-
const candidate =
|
|
7924
|
+
const candidate = path7.win32.join(dir, `${base}${ext}`);
|
|
7738
7925
|
if (exists(candidate)) {
|
|
7739
7926
|
found.push({ file: candidate, route });
|
|
7740
7927
|
break outer;
|
|
@@ -7914,7 +8101,7 @@ function geminiDiscoveryCacheKey(apiKey) {
|
|
|
7914
8101
|
return {
|
|
7915
8102
|
key: `gemini-models:${hash}`,
|
|
7916
8103
|
dir,
|
|
7917
|
-
file:
|
|
8104
|
+
file: path8.join(dir, `gemini_models_${hash}.json`)
|
|
7918
8105
|
};
|
|
7919
8106
|
}
|
|
7920
8107
|
function readGeminiCache(apiKey) {
|
|
@@ -8438,7 +8625,7 @@ var ModelDiscovery = class {
|
|
|
8438
8625
|
|
|
8439
8626
|
// src/services/ModelCatalog.ts
|
|
8440
8627
|
import * as fs2 from "fs";
|
|
8441
|
-
import * as
|
|
8628
|
+
import * as path9 from "path";
|
|
8442
8629
|
var CACHE_KEY = "model-catalog";
|
|
8443
8630
|
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
8444
8631
|
function storageKey(baseUrl) {
|
|
@@ -8490,7 +8677,7 @@ var ModelCatalog = class {
|
|
|
8490
8677
|
const url = (baseUrl || "https://openrouter.ai/api/v1").replace(/\/+$/, "");
|
|
8491
8678
|
const key = storageKey(url);
|
|
8492
8679
|
const cacheDir = globalCacheDir();
|
|
8493
|
-
const cacheFile =
|
|
8680
|
+
const cacheFile = path9.join(cacheDir, `${key.replace(/[:/]/g, "_")}.json`);
|
|
8494
8681
|
if (fs2.existsSync(cacheFile)) fs2.rmSync(cacheFile);
|
|
8495
8682
|
} catch {
|
|
8496
8683
|
}
|
|
@@ -8498,7 +8685,7 @@ var ModelCatalog = class {
|
|
|
8498
8685
|
static readCache(key) {
|
|
8499
8686
|
try {
|
|
8500
8687
|
const cacheDir = globalCacheDir();
|
|
8501
|
-
const cacheFile =
|
|
8688
|
+
const cacheFile = path9.join(cacheDir, `${key.replace(/[:/]/g, "_")}.json`);
|
|
8502
8689
|
if (!fs2.existsSync(cacheFile)) return null;
|
|
8503
8690
|
const raw = fs2.readFileSync(cacheFile, "utf8");
|
|
8504
8691
|
const data = JSON.parse(raw);
|
|
@@ -8512,7 +8699,7 @@ var ModelCatalog = class {
|
|
|
8512
8699
|
try {
|
|
8513
8700
|
const cacheDir = globalCacheDir();
|
|
8514
8701
|
fs2.mkdirSync(cacheDir, { recursive: true });
|
|
8515
|
-
const cacheFile =
|
|
8702
|
+
const cacheFile = path9.join(cacheDir, `${key.replace(/[:/]/g, "_")}.json`);
|
|
8516
8703
|
fs2.writeFileSync(
|
|
8517
8704
|
cacheFile,
|
|
8518
8705
|
JSON.stringify({ models, cachedAt: Date.now() }, null, 2)
|
|
@@ -8953,7 +9140,7 @@ import { spawn as nodeSpawn } from "child_process";
|
|
|
8953
9140
|
|
|
8954
9141
|
// src/utils/workspace.ts
|
|
8955
9142
|
import * as fs3 from "fs";
|
|
8956
|
-
import * as
|
|
9143
|
+
import * as path10 from "path";
|
|
8957
9144
|
var WorkspaceNotFoundError = class extends Error {
|
|
8958
9145
|
constructor(workspace) {
|
|
8959
9146
|
super(`Workspace "${workspace}" does not exist.`);
|
|
@@ -9009,7 +9196,7 @@ function assertWorkspaceIsProject(workspace, deps = {}) {
|
|
|
9009
9196
|
throw new WorkspaceNotAProjectError(workspace);
|
|
9010
9197
|
}
|
|
9011
9198
|
const hasMarker = [...PROJECT_MARKER_DIRS, ...PROJECT_MARKER_FILES].some(
|
|
9012
|
-
(marker2) => exists(
|
|
9199
|
+
(marker2) => exists(path10.join(resolved, marker2))
|
|
9013
9200
|
);
|
|
9014
9201
|
if (!hasMarker) throw new WorkspaceNotAProjectError(workspace);
|
|
9015
9202
|
}
|
|
@@ -10041,14 +10228,14 @@ ${part.text}` : part.text });
|
|
|
10041
10228
|
}
|
|
10042
10229
|
}
|
|
10043
10230
|
}
|
|
10044
|
-
async json(method,
|
|
10045
|
-
const response = await this.deps.fetch(`${this.baseUrl}${
|
|
10231
|
+
async json(method, path21, body, signal) {
|
|
10232
|
+
const response = await this.deps.fetch(`${this.baseUrl}${path21}`, {
|
|
10046
10233
|
method,
|
|
10047
10234
|
headers: { "content-type": "application/json" },
|
|
10048
10235
|
...body === void 0 ? {} : { body: JSON.stringify(body) },
|
|
10049
10236
|
...signal ? { signal } : {}
|
|
10050
10237
|
});
|
|
10051
|
-
if (!response.ok) throw new Error(`${method} ${
|
|
10238
|
+
if (!response.ok) throw new Error(`${method} ${path21} failed: ${response.status} ${response.statusText}`);
|
|
10052
10239
|
return await response.json().catch(() => null);
|
|
10053
10240
|
}
|
|
10054
10241
|
nativeSessionId() {
|
|
@@ -10828,17 +11015,17 @@ function retargetTaskRunner(task, runner, catalog) {
|
|
|
10828
11015
|
|
|
10829
11016
|
// src/services/SkillsService.ts
|
|
10830
11017
|
import * as fs4 from "fs";
|
|
10831
|
-
import * as
|
|
11018
|
+
import * as path12 from "path";
|
|
10832
11019
|
|
|
10833
11020
|
// src/services/builtinSkills.ts
|
|
10834
|
-
import * as
|
|
11021
|
+
import * as path11 from "path";
|
|
10835
11022
|
import { fileURLToPath } from "url";
|
|
10836
11023
|
function builtinSkillsDir() {
|
|
10837
|
-
const dir = typeof __dirname !== "undefined" && __dirname ? __dirname :
|
|
11024
|
+
const dir = typeof __dirname !== "undefined" && __dirname ? __dirname : path11.dirname(fileURLToPath(
|
|
10838
11025
|
// @ts-expect-error - import.meta is only valid under an ESM module setting
|
|
10839
11026
|
import.meta.url
|
|
10840
11027
|
));
|
|
10841
|
-
return
|
|
11028
|
+
return path11.join(dir, "..", "skills");
|
|
10842
11029
|
}
|
|
10843
11030
|
|
|
10844
11031
|
// src/services/SkillsService.ts
|
|
@@ -10877,8 +11064,8 @@ function copyDirSync2(src, dest) {
|
|
|
10877
11064
|
fs4.mkdirSync(dest, { recursive: true });
|
|
10878
11065
|
const entries = fs4.readdirSync(src, { withFileTypes: true });
|
|
10879
11066
|
for (const entry of entries) {
|
|
10880
|
-
const srcPath =
|
|
10881
|
-
const destPath =
|
|
11067
|
+
const srcPath = path12.join(src, entry.name);
|
|
11068
|
+
const destPath = path12.join(dest, entry.name);
|
|
10882
11069
|
if (entry.isDirectory()) copyDirSync2(srcPath, destPath);
|
|
10883
11070
|
else fs4.copyFileSync(srcPath, destPath);
|
|
10884
11071
|
}
|
|
@@ -10889,7 +11076,7 @@ function readDir(dir, source) {
|
|
|
10889
11076
|
const skills = [];
|
|
10890
11077
|
for (const entry of entries) {
|
|
10891
11078
|
if (!entry.isDirectory()) continue;
|
|
10892
|
-
const skillFile =
|
|
11079
|
+
const skillFile = path12.join(dir, entry.name, "SKILL.md");
|
|
10893
11080
|
if (!fs4.existsSync(skillFile)) continue;
|
|
10894
11081
|
const parsed = parseSkillFile(skillFile, entry.name, source);
|
|
10895
11082
|
if (parsed) skills.push(parsed);
|
|
@@ -10902,17 +11089,17 @@ var SkillsService = class {
|
|
|
10902
11089
|
}
|
|
10903
11090
|
workspaceRoot;
|
|
10904
11091
|
localDir() {
|
|
10905
|
-
return this.workspaceRoot ?
|
|
11092
|
+
return this.workspaceRoot ? path12.join(this.workspaceRoot, ".ordewell", "skills") : void 0;
|
|
10906
11093
|
}
|
|
10907
11094
|
globalDir() {
|
|
10908
|
-
return
|
|
11095
|
+
return path12.join(globalDataDir(), "skills");
|
|
10909
11096
|
}
|
|
10910
11097
|
seed(name) {
|
|
10911
|
-
const dest =
|
|
11098
|
+
const dest = path12.join(this.globalDir(), name);
|
|
10912
11099
|
if (fs4.existsSync(dest)) return false;
|
|
10913
11100
|
let srcDir;
|
|
10914
11101
|
try {
|
|
10915
|
-
srcDir =
|
|
11102
|
+
srcDir = path12.join(builtinSkillsDir(), name);
|
|
10916
11103
|
} catch (err) {
|
|
10917
11104
|
console.warn(`Could not locate built-in skills dir: ${String(err)}`);
|
|
10918
11105
|
return false;
|
|
@@ -10938,7 +11125,7 @@ var SkillsService = class {
|
|
|
10938
11125
|
if (entries.length !== 1 || entries[0].name !== "SKILL.md" || !entries[0].isFile()) return false;
|
|
10939
11126
|
let raw;
|
|
10940
11127
|
try {
|
|
10941
|
-
raw = fs4.readFileSync(
|
|
11128
|
+
raw = fs4.readFileSync(path12.join(dir, "SKILL.md"), "utf8");
|
|
10942
11129
|
} catch {
|
|
10943
11130
|
return false;
|
|
10944
11131
|
}
|
|
@@ -10955,7 +11142,7 @@ var SkillsService = class {
|
|
|
10955
11142
|
}
|
|
10956
11143
|
pruneRetired() {
|
|
10957
11144
|
for (const name of RETIRED_BUILTIN_SKILL_NAMES) {
|
|
10958
|
-
const dest =
|
|
11145
|
+
const dest = path12.join(this.globalDir(), name);
|
|
10959
11146
|
if (!fs4.existsSync(dest)) continue;
|
|
10960
11147
|
if (!this.isUnmodifiedRetiredSeed(dest, name)) continue;
|
|
10961
11148
|
try {
|
|
@@ -10970,10 +11157,10 @@ var SkillsService = class {
|
|
|
10970
11157
|
if (BUILTIN_SKILL_NAMES.includes(name)) this.seed(name);
|
|
10971
11158
|
const localDir = this.localDir();
|
|
10972
11159
|
if (localDir) {
|
|
10973
|
-
const localFile =
|
|
11160
|
+
const localFile = path12.join(localDir, name, "SKILL.md");
|
|
10974
11161
|
if (fs4.existsSync(localFile)) return parseSkillFile(localFile, name, "local");
|
|
10975
11162
|
}
|
|
10976
|
-
const globalFile =
|
|
11163
|
+
const globalFile = path12.join(this.globalDir(), name, "SKILL.md");
|
|
10977
11164
|
if (fs4.existsSync(globalFile)) return parseSkillFile(globalFile, name, "global");
|
|
10978
11165
|
return void 0;
|
|
10979
11166
|
}
|
|
@@ -11002,11 +11189,11 @@ function createSkillsService(workspaceRoot) {
|
|
|
11002
11189
|
|
|
11003
11190
|
// src/utils/sessionStore.ts
|
|
11004
11191
|
import * as fs6 from "fs";
|
|
11005
|
-
import * as
|
|
11192
|
+
import * as path14 from "path";
|
|
11006
11193
|
|
|
11007
11194
|
// src/utils/fsHelpers.ts
|
|
11008
11195
|
import * as fs5 from "fs";
|
|
11009
|
-
import * as
|
|
11196
|
+
import * as path13 from "path";
|
|
11010
11197
|
var STATE_DIR = ".ordewell";
|
|
11011
11198
|
function ensureDir(dir) {
|
|
11012
11199
|
if (!fs5.existsSync(dir)) {
|
|
@@ -11014,14 +11201,14 @@ function ensureDir(dir) {
|
|
|
11014
11201
|
}
|
|
11015
11202
|
}
|
|
11016
11203
|
function getStateDir(baseDir) {
|
|
11017
|
-
return
|
|
11204
|
+
return path13.join(baseDir ?? process.cwd(), STATE_DIR);
|
|
11018
11205
|
}
|
|
11019
11206
|
var IGNORE_FILE = ".gitignore";
|
|
11020
11207
|
function ensureStateDirIgnored(baseDir) {
|
|
11021
11208
|
const dir = getStateDir(baseDir);
|
|
11022
11209
|
ensureDir(dir);
|
|
11023
11210
|
try {
|
|
11024
|
-
fs5.writeFileSync(
|
|
11211
|
+
fs5.writeFileSync(path13.join(dir, IGNORE_FILE), "*\n", { flag: "wx" });
|
|
11025
11212
|
} catch (err) {
|
|
11026
11213
|
if (err.code !== "EEXIST") throw err;
|
|
11027
11214
|
}
|
|
@@ -11036,7 +11223,7 @@ function mintSessionId() {
|
|
|
11036
11223
|
// src/utils/sessionStore.ts
|
|
11037
11224
|
var SESSIONS_SUBDIR = "sessions";
|
|
11038
11225
|
function getSessionsDir(baseDir) {
|
|
11039
|
-
return
|
|
11226
|
+
return path14.join(getStateDir(baseDir), SESSIONS_SUBDIR);
|
|
11040
11227
|
}
|
|
11041
11228
|
var REJECTION_MESSAGE = "This session was created with an older version of Ordewell. Please re-plan.";
|
|
11042
11229
|
function hasScalarRunner(parsed) {
|
|
@@ -11071,7 +11258,7 @@ function saveSession(plan, goal, baseDir, id) {
|
|
|
11071
11258
|
plan: JSON.parse(JSON.stringify(plan))
|
|
11072
11259
|
};
|
|
11073
11260
|
const filename = sessionFilename(meta);
|
|
11074
|
-
const filePath =
|
|
11261
|
+
const filePath = path14.join(sessionsDir, filename);
|
|
11075
11262
|
fs6.writeFileSync(filePath, JSON.stringify(session, null, 2));
|
|
11076
11263
|
return meta;
|
|
11077
11264
|
}
|
|
@@ -11081,7 +11268,7 @@ function listSessions(baseDir, logger = defaultLogger) {
|
|
|
11081
11268
|
const files = fs6.readdirSync(sessionsDir).filter((f) => f.endsWith(".json"));
|
|
11082
11269
|
return files.map((f) => {
|
|
11083
11270
|
try {
|
|
11084
|
-
const raw = fs6.readFileSync(
|
|
11271
|
+
const raw = fs6.readFileSync(path14.join(sessionsDir, f), "utf-8");
|
|
11085
11272
|
const parsed = JSON.parse(raw);
|
|
11086
11273
|
if (hasScalarRunner(parsed)) {
|
|
11087
11274
|
logger.warn("sessionStore", `session file ${f}: ${REJECTION_MESSAGE}`);
|
|
@@ -11099,7 +11286,7 @@ function findSessionFile(sessionsDir, sessionId, logger) {
|
|
|
11099
11286
|
const files = fs6.readdirSync(sessionsDir).filter((f) => f.endsWith(".json"));
|
|
11100
11287
|
for (const f of files) {
|
|
11101
11288
|
try {
|
|
11102
|
-
const raw = fs6.readFileSync(
|
|
11289
|
+
const raw = fs6.readFileSync(path14.join(sessionsDir, f), "utf-8");
|
|
11103
11290
|
const session = JSON.parse(raw);
|
|
11104
11291
|
if (session.meta.id === sessionId) return f;
|
|
11105
11292
|
} catch (err) {
|
|
@@ -11114,7 +11301,7 @@ function loadSession(sessionId, baseDir, logger = defaultLogger) {
|
|
|
11114
11301
|
try {
|
|
11115
11302
|
const file = findSessionFile(sessionsDir, sessionId, logger);
|
|
11116
11303
|
if (file) {
|
|
11117
|
-
const raw = fs6.readFileSync(
|
|
11304
|
+
const raw = fs6.readFileSync(path14.join(sessionsDir, file), "utf-8");
|
|
11118
11305
|
const parsed = JSON.parse(raw);
|
|
11119
11306
|
if (hasScalarRunner(parsed)) {
|
|
11120
11307
|
logger.warn("sessionStore", `session file ${file}: ${REJECTION_MESSAGE}`);
|
|
@@ -11148,7 +11335,7 @@ function deleteSession(sessionId, baseDir, logger = defaultLogger) {
|
|
|
11148
11335
|
try {
|
|
11149
11336
|
const file = findSessionFile(sessionsDir, sessionId, logger);
|
|
11150
11337
|
if (file) {
|
|
11151
|
-
fs6.unlinkSync(
|
|
11338
|
+
fs6.unlinkSync(path14.join(sessionsDir, file));
|
|
11152
11339
|
return true;
|
|
11153
11340
|
}
|
|
11154
11341
|
} catch (err) {
|
|
@@ -11159,7 +11346,7 @@ function deleteSession(sessionId, baseDir, logger = defaultLogger) {
|
|
|
11159
11346
|
|
|
11160
11347
|
// src/utils/prdStore.ts
|
|
11161
11348
|
import * as fs7 from "fs";
|
|
11162
|
-
import * as
|
|
11349
|
+
import * as path15 from "path";
|
|
11163
11350
|
var PRD_BLOCK_RE = /<!--\s*ORDEWELL_PRD_START\s+slug="([^"]+)"\s*-->\s*([\s\S]*?)\s*<!--\s*ORDEWELL_PRD_END\s*-->/;
|
|
11164
11351
|
function extractPrdBlock(text) {
|
|
11165
11352
|
const match = PRD_BLOCK_RE.exec(text);
|
|
@@ -11173,9 +11360,9 @@ function sanitizeSlug(raw) {
|
|
|
11173
11360
|
return raw.toLowerCase().replace(/[^a-z0-9-_]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
11174
11361
|
}
|
|
11175
11362
|
function savePrdMarkdown(workspace, slug2, markdown) {
|
|
11176
|
-
const dir =
|
|
11363
|
+
const dir = path15.join(workspace, ".scratch", sanitizeSlug(slug2));
|
|
11177
11364
|
fs7.mkdirSync(dir, { recursive: true });
|
|
11178
|
-
const file =
|
|
11365
|
+
const file = path15.join(dir, "PRD.md");
|
|
11179
11366
|
fs7.writeFileSync(file, markdown.endsWith("\n") ? markdown : markdown + "\n", "utf8");
|
|
11180
11367
|
return file;
|
|
11181
11368
|
}
|
|
@@ -12829,8 +13016,8 @@ var HeadlessRunner = class extends AbstractRunner {
|
|
|
12829
13016
|
import { execFile as execFile2 } from "child_process";
|
|
12830
13017
|
import { promisify as promisify4 } from "util";
|
|
12831
13018
|
import { tmpdir } from "os";
|
|
12832
|
-
import { join as
|
|
12833
|
-
import { existsSync as
|
|
13019
|
+
import { join as join14 } from "path";
|
|
13020
|
+
import { existsSync as existsSync9, readFileSync as readFileSync6, unlinkSync as unlinkSync2, writeFileSync as writeFileSync6 } from "fs";
|
|
12834
13021
|
|
|
12835
13022
|
// src/utils/tmux.ts
|
|
12836
13023
|
import { execSync as execSync2 } from "child_process";
|
|
@@ -12937,7 +13124,7 @@ var TmuxSession = class extends AbstractTerminalSession {
|
|
|
12937
13124
|
if (this.exited) return;
|
|
12938
13125
|
let content;
|
|
12939
13126
|
try {
|
|
12940
|
-
content =
|
|
13127
|
+
content = existsSync9(this.logPath) ? readFileSync6(this.logPath, "utf8") : "";
|
|
12941
13128
|
} catch {
|
|
12942
13129
|
return;
|
|
12943
13130
|
}
|
|
@@ -13116,7 +13303,7 @@ var TmuxRunner = class extends AbstractRunner {
|
|
|
13116
13303
|
windowName,
|
|
13117
13304
|
this.execFileImpl,
|
|
13118
13305
|
this.pollIntervalMs,
|
|
13119
|
-
|
|
13306
|
+
join14(this.logDir, `${id}.log`),
|
|
13120
13307
|
this.socket
|
|
13121
13308
|
);
|
|
13122
13309
|
invocation.env = { ...invocation.env, PATH: await this.resolvePath() };
|
|
@@ -13129,8 +13316,8 @@ var TmuxRunner = class extends AbstractRunner {
|
|
|
13129
13316
|
|
|
13130
13317
|
// src/utils/daemonToken.ts
|
|
13131
13318
|
import { randomBytes as randomBytes2, timingSafeEqual } from "crypto";
|
|
13132
|
-
import { closeSync, mkdirSync as mkdirSync7, openSync, readFileSync as
|
|
13133
|
-
import { join as
|
|
13319
|
+
import { closeSync, mkdirSync as mkdirSync7, openSync, readFileSync as readFileSync7, unlinkSync as unlinkSync3, writeSync } from "fs";
|
|
13320
|
+
import { join as join15 } from "path";
|
|
13134
13321
|
var BEARER_PREFIX = "bearer ";
|
|
13135
13322
|
var DAEMON_TOKEN_SUBPROTOCOL_PREFIX = "ordewell.token.";
|
|
13136
13323
|
var DAEMON_SUBPROTOCOL = "ordewell.v1";
|
|
@@ -13138,7 +13325,7 @@ function configDir() {
|
|
|
13138
13325
|
return globalDataDir();
|
|
13139
13326
|
}
|
|
13140
13327
|
function daemonTokenPath(port) {
|
|
13141
|
-
return
|
|
13328
|
+
return join15(configDir(), `server-${port}.token`);
|
|
13142
13329
|
}
|
|
13143
13330
|
function mintDaemonToken(port) {
|
|
13144
13331
|
const token = randomBytes2(32).toString("base64url");
|
|
@@ -13158,7 +13345,7 @@ function mintDaemonToken(port) {
|
|
|
13158
13345
|
}
|
|
13159
13346
|
function readDaemonToken(port) {
|
|
13160
13347
|
try {
|
|
13161
|
-
const token =
|
|
13348
|
+
const token = readFileSync7(daemonTokenPath(port), "utf8").trim();
|
|
13162
13349
|
return token === "" ? void 0 : token;
|
|
13163
13350
|
} catch {
|
|
13164
13351
|
return void 0;
|
|
@@ -13200,17 +13387,17 @@ function tokensMatch(presented, expected) {
|
|
|
13200
13387
|
|
|
13201
13388
|
// src/plugins/RunnerRegistry.ts
|
|
13202
13389
|
import * as fs9 from "fs";
|
|
13203
|
-
import * as
|
|
13204
|
-
import * as
|
|
13390
|
+
import * as path18 from "path";
|
|
13391
|
+
import * as os5 from "os";
|
|
13205
13392
|
import { execFileSync } from "child_process";
|
|
13206
13393
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
13207
13394
|
|
|
13208
13395
|
// src/plugins/FsPluginStore.ts
|
|
13209
13396
|
import * as fs8 from "fs";
|
|
13210
|
-
import * as
|
|
13397
|
+
import * as path17 from "path";
|
|
13211
13398
|
|
|
13212
13399
|
// src/plugins/pluginNames.ts
|
|
13213
|
-
import * as
|
|
13400
|
+
import * as path16 from "path";
|
|
13214
13401
|
var PLUGIN_NAME_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
|
|
13215
13402
|
var MAX_PLUGIN_NAME_LENGTH = 64;
|
|
13216
13403
|
function isPlainPluginName(name) {
|
|
@@ -13225,10 +13412,10 @@ function assertPlainPluginName(name) {
|
|
|
13225
13412
|
}
|
|
13226
13413
|
function resolvePluginInstallDir(pluginsDir, name) {
|
|
13227
13414
|
assertPlainPluginName(name);
|
|
13228
|
-
const root =
|
|
13229
|
-
const dest =
|
|
13230
|
-
const relative3 =
|
|
13231
|
-
if (relative3 !== name || relative3 === "" ||
|
|
13415
|
+
const root = path16.resolve(pluginsDir);
|
|
13416
|
+
const dest = path16.resolve(root, name);
|
|
13417
|
+
const relative3 = path16.relative(root, dest);
|
|
13418
|
+
if (relative3 !== name || relative3 === "" || path16.isAbsolute(relative3)) {
|
|
13232
13419
|
throw new Error(`Plugin install path escapes the plugins directory: ${JSON.stringify(name)}`);
|
|
13233
13420
|
}
|
|
13234
13421
|
return dest;
|
|
@@ -13243,10 +13430,10 @@ function isValidManifest(obj) {
|
|
|
13243
13430
|
|
|
13244
13431
|
// src/plugins/FsPluginStore.ts
|
|
13245
13432
|
function userPluginsDir() {
|
|
13246
|
-
return
|
|
13433
|
+
return path17.join(globalDataDir(), "plugins");
|
|
13247
13434
|
}
|
|
13248
13435
|
function loadManifestFromDir(dir) {
|
|
13249
|
-
const manifestPath =
|
|
13436
|
+
const manifestPath = path17.join(dir, "manifest.json");
|
|
13250
13437
|
if (!fs8.existsSync(manifestPath)) return null;
|
|
13251
13438
|
try {
|
|
13252
13439
|
const raw = fs8.readFileSync(manifestPath, "utf8");
|
|
@@ -13261,8 +13448,8 @@ function copyDirSync3(src, dest) {
|
|
|
13261
13448
|
ensureDir(dest);
|
|
13262
13449
|
const entries = fs8.readdirSync(src, { withFileTypes: true });
|
|
13263
13450
|
for (const entry of entries) {
|
|
13264
|
-
const srcPath =
|
|
13265
|
-
const destPath =
|
|
13451
|
+
const srcPath = path17.join(src, entry.name);
|
|
13452
|
+
const destPath = path17.join(dest, entry.name);
|
|
13266
13453
|
if (entry.isDirectory()) {
|
|
13267
13454
|
copyDirSync3(srcPath, destPath);
|
|
13268
13455
|
} else {
|
|
@@ -13274,7 +13461,7 @@ function rmDirSync(dir) {
|
|
|
13274
13461
|
if (!fs8.existsSync(dir)) return;
|
|
13275
13462
|
const entries = fs8.readdirSync(dir, { withFileTypes: true });
|
|
13276
13463
|
for (const entry of entries) {
|
|
13277
|
-
const p =
|
|
13464
|
+
const p = path17.join(dir, entry.name);
|
|
13278
13465
|
if (entry.isDirectory()) {
|
|
13279
13466
|
rmDirSync(p);
|
|
13280
13467
|
} else {
|
|
@@ -13327,11 +13514,11 @@ var FsPluginStore = class {
|
|
|
13327
13514
|
return null;
|
|
13328
13515
|
}
|
|
13329
13516
|
}
|
|
13330
|
-
dirExists(
|
|
13331
|
-
return fs8.existsSync(
|
|
13517
|
+
dirExists(path21) {
|
|
13518
|
+
return fs8.existsSync(path21) && fs8.statSync(path21).isDirectory();
|
|
13332
13519
|
}
|
|
13333
|
-
exists(
|
|
13334
|
-
return fs8.existsSync(
|
|
13520
|
+
exists(path21) {
|
|
13521
|
+
return fs8.existsSync(path21);
|
|
13335
13522
|
}
|
|
13336
13523
|
};
|
|
13337
13524
|
|
|
@@ -13763,7 +13950,7 @@ var RunnerRegistry = class {
|
|
|
13763
13950
|
return entry?.source === "builtin";
|
|
13764
13951
|
}
|
|
13765
13952
|
installFromPath(sourcePath) {
|
|
13766
|
-
const absPath =
|
|
13953
|
+
const absPath = path18.resolve(sourcePath);
|
|
13767
13954
|
if (!this.store.dirExists(absPath)) {
|
|
13768
13955
|
throw new Error(`Plugin source must be a directory: ${absPath}`);
|
|
13769
13956
|
}
|
|
@@ -13775,7 +13962,7 @@ var RunnerRegistry = class {
|
|
|
13775
13962
|
}
|
|
13776
13963
|
installFromGit(url) {
|
|
13777
13964
|
const validated = assertInstallablePluginUrl(url);
|
|
13778
|
-
const tmpDir =
|
|
13965
|
+
const tmpDir = path18.join(os5.tmpdir(), `ordewell-plugin-${randomBytes3(12).toString("hex")}`);
|
|
13779
13966
|
this.store.ensureDir(tmpDir);
|
|
13780
13967
|
try {
|
|
13781
13968
|
try {
|
|
@@ -13788,7 +13975,7 @@ var RunnerRegistry = class {
|
|
|
13788
13975
|
const hasManifest = contents.some((f) => f === "manifest.json");
|
|
13789
13976
|
let sourceDir = tmpDir;
|
|
13790
13977
|
if (!hasManifest) {
|
|
13791
|
-
const onlyEntry = contents.length === 1 ?
|
|
13978
|
+
const onlyEntry = contents.length === 1 ? path18.join(tmpDir, contents[0]) : void 0;
|
|
13792
13979
|
if (!onlyEntry || !this.store.dirExists(onlyEntry)) {
|
|
13793
13980
|
throw new Error(`No manifest.json found in repository: ${validated.toString()}`);
|
|
13794
13981
|
}
|
|
@@ -13836,7 +14023,7 @@ var RunnerRegistry = class {
|
|
|
13836
14023
|
}
|
|
13837
14024
|
createSkeleton(name, outputDir) {
|
|
13838
14025
|
assertPlainPluginName(name);
|
|
13839
|
-
const dir =
|
|
14026
|
+
const dir = path18.resolve(outputDir, name);
|
|
13840
14027
|
this.store.ensureDir(dir);
|
|
13841
14028
|
const manifest = {
|
|
13842
14029
|
name,
|
|
@@ -13868,8 +14055,8 @@ var RunnerRegistry = class {
|
|
|
13868
14055
|
]
|
|
13869
14056
|
}
|
|
13870
14057
|
};
|
|
13871
|
-
this.store.writeFile(
|
|
13872
|
-
const runSh =
|
|
14058
|
+
this.store.writeFile(path18.join(dir, "manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
|
|
14059
|
+
const runSh = path18.join(dir, "run.sh");
|
|
13873
14060
|
const scriptContent = `#!/usr/bin/env bash
|
|
13874
14061
|
# Custom runner script for ${name}
|
|
13875
14062
|
# Receives:
|
|
@@ -13902,14 +14089,14 @@ function fsChmodSync(fpath, mode) {
|
|
|
13902
14089
|
|
|
13903
14090
|
// src/utils/stateStore.ts
|
|
13904
14091
|
import * as fs10 from "fs";
|
|
13905
|
-
import * as
|
|
14092
|
+
import * as path19 from "path";
|
|
13906
14093
|
var STATE_FILE = "state.json";
|
|
13907
14094
|
function getStatePath(baseDir) {
|
|
13908
|
-
return
|
|
14095
|
+
return path19.join(getStateDir(baseDir), STATE_FILE);
|
|
13909
14096
|
}
|
|
13910
14097
|
function saveState(plan, baseDir) {
|
|
13911
14098
|
const statePath = getStatePath(baseDir ?? process.cwd());
|
|
13912
|
-
ensureDir(
|
|
14099
|
+
ensureDir(path19.dirname(statePath));
|
|
13913
14100
|
plan.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
|
|
13914
14101
|
fs10.writeFileSync(statePath, JSON.stringify(plan, null, 2));
|
|
13915
14102
|
}
|
|
@@ -13942,7 +14129,7 @@ function stateExists(baseDir) {
|
|
|
13942
14129
|
|
|
13943
14130
|
// src/services/SettingsService.ts
|
|
13944
14131
|
import * as fs11 from "fs";
|
|
13945
|
-
import * as
|
|
14132
|
+
import * as path20 from "path";
|
|
13946
14133
|
var DEFAULTS = {
|
|
13947
14134
|
tdd: { enabled: true },
|
|
13948
14135
|
verification: { enabled: false }
|
|
@@ -13950,7 +14137,7 @@ var DEFAULTS = {
|
|
|
13950
14137
|
function getSettingsPath() {
|
|
13951
14138
|
const override = process.env.ORDEWELL_SETTINGS_PATH;
|
|
13952
14139
|
if (override && override.trim()) return override.trim();
|
|
13953
|
-
return
|
|
14140
|
+
return path20.join(globalDataDir(), "settings.json");
|
|
13954
14141
|
}
|
|
13955
14142
|
function readPlannerModels(raw) {
|
|
13956
14143
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
@@ -14078,7 +14265,7 @@ var SettingsService = class {
|
|
|
14078
14265
|
return { ...DEFAULTS, tdd: { ...DEFAULTS.tdd }, verification: { ...DEFAULTS.verification } };
|
|
14079
14266
|
}
|
|
14080
14267
|
persist() {
|
|
14081
|
-
const dir =
|
|
14268
|
+
const dir = path20.dirname(this.filePath);
|
|
14082
14269
|
if (!fs11.existsSync(dir)) {
|
|
14083
14270
|
fs11.mkdirSync(dir, { recursive: true });
|
|
14084
14271
|
}
|