@ordewell/core 0.4.7 → 0.4.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ITerminalRunner-fynILAiR.d.mts → ITerminalRunner-1NAv8wCC.d.mts} +15 -3
- package/dist/{ITerminalRunner-Cpyzyrnl.d.ts → ITerminalRunner-CbE6gKLI.d.ts} +15 -3
- package/dist/index.d.mts +219 -3
- package/dist/index.d.ts +219 -3
- package/dist/index.js +619 -124
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +594 -126
- 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.mjs
CHANGED
|
@@ -108,7 +108,6 @@ var AUTO_COMMANDS = [
|
|
|
108
108
|
"pwd",
|
|
109
109
|
"which",
|
|
110
110
|
"type",
|
|
111
|
-
"env",
|
|
112
111
|
"uname",
|
|
113
112
|
"whoami",
|
|
114
113
|
"cut",
|
|
@@ -309,6 +308,52 @@ var MULTIPLEXERS = [
|
|
|
309
308
|
"flutter",
|
|
310
309
|
"dart"
|
|
311
310
|
];
|
|
311
|
+
var HELP_FLAGS = ["--help", "--version"];
|
|
312
|
+
var WRAPPER_FAMILY = {
|
|
313
|
+
env: {
|
|
314
|
+
valueFlags: ["-u", "--unset", "-C", "--chdir"],
|
|
315
|
+
booleanFlags: [
|
|
316
|
+
"-i",
|
|
317
|
+
"--ignore-environment",
|
|
318
|
+
"-0",
|
|
319
|
+
"--null",
|
|
320
|
+
"-v",
|
|
321
|
+
"--debug",
|
|
322
|
+
// Optional-value flags: see WrapperSpec.booleanFlags.
|
|
323
|
+
"--block-signal",
|
|
324
|
+
"--default-signal",
|
|
325
|
+
"--ignore-signal",
|
|
326
|
+
"--list-signal-handling",
|
|
327
|
+
...HELP_FLAGS
|
|
328
|
+
],
|
|
329
|
+
stringFlags: ["-S", "--split-string"],
|
|
330
|
+
acceptsAssignments: true
|
|
331
|
+
},
|
|
332
|
+
nice: {
|
|
333
|
+
valueFlags: ["-n", "--adjustment"],
|
|
334
|
+
booleanFlags: HELP_FLAGS,
|
|
335
|
+
booleanPattern: /^-\d+$/
|
|
336
|
+
},
|
|
337
|
+
timeout: {
|
|
338
|
+
valueFlags: ["-s", "--signal", "-k", "--kill-after"],
|
|
339
|
+
booleanFlags: ["--preserve-status", "--foreground", "-v", "--verbose", ...HELP_FLAGS],
|
|
340
|
+
positionals: 1
|
|
341
|
+
},
|
|
342
|
+
nohup: { booleanFlags: HELP_FLAGS },
|
|
343
|
+
setsid: { booleanFlags: ["-c", "--ctty", "-f", "--fork", "-w", "--wait", "-h", "-V", ...HELP_FLAGS] },
|
|
344
|
+
stdbuf: {
|
|
345
|
+
valueFlags: ["-i", "--input", "-o", "--output", "-e", "--error"],
|
|
346
|
+
booleanFlags: HELP_FLAGS
|
|
347
|
+
},
|
|
348
|
+
ionice: {
|
|
349
|
+
valueFlags: ["-c", "--class", "-n", "--classdata", "-p", "--pid", "-P", "--pgid", "-u", "--uid"],
|
|
350
|
+
booleanFlags: ["-t", "--ignore", "-h", "-V", ...HELP_FLAGS]
|
|
351
|
+
},
|
|
352
|
+
// The multi-call binary ships its own `rm`, `mv` and `sh`, so the refused
|
|
353
|
+
// name arrives as its first argument.
|
|
354
|
+
busybox: { booleanFlags: ["--list", "--install", ...HELP_FLAGS] },
|
|
355
|
+
command: { booleanFlags: ["-p"], noExecFlags: ["-v", "-V"] }
|
|
356
|
+
};
|
|
312
357
|
var POSIX_DIALECT = {
|
|
313
358
|
escape: "\\",
|
|
314
359
|
escapeInQuotes: true,
|
|
@@ -523,10 +568,92 @@ function binaryName(token, dialect) {
|
|
|
523
568
|
if (dot <= 0) return base;
|
|
524
569
|
return dialect.strippedExtensions.includes(base.slice(dot).toLowerCase()) ? base.slice(0, dot) : base;
|
|
525
570
|
}
|
|
571
|
+
var ASSIGNMENT = /^[A-Za-z_][A-Za-z0-9_]*=/;
|
|
526
572
|
function toSegment(tokens, piped, dialect) {
|
|
527
573
|
const rest = [...tokens];
|
|
528
|
-
|
|
529
|
-
|
|
574
|
+
const assignments = [];
|
|
575
|
+
while (rest.length > 0 && ASSIGNMENT.test(rest[0])) assignments.push(rest.shift());
|
|
576
|
+
return {
|
|
577
|
+
binary: rest.length > 0 ? binaryName(rest[0], dialect) : "",
|
|
578
|
+
args: rest.slice(1),
|
|
579
|
+
assignments,
|
|
580
|
+
piped,
|
|
581
|
+
expandable: false
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
function joinedShortFlag(list, token) {
|
|
585
|
+
if (token.length <= 2) return void 0;
|
|
586
|
+
return list.find((f) => f.length === 2 && token.startsWith(f));
|
|
587
|
+
}
|
|
588
|
+
function scanWrapperArgs(binary, spec, args) {
|
|
589
|
+
const valueFlags = spec.valueFlags ?? [];
|
|
590
|
+
const stringFlags = spec.stringFlags ?? [];
|
|
591
|
+
const assignments = [];
|
|
592
|
+
let positionals = spec.positionals ?? 0;
|
|
593
|
+
let i = 0;
|
|
594
|
+
while (i < args.length) {
|
|
595
|
+
const token = args[i];
|
|
596
|
+
if (token === "--") {
|
|
597
|
+
i++;
|
|
598
|
+
break;
|
|
599
|
+
}
|
|
600
|
+
if (/^-./.test(token)) {
|
|
601
|
+
const eq = token.startsWith("--") ? token.indexOf("=") : -1;
|
|
602
|
+
const name = eq > 0 ? token.slice(0, eq) : token;
|
|
603
|
+
const selfContained = eq > 0;
|
|
604
|
+
if ((spec.noExecFlags ?? []).includes(name)) return { kind: "no-exec" };
|
|
605
|
+
if (stringFlags.includes(name) || joinedShortFlag(stringFlags, token)) {
|
|
606
|
+
return {
|
|
607
|
+
kind: "refuse",
|
|
608
|
+
reason: `"${binary} ${name}" splits a string into a command, which this classifier cannot inspect. Use the read-only research tools, or describe it as a task.`
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
if ((spec.booleanFlags ?? []).includes(name) || spec.booleanPattern?.test(token)) {
|
|
612
|
+
i++;
|
|
613
|
+
continue;
|
|
614
|
+
}
|
|
615
|
+
if (valueFlags.includes(name)) {
|
|
616
|
+
i += selfContained ? 1 : 2;
|
|
617
|
+
continue;
|
|
618
|
+
}
|
|
619
|
+
if (joinedShortFlag(valueFlags, token)) {
|
|
620
|
+
i++;
|
|
621
|
+
continue;
|
|
622
|
+
}
|
|
623
|
+
return {
|
|
624
|
+
kind: "refuse",
|
|
625
|
+
reason: `"${token}" is not a flag this classifier knows on the wrapper "${binary}", so it cannot tell which command "${binary}" would actually run. Re-run without it.`
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
if (spec.acceptsAssignments && ASSIGNMENT.test(token)) {
|
|
629
|
+
assignments.push(token);
|
|
630
|
+
i++;
|
|
631
|
+
continue;
|
|
632
|
+
}
|
|
633
|
+
if (positionals > 0) {
|
|
634
|
+
positionals--;
|
|
635
|
+
i++;
|
|
636
|
+
continue;
|
|
637
|
+
}
|
|
638
|
+
break;
|
|
639
|
+
}
|
|
640
|
+
return { kind: "command", tokens: args.slice(i), assignments };
|
|
641
|
+
}
|
|
642
|
+
function unwrap(seg, dialect) {
|
|
643
|
+
const wrappers = [];
|
|
644
|
+
const assignments = [...seg.assignments];
|
|
645
|
+
let current = seg;
|
|
646
|
+
while (WRAPPER_FAMILY[current.binary]) {
|
|
647
|
+
const scan = scanWrapperArgs(current.binary, WRAPPER_FAMILY[current.binary], current.args);
|
|
648
|
+
if (scan.kind === "refuse") return { seg: { ...current, assignments }, wrappers, reason: scan.reason };
|
|
649
|
+
if (scan.kind === "no-exec" || scan.tokens.length === 0) break;
|
|
650
|
+
assignments.push(...scan.assignments);
|
|
651
|
+
wrappers.push(current.binary);
|
|
652
|
+
const inner = toSegment(scan.tokens, current.piped, dialect);
|
|
653
|
+
assignments.push(...inner.assignments);
|
|
654
|
+
current = { ...inner, assignments: [], expandable: current.expandable };
|
|
655
|
+
}
|
|
656
|
+
return { seg: { ...current, assignments }, wrappers };
|
|
530
657
|
}
|
|
531
658
|
function lexAll(command, dialect) {
|
|
532
659
|
const queue = [];
|
|
@@ -589,6 +716,16 @@ function refusalFor(seg) {
|
|
|
589
716
|
return `"git ${sub} ${flag}" mutates refs. You are a read-only planner \u2014 describe the change as a task instead.`;
|
|
590
717
|
}
|
|
591
718
|
}
|
|
719
|
+
const execPathFlag = seg.args.find((a) => a === "--exec-path" || a.startsWith("--exec-path="));
|
|
720
|
+
if (execPathFlag) {
|
|
721
|
+
return `"git ${execPathFlag}" redirects where git looks for its helper programs, and can make it run an arbitrary one. Use the read-only research tools, or describe the change as a task.`;
|
|
722
|
+
}
|
|
723
|
+
if (sub === "grep") {
|
|
724
|
+
const pagerFlag = seg.args.find((a) => a === "-O" || a === "--open-files-in-pager" || a.startsWith("--open-files-in-pager="));
|
|
725
|
+
if (pagerFlag) {
|
|
726
|
+
return `"git grep ${pagerFlag}" opens the results in an arbitrary named program. Use the read-only research tools, or describe the change as a task.`;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
592
729
|
}
|
|
593
730
|
if (seg.binary === "find") {
|
|
594
731
|
const flag = seg.args.find((a) => ["-exec", "-execdir", "-ok", "-okdir", "-delete"].includes(a));
|
|
@@ -611,8 +748,17 @@ function refusalFor(seg) {
|
|
|
611
748
|
return `Inline code via "${seg.binary} ${seg.args.find(isInlineCodeFlag)}" is not available to the planner. Use the read-only research tools, or describe it as a task.`;
|
|
612
749
|
}
|
|
613
750
|
}
|
|
751
|
+
if (seg.assignments.length > 0) {
|
|
752
|
+
return `The environment assignment "${seg.assignments[0]}" decides what "${seg.binary}" actually does, and this classifier cannot judge the value. Re-run the command without the assignment.`;
|
|
753
|
+
}
|
|
614
754
|
return void 0;
|
|
615
755
|
}
|
|
756
|
+
function withWrapperNote(reason, wrappers) {
|
|
757
|
+
if (wrappers.length === 0) return reason;
|
|
758
|
+
const quoted = wrappers.map((w) => `"${w}"`);
|
|
759
|
+
const names = quoted.length > 1 ? `${quoted.slice(0, -1).join(", ")} and ${quoted[quoted.length - 1]}` : quoted[0];
|
|
760
|
+
return `${reason} Wrapping it in ${names} does not change what runs.`;
|
|
761
|
+
}
|
|
616
762
|
function classifyCommand(command, opts = {}) {
|
|
617
763
|
const trimmed = command.trim();
|
|
618
764
|
if (!trimmed) return { tier: "refuse", scope: "", reason: "Empty command." };
|
|
@@ -641,11 +787,13 @@ function classifyCommand(command, opts = {}) {
|
|
|
641
787
|
};
|
|
642
788
|
}
|
|
643
789
|
if (segments.length === 0) return { tier: "refuse", scope: "", reason: "No command found." };
|
|
644
|
-
|
|
790
|
+
const unwrapped = segments.map((seg) => unwrap(seg, dialect));
|
|
791
|
+
for (const { seg, wrappers, reason: wrapperReason } of unwrapped) {
|
|
792
|
+
if (wrapperReason) return { tier: "refuse", scope: "", reason: wrapperReason };
|
|
645
793
|
const reason = refusalFor(seg);
|
|
646
|
-
if (reason) return { tier: "refuse", scope: "", reason };
|
|
794
|
+
if (reason) return { tier: "refuse", scope: "", reason: withWrapperNote(reason, wrappers) };
|
|
647
795
|
}
|
|
648
|
-
const nonAuto =
|
|
796
|
+
const nonAuto = unwrapped.map((u) => u.seg).filter((s) => !isAuto(s));
|
|
649
797
|
if (nonAuto.length === 0) return { tier: "auto", scope: "" };
|
|
650
798
|
const scope = [...new Set(nonAuto.map(scopeFor))].sort().join(" + ");
|
|
651
799
|
return { tier: "ask", scope };
|
|
@@ -1144,14 +1292,14 @@ var PendingApprovals = class {
|
|
|
1144
1292
|
ask(request) {
|
|
1145
1293
|
const id = `ap-${Date.now()}-${counter++}`;
|
|
1146
1294
|
const pending = { id, request, createdAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
1147
|
-
return new Promise((
|
|
1295
|
+
return new Promise((resolve4) => {
|
|
1148
1296
|
const settle = (granted) => {
|
|
1149
1297
|
const entry = this.entries.get(id);
|
|
1150
1298
|
if (!entry) return;
|
|
1151
1299
|
clearTimeout(entry.timer);
|
|
1152
1300
|
this.entries.delete(id);
|
|
1153
1301
|
this.opts.onSettled?.(id, granted);
|
|
1154
|
-
|
|
1302
|
+
resolve4(granted);
|
|
1155
1303
|
};
|
|
1156
1304
|
const timer = setTimeout(() => settle(false), this.opts.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
1157
1305
|
timer.unref?.();
|
|
@@ -5791,28 +5939,28 @@ function posixBinDirs() {
|
|
|
5791
5939
|
];
|
|
5792
5940
|
}
|
|
5793
5941
|
function windowsBinDirs(env, home) {
|
|
5794
|
-
const
|
|
5795
|
-
const under = (base, ...parts) => base ? [
|
|
5942
|
+
const join16 = (...parts) => path5.win32.join(...parts);
|
|
5943
|
+
const under = (base, ...parts) => base ? [join16(base, ...parts)] : [];
|
|
5796
5944
|
const appData = env.APPDATA;
|
|
5797
5945
|
const localAppData = env.LOCALAPPDATA;
|
|
5798
5946
|
const programData = env.ProgramData;
|
|
5799
5947
|
return [
|
|
5800
5948
|
// Native per-user installers, PowerShell-driven and otherwise.
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5949
|
+
join16(home, ".local", "bin"),
|
|
5950
|
+
join16(home, ".opencode", "bin"),
|
|
5951
|
+
join16(home, ".claude", "bin"),
|
|
5952
|
+
join16(home, ".codex", "bin"),
|
|
5805
5953
|
...under(localAppData, "Programs", "claude"),
|
|
5806
5954
|
// Node package managers. npm's global prefix is `%APPDATA%\npm`; the
|
|
5807
5955
|
// literal spelling is kept as a fallback for a host that does not export
|
|
5808
5956
|
// APPDATA (a service account, a stripped CI container).
|
|
5809
5957
|
...under(appData, "npm"),
|
|
5810
|
-
|
|
5958
|
+
join16(home, "AppData", "Roaming", "npm"),
|
|
5811
5959
|
...under(localAppData, "pnpm"),
|
|
5812
5960
|
...under(localAppData, "Yarn", "bin"),
|
|
5813
|
-
|
|
5961
|
+
join16(home, ".bun", "bin"),
|
|
5814
5962
|
// Windows package managers.
|
|
5815
|
-
|
|
5963
|
+
join16(home, "scoop", "shims"),
|
|
5816
5964
|
...under(env.SCOOP, "shims"),
|
|
5817
5965
|
...under(env.SCOOP_GLOBAL ?? programData, "scoop", "shims"),
|
|
5818
5966
|
...under(programData, "chocolatey", "bin"),
|
|
@@ -5822,7 +5970,7 @@ function windowsBinDirs(env, home) {
|
|
|
5822
5970
|
...under(localAppData, "Microsoft", "WindowsApps"),
|
|
5823
5971
|
// Version managers. Volta's Windows home is not the POSIX `~/.volta`.
|
|
5824
5972
|
...under(localAppData, "Volta", "bin"),
|
|
5825
|
-
|
|
5973
|
+
join16(home, ".volta", "bin")
|
|
5826
5974
|
];
|
|
5827
5975
|
}
|
|
5828
5976
|
function wellKnownBinDirs(deps = {}) {
|
|
@@ -6123,7 +6271,7 @@ var defaultAppServerClient = async (command, args, options) => {
|
|
|
6123
6271
|
const PATH = await augmentedPath();
|
|
6124
6272
|
const launch = await planDirectLaunch(command, args).catch(() => null);
|
|
6125
6273
|
if (!launch) return null;
|
|
6126
|
-
return new Promise((
|
|
6274
|
+
return new Promise((resolve4) => {
|
|
6127
6275
|
let child;
|
|
6128
6276
|
try {
|
|
6129
6277
|
child = spawn(launch.file, launch.args, {
|
|
@@ -6132,7 +6280,7 @@ var defaultAppServerClient = async (command, args, options) => {
|
|
|
6132
6280
|
windowsVerbatimArguments: launch.verbatim
|
|
6133
6281
|
});
|
|
6134
6282
|
} catch {
|
|
6135
|
-
|
|
6283
|
+
resolve4(null);
|
|
6136
6284
|
return;
|
|
6137
6285
|
}
|
|
6138
6286
|
let settled = false;
|
|
@@ -6141,7 +6289,7 @@ var defaultAppServerClient = async (command, args, options) => {
|
|
|
6141
6289
|
settled = true;
|
|
6142
6290
|
clearTimeout(timer);
|
|
6143
6291
|
killTree(child);
|
|
6144
|
-
|
|
6292
|
+
resolve4(value);
|
|
6145
6293
|
};
|
|
6146
6294
|
const timer = setTimeout(() => finish(null), options?.timeout ?? 2e4);
|
|
6147
6295
|
child.on("error", () => finish(null));
|
|
@@ -7181,11 +7329,71 @@ var RunnerInstallation = class {
|
|
|
7181
7329
|
}
|
|
7182
7330
|
};
|
|
7183
7331
|
|
|
7332
|
+
// src/services/settingsEnvAllowlist.ts
|
|
7333
|
+
var ORDEWELL_SETTABLE_ENV = [
|
|
7334
|
+
"AI_PROVIDER",
|
|
7335
|
+
"ORCHESTRATOR_MODEL",
|
|
7336
|
+
"ORDEWELL_SUBAGENT_MODEL",
|
|
7337
|
+
"ORDEWELL_PLANNER_EFFORT",
|
|
7338
|
+
"ORDEWELL_RESEARCH_ENABLED",
|
|
7339
|
+
"ORDEWELL_MAX_PARALLEL"
|
|
7340
|
+
];
|
|
7341
|
+
var SETTINGS_ENV_REFUSED = [
|
|
7342
|
+
// Approval posture and pre-approved scope.
|
|
7343
|
+
"ORDEWELL_AUTONOMOUS_MODE",
|
|
7344
|
+
"ORDEWELL_APPROVAL_MODE",
|
|
7345
|
+
"ORDEWELL_APPROVAL_ALLOW",
|
|
7346
|
+
// Where settings are persisted.
|
|
7347
|
+
"ORDEWELL_SETTINGS_PATH",
|
|
7348
|
+
// Runtime options and dynamic loaders.
|
|
7349
|
+
"NODE_OPTIONS",
|
|
7350
|
+
"NODE_REPL_EXTERNAL_MODULE",
|
|
7351
|
+
"NODE_PATH",
|
|
7352
|
+
"ELECTRON_RUN_AS_NODE",
|
|
7353
|
+
"LD_PRELOAD",
|
|
7354
|
+
"LD_LIBRARY_PATH",
|
|
7355
|
+
"LD_AUDIT",
|
|
7356
|
+
"DYLD_INSERT_LIBRARIES",
|
|
7357
|
+
"DYLD_LIBRARY_PATH",
|
|
7358
|
+
"DYLD_FRAMEWORK_PATH",
|
|
7359
|
+
// Executable resolution.
|
|
7360
|
+
"PATH",
|
|
7361
|
+
"PATHEXT",
|
|
7362
|
+
"NODE"
|
|
7363
|
+
];
|
|
7364
|
+
var REFUSED = new Set(SETTINGS_ENV_REFUSED);
|
|
7365
|
+
function providerEnvKeys() {
|
|
7366
|
+
const keys = [];
|
|
7367
|
+
for (const meta of Object.values(ALL_PROVIDERS)) {
|
|
7368
|
+
if (meta.apiKeyEnvVar) keys.push(meta.apiKeyEnvVar);
|
|
7369
|
+
if (meta.baseUrlEnvVar) keys.push(meta.baseUrlEnvVar);
|
|
7370
|
+
for (const detect of meta.detectEnvVars) keys.push(detect);
|
|
7371
|
+
}
|
|
7372
|
+
return keys;
|
|
7373
|
+
}
|
|
7374
|
+
var PROVIDER_CREDENTIAL_ENV = new Set(providerEnvKeys());
|
|
7375
|
+
var SETTINGS_ENV_ALLOWLIST = new Set(
|
|
7376
|
+
[...providerEnvKeys(), ...ORDEWELL_SETTABLE_ENV].filter((key) => !REFUSED.has(key))
|
|
7377
|
+
);
|
|
7378
|
+
function admitSettingsEnv(env) {
|
|
7379
|
+
const accepted = {};
|
|
7380
|
+
const rejected = [];
|
|
7381
|
+
for (const [key, value] of Object.entries(env)) {
|
|
7382
|
+
if (REFUSED.has(key) || !SETTINGS_ENV_ALLOWLIST.has(key) || typeof value !== "string") {
|
|
7383
|
+
rejected.push(key);
|
|
7384
|
+
continue;
|
|
7385
|
+
}
|
|
7386
|
+
accepted[key] = value;
|
|
7387
|
+
}
|
|
7388
|
+
return { accepted, rejected };
|
|
7389
|
+
}
|
|
7390
|
+
|
|
7184
7391
|
// src/services/harness/CliAgentAiService.ts
|
|
7185
7392
|
import { spawn as nodeSpawn } from "child_process";
|
|
7186
7393
|
|
|
7187
7394
|
// src/utils/workspace.ts
|
|
7188
7395
|
import * as fs3 from "fs";
|
|
7396
|
+
import * as path9 from "path";
|
|
7189
7397
|
var WorkspaceNotFoundError = class extends Error {
|
|
7190
7398
|
constructor(workspace) {
|
|
7191
7399
|
super(`Workspace "${workspace}" does not exist.`);
|
|
@@ -7205,6 +7413,46 @@ function assertWorkspaceExists(workspace, deps = {}) {
|
|
|
7205
7413
|
const isDirectory = deps.isDirectory ?? defaultIsDirectory;
|
|
7206
7414
|
if (!isDirectory(workspace)) throw new WorkspaceNotFoundError(workspace);
|
|
7207
7415
|
}
|
|
7416
|
+
var WorkspaceNotAProjectError = class extends Error {
|
|
7417
|
+
constructor(workspace) {
|
|
7418
|
+
super(`Workspace "${workspace}" is not a project directory (no .ordewell state, version control, or recognized manifest found).`);
|
|
7419
|
+
this.workspace = workspace;
|
|
7420
|
+
this.name = "WorkspaceNotAProjectError";
|
|
7421
|
+
}
|
|
7422
|
+
workspace;
|
|
7423
|
+
};
|
|
7424
|
+
var PROJECT_MARKER_DIRS = [".ordewell", ".git", ".hg", ".svn", ".bzr"];
|
|
7425
|
+
var PROJECT_MARKER_FILES = [
|
|
7426
|
+
"package.json",
|
|
7427
|
+
"Cargo.toml",
|
|
7428
|
+
"go.mod",
|
|
7429
|
+
"pyproject.toml",
|
|
7430
|
+
"setup.py",
|
|
7431
|
+
"requirements.txt",
|
|
7432
|
+
"Pipfile",
|
|
7433
|
+
"pom.xml",
|
|
7434
|
+
"build.gradle",
|
|
7435
|
+
"build.gradle.kts",
|
|
7436
|
+
"Gemfile",
|
|
7437
|
+
"composer.json",
|
|
7438
|
+
"pubspec.yaml",
|
|
7439
|
+
"mix.exs",
|
|
7440
|
+
"CMakeLists.txt"
|
|
7441
|
+
];
|
|
7442
|
+
function assertWorkspaceIsProject(workspace, deps = {}) {
|
|
7443
|
+
const realpath = deps.realpath ?? ((candidate) => fs3.realpathSync(candidate));
|
|
7444
|
+
const exists = deps.exists ?? ((candidate) => fs3.existsSync(candidate));
|
|
7445
|
+
let resolved;
|
|
7446
|
+
try {
|
|
7447
|
+
resolved = realpath(workspace);
|
|
7448
|
+
} catch {
|
|
7449
|
+
throw new WorkspaceNotAProjectError(workspace);
|
|
7450
|
+
}
|
|
7451
|
+
const hasMarker = [...PROJECT_MARKER_DIRS, ...PROJECT_MARKER_FILES].some(
|
|
7452
|
+
(marker) => exists(path9.join(resolved, marker))
|
|
7453
|
+
);
|
|
7454
|
+
if (!hasMarker) throw new WorkspaceNotAProjectError(workspace);
|
|
7455
|
+
}
|
|
7208
7456
|
|
|
7209
7457
|
// src/services/harness/AgentAdapter.ts
|
|
7210
7458
|
var LineBuffer = class {
|
|
@@ -7260,8 +7508,8 @@ var StdioAgentAdapter = class {
|
|
|
7260
7508
|
}
|
|
7261
7509
|
async start(opts) {
|
|
7262
7510
|
assertWorkspaceExists(opts.cwd, { isDirectory: this.deps.isDirectory });
|
|
7263
|
-
this.processEnded = new Promise((
|
|
7264
|
-
this.markEnded =
|
|
7511
|
+
this.processEnded = new Promise((resolve4) => {
|
|
7512
|
+
this.markEnded = resolve4;
|
|
7265
7513
|
});
|
|
7266
7514
|
const spec = this.spawnSpec(opts);
|
|
7267
7515
|
const resolvePath = this.deps.resolvePath ?? augmentedPath;
|
|
@@ -7309,7 +7557,7 @@ ${err.message}`).slice(-STDERR_TAIL_CHARS);
|
|
|
7309
7557
|
onEvent({ type: "error", message: this.exitMessage() });
|
|
7310
7558
|
return;
|
|
7311
7559
|
}
|
|
7312
|
-
await new Promise((
|
|
7560
|
+
await new Promise((resolve4) => {
|
|
7313
7561
|
let settled = false;
|
|
7314
7562
|
const finish = () => {
|
|
7315
7563
|
if (settled) return;
|
|
@@ -7318,7 +7566,7 @@ ${err.message}`).slice(-STDERR_TAIL_CHARS);
|
|
|
7318
7566
|
signal?.removeEventListener("abort", onAbort);
|
|
7319
7567
|
this.process?.removeListener("exit", onExit);
|
|
7320
7568
|
this.process?.removeListener("error", onExit);
|
|
7321
|
-
|
|
7569
|
+
resolve4();
|
|
7322
7570
|
};
|
|
7323
7571
|
const emit = (event) => {
|
|
7324
7572
|
onEvent(event);
|
|
@@ -7519,14 +7767,14 @@ function codexSandboxUnavailableMessage() {
|
|
|
7519
7767
|
].join("\n");
|
|
7520
7768
|
}
|
|
7521
7769
|
function runProbe(deps, cwd, env, flags) {
|
|
7522
|
-
return new Promise((
|
|
7770
|
+
return new Promise((resolve4) => {
|
|
7523
7771
|
let output = "";
|
|
7524
7772
|
let settled = false;
|
|
7525
7773
|
const finish = (code) => {
|
|
7526
7774
|
if (settled) return;
|
|
7527
7775
|
settled = true;
|
|
7528
7776
|
clearTimeout(timer);
|
|
7529
|
-
|
|
7777
|
+
resolve4({ code, output });
|
|
7530
7778
|
};
|
|
7531
7779
|
const timer = setTimeout(() => finish(null), PROBE_TIMEOUT_MS);
|
|
7532
7780
|
timer.unref?.();
|
|
@@ -7609,8 +7857,8 @@ var CodexAdapter = class extends StdioAgentAdapter {
|
|
|
7609
7857
|
async handshake(opts) {
|
|
7610
7858
|
this.sandbox = await probeCodexSandbox(this.deps, opts.cwd, this.spawnEnv);
|
|
7611
7859
|
if (this.sandbox === "unavailable") throw new Error(codexSandboxUnavailableMessage());
|
|
7612
|
-
const ready = new Promise((
|
|
7613
|
-
this.settleHandshake =
|
|
7860
|
+
const ready = new Promise((resolve4) => {
|
|
7861
|
+
this.settleHandshake = resolve4;
|
|
7614
7862
|
});
|
|
7615
7863
|
this.writeLine({
|
|
7616
7864
|
jsonrpc: "2.0",
|
|
@@ -7623,8 +7871,8 @@ var CodexAdapter = class extends StdioAgentAdapter {
|
|
|
7623
7871
|
// A binary that rejects `app-server` outright dies immediately; waiting
|
|
7624
7872
|
// out the timeout would turn a one-line diagnostic into a 30s stall.
|
|
7625
7873
|
this.processEnded.then(() => false),
|
|
7626
|
-
new Promise((
|
|
7627
|
-
const t = setTimeout(() =>
|
|
7874
|
+
new Promise((resolve4) => {
|
|
7875
|
+
const t = setTimeout(() => resolve4(false), HANDSHAKE_TIMEOUT_MS);
|
|
7628
7876
|
t.unref?.();
|
|
7629
7877
|
})
|
|
7630
7878
|
]);
|
|
@@ -7912,12 +8160,12 @@ var OpenCodeAdapter = class {
|
|
|
7912
8160
|
cwd: opts.cwd,
|
|
7913
8161
|
windowsVerbatimArguments: launch.verbatim
|
|
7914
8162
|
});
|
|
7915
|
-
const banner = new Promise((
|
|
8163
|
+
const banner = new Promise((resolve4) => {
|
|
7916
8164
|
let seen = "";
|
|
7917
8165
|
const scan = (chunk) => {
|
|
7918
8166
|
seen += chunk.toString();
|
|
7919
8167
|
const match = seen.match(/https?:\/\/[^\s]+/);
|
|
7920
|
-
if (match)
|
|
8168
|
+
if (match) resolve4(match[0].replace(/[.,)]$/, ""));
|
|
7921
8169
|
};
|
|
7922
8170
|
this.process.stdout?.on("data", scan);
|
|
7923
8171
|
this.process.stderr?.on("data", (chunk) => {
|
|
@@ -7926,15 +8174,15 @@ var OpenCodeAdapter = class {
|
|
|
7926
8174
|
});
|
|
7927
8175
|
this.process.on("exit", () => {
|
|
7928
8176
|
this.exited = true;
|
|
7929
|
-
|
|
8177
|
+
resolve4(null);
|
|
7930
8178
|
});
|
|
7931
8179
|
this.process.on("error", (err) => {
|
|
7932
8180
|
this.exited = true;
|
|
7933
8181
|
this.stderrTail = (this.stderrTail + `
|
|
7934
8182
|
${err.message}`).slice(-STDERR_TAIL_CHARS2);
|
|
7935
|
-
|
|
8183
|
+
resolve4(null);
|
|
7936
8184
|
});
|
|
7937
|
-
const timer = setTimeout(() =>
|
|
8185
|
+
const timer = setTimeout(() => resolve4(null), SERVER_READY_TIMEOUT_MS);
|
|
7938
8186
|
timer.unref?.();
|
|
7939
8187
|
});
|
|
7940
8188
|
this.baseUrl = await banner;
|
|
@@ -7964,8 +8212,8 @@ ${this.stderrTail.trim()}` : ""}`);
|
|
|
7964
8212
|
const streamAbort = new AbortController();
|
|
7965
8213
|
let connected = () => {
|
|
7966
8214
|
};
|
|
7967
|
-
const streamReady = new Promise((
|
|
7968
|
-
connected =
|
|
8215
|
+
const streamReady = new Promise((resolve4) => {
|
|
8216
|
+
connected = resolve4;
|
|
7969
8217
|
});
|
|
7970
8218
|
const live = this.streamEvents(
|
|
7971
8219
|
streamAbort.signal,
|
|
@@ -8117,14 +8365,14 @@ ${this.stderrTail.trim()}` : ""}`);
|
|
|
8117
8365
|
}
|
|
8118
8366
|
}
|
|
8119
8367
|
}
|
|
8120
|
-
async json(method,
|
|
8121
|
-
const response = await this.deps.fetch(`${this.baseUrl}${
|
|
8368
|
+
async json(method, path17, body, signal) {
|
|
8369
|
+
const response = await this.deps.fetch(`${this.baseUrl}${path17}`, {
|
|
8122
8370
|
method,
|
|
8123
8371
|
headers: { "content-type": "application/json" },
|
|
8124
8372
|
...body === void 0 ? {} : { body: JSON.stringify(body) },
|
|
8125
8373
|
...signal ? { signal } : {}
|
|
8126
8374
|
});
|
|
8127
|
-
if (!response.ok) throw new Error(`${method} ${
|
|
8375
|
+
if (!response.ok) throw new Error(`${method} ${path17} failed: ${response.status} ${response.statusText}`);
|
|
8128
8376
|
return await response.json().catch(() => null);
|
|
8129
8377
|
}
|
|
8130
8378
|
nativeSessionId() {
|
|
@@ -8938,11 +9186,11 @@ function executionSummary(tasks) {
|
|
|
8938
9186
|
|
|
8939
9187
|
// src/utils/sessionStore.ts
|
|
8940
9188
|
import * as fs5 from "fs";
|
|
8941
|
-
import * as
|
|
9189
|
+
import * as path11 from "path";
|
|
8942
9190
|
|
|
8943
9191
|
// src/utils/fsHelpers.ts
|
|
8944
9192
|
import * as fs4 from "fs";
|
|
8945
|
-
import * as
|
|
9193
|
+
import * as path10 from "path";
|
|
8946
9194
|
var STATE_DIR = ".ordewell";
|
|
8947
9195
|
function ensureDir(dir) {
|
|
8948
9196
|
if (!fs4.existsSync(dir)) {
|
|
@@ -8950,13 +9198,19 @@ function ensureDir(dir) {
|
|
|
8950
9198
|
}
|
|
8951
9199
|
}
|
|
8952
9200
|
function getStateDir(baseDir) {
|
|
8953
|
-
return
|
|
9201
|
+
return path10.join(baseDir ?? process.cwd(), STATE_DIR);
|
|
9202
|
+
}
|
|
9203
|
+
|
|
9204
|
+
// src/utils/sessionId.ts
|
|
9205
|
+
import { randomBytes } from "crypto";
|
|
9206
|
+
function mintSessionId() {
|
|
9207
|
+
return `session-${randomBytes(16).toString("hex")}`;
|
|
8954
9208
|
}
|
|
8955
9209
|
|
|
8956
9210
|
// src/utils/sessionStore.ts
|
|
8957
9211
|
var SESSIONS_SUBDIR = "sessions";
|
|
8958
9212
|
function getSessionsDir(baseDir) {
|
|
8959
|
-
return
|
|
9213
|
+
return path11.join(getStateDir(baseDir), SESSIONS_SUBDIR);
|
|
8960
9214
|
}
|
|
8961
9215
|
var REJECTION_MESSAGE = "This session was created with an older version of Ordewell. Please re-plan.";
|
|
8962
9216
|
function hasScalarRunner(parsed) {
|
|
@@ -8977,7 +9231,7 @@ function saveSession(plan, goal, baseDir, id) {
|
|
|
8977
9231
|
ensureDir(sessionsDir);
|
|
8978
9232
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
8979
9233
|
const meta = {
|
|
8980
|
-
id: id ||
|
|
9234
|
+
id: id || mintSessionId(),
|
|
8981
9235
|
goal: goal || "(untitled)",
|
|
8982
9236
|
runners: plan.runners,
|
|
8983
9237
|
taskCount: plan.tasks.flatMap((t) => [t, ...t.subtasks || []]).length,
|
|
@@ -8990,7 +9244,7 @@ function saveSession(plan, goal, baseDir, id) {
|
|
|
8990
9244
|
plan: JSON.parse(JSON.stringify(plan))
|
|
8991
9245
|
};
|
|
8992
9246
|
const filename = sessionFilename(meta);
|
|
8993
|
-
const filePath =
|
|
9247
|
+
const filePath = path11.join(sessionsDir, filename);
|
|
8994
9248
|
fs5.writeFileSync(filePath, JSON.stringify(session, null, 2));
|
|
8995
9249
|
return meta;
|
|
8996
9250
|
}
|
|
@@ -9000,7 +9254,7 @@ function listSessions(baseDir, logger = defaultLogger) {
|
|
|
9000
9254
|
const files = fs5.readdirSync(sessionsDir).filter((f) => f.endsWith(".json"));
|
|
9001
9255
|
return files.map((f) => {
|
|
9002
9256
|
try {
|
|
9003
|
-
const raw = fs5.readFileSync(
|
|
9257
|
+
const raw = fs5.readFileSync(path11.join(sessionsDir, f), "utf-8");
|
|
9004
9258
|
const parsed = JSON.parse(raw);
|
|
9005
9259
|
if (hasScalarRunner(parsed)) {
|
|
9006
9260
|
logger.warn("sessionStore", `session file ${f}: ${REJECTION_MESSAGE}`);
|
|
@@ -9018,7 +9272,7 @@ function findSessionFile(sessionsDir, sessionId, logger) {
|
|
|
9018
9272
|
const files = fs5.readdirSync(sessionsDir).filter((f) => f.endsWith(".json"));
|
|
9019
9273
|
for (const f of files) {
|
|
9020
9274
|
try {
|
|
9021
|
-
const raw = fs5.readFileSync(
|
|
9275
|
+
const raw = fs5.readFileSync(path11.join(sessionsDir, f), "utf-8");
|
|
9022
9276
|
const session = JSON.parse(raw);
|
|
9023
9277
|
if (session.meta.id === sessionId) return f;
|
|
9024
9278
|
} catch (err) {
|
|
@@ -9033,7 +9287,7 @@ function loadSession(sessionId, baseDir, logger = defaultLogger) {
|
|
|
9033
9287
|
try {
|
|
9034
9288
|
const file = findSessionFile(sessionsDir, sessionId, logger);
|
|
9035
9289
|
if (file) {
|
|
9036
|
-
const raw = fs5.readFileSync(
|
|
9290
|
+
const raw = fs5.readFileSync(path11.join(sessionsDir, file), "utf-8");
|
|
9037
9291
|
const parsed = JSON.parse(raw);
|
|
9038
9292
|
if (hasScalarRunner(parsed)) {
|
|
9039
9293
|
logger.warn("sessionStore", `session file ${file}: ${REJECTION_MESSAGE}`);
|
|
@@ -9067,7 +9321,7 @@ function deleteSession(sessionId, baseDir, logger = defaultLogger) {
|
|
|
9067
9321
|
try {
|
|
9068
9322
|
const file = findSessionFile(sessionsDir, sessionId, logger);
|
|
9069
9323
|
if (file) {
|
|
9070
|
-
fs5.unlinkSync(
|
|
9324
|
+
fs5.unlinkSync(path11.join(sessionsDir, file));
|
|
9071
9325
|
return true;
|
|
9072
9326
|
}
|
|
9073
9327
|
} catch (err) {
|
|
@@ -9086,11 +9340,6 @@ var PlanEditError = class extends Error {
|
|
|
9086
9340
|
function sessionRuntimeSettings(settings) {
|
|
9087
9341
|
return { ...plannerRuntimeToggles(settings), modelAllowlist: settings.modelAllowlist };
|
|
9088
9342
|
}
|
|
9089
|
-
var lastMintedAt = 0;
|
|
9090
|
-
function mintSessionId() {
|
|
9091
|
-
lastMintedAt = Math.max(Date.now(), lastMintedAt + 1);
|
|
9092
|
-
return `session-${lastMintedAt}`;
|
|
9093
|
-
}
|
|
9094
9343
|
var Session = class {
|
|
9095
9344
|
/** Injected by a test; when present it is the service, forever. */
|
|
9096
9345
|
pinnedAiService;
|
|
@@ -10531,8 +10780,8 @@ var HeadlessRunner = class extends AbstractRunner {
|
|
|
10531
10780
|
import { execFile as execFile2 } from "child_process";
|
|
10532
10781
|
import { promisify as promisify4 } from "util";
|
|
10533
10782
|
import { tmpdir } from "os";
|
|
10534
|
-
import { join as
|
|
10535
|
-
import { existsSync as
|
|
10783
|
+
import { join as join10 } from "path";
|
|
10784
|
+
import { existsSync as existsSync6, readFileSync as readFileSync4, unlinkSync as unlinkSync2, writeFileSync as writeFileSync5 } from "fs";
|
|
10536
10785
|
|
|
10537
10786
|
// src/utils/tmux.ts
|
|
10538
10787
|
import { execSync as execSync2 } from "child_process";
|
|
@@ -10637,7 +10886,7 @@ var TmuxSession = class extends AbstractTerminalSession {
|
|
|
10637
10886
|
if (this.exited) return;
|
|
10638
10887
|
let content;
|
|
10639
10888
|
try {
|
|
10640
|
-
content =
|
|
10889
|
+
content = existsSync6(this.logPath) ? readFileSync4(this.logPath, "utf8") : "";
|
|
10641
10890
|
} catch {
|
|
10642
10891
|
return;
|
|
10643
10892
|
}
|
|
@@ -10816,7 +11065,7 @@ var TmuxRunner = class extends AbstractRunner {
|
|
|
10816
11065
|
windowName,
|
|
10817
11066
|
this.execFileImpl,
|
|
10818
11067
|
this.pollIntervalMs,
|
|
10819
|
-
|
|
11068
|
+
join10(this.logDir, `${id}.log`),
|
|
10820
11069
|
this.socket
|
|
10821
11070
|
);
|
|
10822
11071
|
invocation.env = { ...invocation.env, PATH: await this.resolvePath() };
|
|
@@ -10826,26 +11075,128 @@ var TmuxRunner = class extends AbstractRunner {
|
|
|
10826
11075
|
}
|
|
10827
11076
|
};
|
|
10828
11077
|
|
|
11078
|
+
// src/utils/daemonToken.ts
|
|
11079
|
+
import { randomBytes as randomBytes2, timingSafeEqual } from "crypto";
|
|
11080
|
+
import { closeSync, mkdirSync as mkdirSync5, openSync, readFileSync as readFileSync5, unlinkSync as unlinkSync3, writeSync } from "fs";
|
|
11081
|
+
import { homedir as homedir5 } from "os";
|
|
11082
|
+
import { join as join11 } from "path";
|
|
11083
|
+
var BEARER_PREFIX = "bearer ";
|
|
11084
|
+
var DAEMON_TOKEN_SUBPROTOCOL_PREFIX = "ordewell.token.";
|
|
11085
|
+
var DAEMON_SUBPROTOCOL = "ordewell.v1";
|
|
11086
|
+
function configDir() {
|
|
11087
|
+
return join11(homedir5(), ".config", "ordewell");
|
|
11088
|
+
}
|
|
11089
|
+
function daemonTokenPath(port) {
|
|
11090
|
+
return join11(configDir(), `server-${port}.token`);
|
|
11091
|
+
}
|
|
11092
|
+
function mintDaemonToken(port) {
|
|
11093
|
+
const token = randomBytes2(32).toString("base64url");
|
|
11094
|
+
const file = daemonTokenPath(port);
|
|
11095
|
+
mkdirSync5(configDir(), { recursive: true });
|
|
11096
|
+
try {
|
|
11097
|
+
unlinkSync3(file);
|
|
11098
|
+
} catch {
|
|
11099
|
+
}
|
|
11100
|
+
const fd = openSync(file, "wx", 384);
|
|
11101
|
+
try {
|
|
11102
|
+
writeSync(fd, token);
|
|
11103
|
+
} finally {
|
|
11104
|
+
closeSync(fd);
|
|
11105
|
+
}
|
|
11106
|
+
return { token, file };
|
|
11107
|
+
}
|
|
11108
|
+
function readDaemonToken(port) {
|
|
11109
|
+
try {
|
|
11110
|
+
const token = readFileSync5(daemonTokenPath(port), "utf8").trim();
|
|
11111
|
+
return token === "" ? void 0 : token;
|
|
11112
|
+
} catch {
|
|
11113
|
+
return void 0;
|
|
11114
|
+
}
|
|
11115
|
+
}
|
|
11116
|
+
function clearDaemonToken(port) {
|
|
11117
|
+
try {
|
|
11118
|
+
unlinkSync3(daemonTokenPath(port));
|
|
11119
|
+
} catch {
|
|
11120
|
+
}
|
|
11121
|
+
}
|
|
11122
|
+
function bearerHeaderValue(token) {
|
|
11123
|
+
return `Bearer ${token}`;
|
|
11124
|
+
}
|
|
11125
|
+
function tokenSubprotocols(token) {
|
|
11126
|
+
return [DAEMON_SUBPROTOCOL, `${DAEMON_TOKEN_SUBPROTOCOL_PREFIX}${token}`];
|
|
11127
|
+
}
|
|
11128
|
+
function extractPresentedToken(carriers) {
|
|
11129
|
+
const authorization = carriers.authorization;
|
|
11130
|
+
if (authorization && authorization.toLowerCase().startsWith(BEARER_PREFIX)) {
|
|
11131
|
+
const value = authorization.slice(BEARER_PREFIX.length).trim();
|
|
11132
|
+
if (value !== "") return value;
|
|
11133
|
+
}
|
|
11134
|
+
for (const offered of (carriers.secWebSocketProtocol ?? "").split(",")) {
|
|
11135
|
+
const value = offered.trim();
|
|
11136
|
+
if (!value.startsWith(DAEMON_TOKEN_SUBPROTOCOL_PREFIX)) continue;
|
|
11137
|
+
const token = value.slice(DAEMON_TOKEN_SUBPROTOCOL_PREFIX.length);
|
|
11138
|
+
if (token !== "") return token;
|
|
11139
|
+
}
|
|
11140
|
+
return void 0;
|
|
11141
|
+
}
|
|
11142
|
+
function tokensMatch(presented, expected) {
|
|
11143
|
+
if (presented === void 0) return false;
|
|
11144
|
+
const a = Buffer.from(presented, "utf8");
|
|
11145
|
+
const b = Buffer.from(expected, "utf8");
|
|
11146
|
+
if (a.length !== b.length) return false;
|
|
11147
|
+
return timingSafeEqual(a, b);
|
|
11148
|
+
}
|
|
11149
|
+
|
|
10829
11150
|
// src/plugins/RunnerRegistry.ts
|
|
10830
11151
|
import * as fs7 from "fs";
|
|
10831
|
-
import * as
|
|
11152
|
+
import * as path14 from "path";
|
|
10832
11153
|
import * as os5 from "os";
|
|
10833
|
-
import {
|
|
11154
|
+
import { execFileSync } from "child_process";
|
|
11155
|
+
import { randomBytes as randomBytes3 } from "crypto";
|
|
10834
11156
|
|
|
10835
11157
|
// src/plugins/FsPluginStore.ts
|
|
10836
11158
|
import * as fs6 from "fs";
|
|
10837
|
-
import * as
|
|
11159
|
+
import * as path13 from "path";
|
|
10838
11160
|
import * as os4 from "os";
|
|
10839
|
-
|
|
10840
|
-
|
|
11161
|
+
|
|
11162
|
+
// src/plugins/pluginNames.ts
|
|
11163
|
+
import * as path12 from "path";
|
|
11164
|
+
var PLUGIN_NAME_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
|
|
11165
|
+
var MAX_PLUGIN_NAME_LENGTH = 64;
|
|
11166
|
+
function isPlainPluginName(name) {
|
|
11167
|
+
return typeof name === "string" && name.length <= MAX_PLUGIN_NAME_LENGTH && PLUGIN_NAME_PATTERN.test(name);
|
|
11168
|
+
}
|
|
11169
|
+
function assertPlainPluginName(name) {
|
|
11170
|
+
if (!isPlainPluginName(name)) {
|
|
11171
|
+
throw new Error(
|
|
11172
|
+
`Invalid plugin name: ${JSON.stringify(name)}. Names must be a single plain segment of letters, digits, '.', '-' or '_' (max ${MAX_PLUGIN_NAME_LENGTH} characters).`
|
|
11173
|
+
);
|
|
11174
|
+
}
|
|
10841
11175
|
}
|
|
11176
|
+
function resolvePluginInstallDir(pluginsDir, name) {
|
|
11177
|
+
assertPlainPluginName(name);
|
|
11178
|
+
const root = path12.resolve(pluginsDir);
|
|
11179
|
+
const dest = path12.resolve(root, name);
|
|
11180
|
+
const relative3 = path12.relative(root, dest);
|
|
11181
|
+
if (relative3 !== name || relative3 === "" || path12.isAbsolute(relative3)) {
|
|
11182
|
+
throw new Error(`Plugin install path escapes the plugins directory: ${JSON.stringify(name)}`);
|
|
11183
|
+
}
|
|
11184
|
+
return dest;
|
|
11185
|
+
}
|
|
11186
|
+
|
|
11187
|
+
// src/plugins/manifestValidation.ts
|
|
10842
11188
|
function isValidManifest(obj) {
|
|
10843
11189
|
if (!obj || typeof obj !== "object") return false;
|
|
10844
11190
|
const m = obj;
|
|
10845
|
-
return
|
|
11191
|
+
return isPlainPluginName(m.name) && typeof m.displayName === "string" && typeof m.description === "string" && typeof m.version === "string" && typeof m.runner === "object" && m.runner !== null && typeof m.runner.command === "string" && Array.isArray(m.runner.argsTemplate) && typeof m.features === "object" && m.features !== null && typeof m.modelDiscovery === "object" && m.modelDiscovery !== null;
|
|
11192
|
+
}
|
|
11193
|
+
|
|
11194
|
+
// src/plugins/FsPluginStore.ts
|
|
11195
|
+
function userPluginsDir() {
|
|
11196
|
+
return path13.join(os4.homedir(), ".config", "ordewell", "plugins");
|
|
10846
11197
|
}
|
|
10847
11198
|
function loadManifestFromDir(dir) {
|
|
10848
|
-
const manifestPath =
|
|
11199
|
+
const manifestPath = path13.join(dir, "manifest.json");
|
|
10849
11200
|
if (!fs6.existsSync(manifestPath)) return null;
|
|
10850
11201
|
try {
|
|
10851
11202
|
const raw = fs6.readFileSync(manifestPath, "utf8");
|
|
@@ -10860,8 +11211,8 @@ function copyDirSync(src, dest) {
|
|
|
10860
11211
|
ensureDir(dest);
|
|
10861
11212
|
const entries = fs6.readdirSync(src, { withFileTypes: true });
|
|
10862
11213
|
for (const entry of entries) {
|
|
10863
|
-
const srcPath =
|
|
10864
|
-
const destPath =
|
|
11214
|
+
const srcPath = path13.join(src, entry.name);
|
|
11215
|
+
const destPath = path13.join(dest, entry.name);
|
|
10865
11216
|
if (entry.isDirectory()) {
|
|
10866
11217
|
copyDirSync(srcPath, destPath);
|
|
10867
11218
|
} else {
|
|
@@ -10873,7 +11224,7 @@ function rmDirSync(dir) {
|
|
|
10873
11224
|
if (!fs6.existsSync(dir)) return;
|
|
10874
11225
|
const entries = fs6.readdirSync(dir, { withFileTypes: true });
|
|
10875
11226
|
for (const entry of entries) {
|
|
10876
|
-
const p =
|
|
11227
|
+
const p = path13.join(dir, entry.name);
|
|
10877
11228
|
if (entry.isDirectory()) {
|
|
10878
11229
|
rmDirSync(p);
|
|
10879
11230
|
} else {
|
|
@@ -10897,6 +11248,13 @@ var FsPluginStore = class {
|
|
|
10897
11248
|
}
|
|
10898
11249
|
return entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
10899
11250
|
}
|
|
11251
|
+
listDir(dir) {
|
|
11252
|
+
try {
|
|
11253
|
+
return fs6.readdirSync(dir);
|
|
11254
|
+
} catch {
|
|
11255
|
+
return [];
|
|
11256
|
+
}
|
|
11257
|
+
}
|
|
10900
11258
|
loadManifest(pluginDir) {
|
|
10901
11259
|
return loadManifestFromDir(pluginDir);
|
|
10902
11260
|
}
|
|
@@ -10919,11 +11277,11 @@ var FsPluginStore = class {
|
|
|
10919
11277
|
return null;
|
|
10920
11278
|
}
|
|
10921
11279
|
}
|
|
10922
|
-
dirExists(
|
|
10923
|
-
return fs6.existsSync(
|
|
11280
|
+
dirExists(path17) {
|
|
11281
|
+
return fs6.existsSync(path17) && fs6.statSync(path17).isDirectory();
|
|
10924
11282
|
}
|
|
10925
|
-
exists(
|
|
10926
|
-
return fs6.existsSync(
|
|
11283
|
+
exists(path17) {
|
|
11284
|
+
return fs6.existsSync(path17);
|
|
10927
11285
|
}
|
|
10928
11286
|
};
|
|
10929
11287
|
|
|
@@ -11211,17 +11569,98 @@ var OPENCODE_MANIFEST = {
|
|
|
11211
11569
|
]
|
|
11212
11570
|
};
|
|
11213
11571
|
|
|
11572
|
+
// src/plugins/pluginSource.ts
|
|
11573
|
+
var ALLOWED_PLUGIN_HOSTS = [
|
|
11574
|
+
"github.com",
|
|
11575
|
+
"gitlab.com",
|
|
11576
|
+
"bitbucket.org",
|
|
11577
|
+
"codeberg.org"
|
|
11578
|
+
];
|
|
11579
|
+
var SAFE_REPO_PATH = /^\/[A-Za-z0-9._~-]+(?:\/[A-Za-z0-9._~-]+)*$/;
|
|
11580
|
+
var HAS_SCHEME = /^[A-Za-z][A-Za-z0-9+.-]+:/;
|
|
11581
|
+
var SCP_LIKE_REMOTE = /^[^/\\]+@[^/\\]+:/;
|
|
11582
|
+
function hasControlCharacter(value) {
|
|
11583
|
+
for (let i = 0; i < value.length; i++) {
|
|
11584
|
+
const code = value.charCodeAt(i);
|
|
11585
|
+
if (code < 32 || code === 127) return true;
|
|
11586
|
+
}
|
|
11587
|
+
return false;
|
|
11588
|
+
}
|
|
11589
|
+
function assertInstallablePluginUrl(url) {
|
|
11590
|
+
if (typeof url !== "string" || url.trim() === "") {
|
|
11591
|
+
throw new Error("A plugin repository URL is required.");
|
|
11592
|
+
}
|
|
11593
|
+
if (hasControlCharacter(url)) {
|
|
11594
|
+
throw new Error("Plugin URL contains control characters.");
|
|
11595
|
+
}
|
|
11596
|
+
let parsed;
|
|
11597
|
+
try {
|
|
11598
|
+
parsed = new URL(url.trim());
|
|
11599
|
+
} catch {
|
|
11600
|
+
throw new Error(`Not a valid plugin repository URL: ${url}`);
|
|
11601
|
+
}
|
|
11602
|
+
if (parsed.protocol !== "https:") {
|
|
11603
|
+
throw new Error(
|
|
11604
|
+
`Plugin repositories must be cloned over https (got "${parsed.protocol}//"). git transport helpers and non-https schemes are not accepted.`
|
|
11605
|
+
);
|
|
11606
|
+
}
|
|
11607
|
+
if (parsed.username || parsed.password) {
|
|
11608
|
+
throw new Error("Plugin URL must not embed credentials.");
|
|
11609
|
+
}
|
|
11610
|
+
if (parsed.port) {
|
|
11611
|
+
throw new Error("Plugin URL must not specify a port.");
|
|
11612
|
+
}
|
|
11613
|
+
if (parsed.search || parsed.hash) {
|
|
11614
|
+
throw new Error("Plugin URL must not carry a query string or fragment.");
|
|
11615
|
+
}
|
|
11616
|
+
const host = parsed.hostname.toLowerCase();
|
|
11617
|
+
if (!ALLOWED_PLUGIN_HOSTS.includes(host)) {
|
|
11618
|
+
throw new Error(
|
|
11619
|
+
`Plugin host not allowed: ${host}. Allowed hosts: ${ALLOWED_PLUGIN_HOSTS.join(", ")}.`
|
|
11620
|
+
);
|
|
11621
|
+
}
|
|
11622
|
+
if (!SAFE_REPO_PATH.test(parsed.pathname)) {
|
|
11623
|
+
throw new Error(`Not a plain repository path: ${parsed.pathname}`);
|
|
11624
|
+
}
|
|
11625
|
+
return parsed;
|
|
11626
|
+
}
|
|
11627
|
+
function classifyPluginSource(source) {
|
|
11628
|
+
const trimmed = source.trim();
|
|
11629
|
+
if (trimmed.startsWith("github:")) {
|
|
11630
|
+
const repo = trimmed.slice("github:".length).replace(/\.git$/, "");
|
|
11631
|
+
return { kind: "git", url: `https://github.com/${repo}.git` };
|
|
11632
|
+
}
|
|
11633
|
+
if (HAS_SCHEME.test(trimmed) || SCP_LIKE_REMOTE.test(trimmed)) {
|
|
11634
|
+
return { kind: "git", url: trimmed };
|
|
11635
|
+
}
|
|
11636
|
+
return { kind: "path", path: source };
|
|
11637
|
+
}
|
|
11638
|
+
|
|
11214
11639
|
// src/plugins/RunnerRegistry.ts
|
|
11215
11640
|
var BUILTIN_MANIFESTS = [
|
|
11216
11641
|
CLAUDE_CODE_MANIFEST,
|
|
11217
11642
|
CODEX_MANIFEST,
|
|
11218
11643
|
OPENCODE_MANIFEST
|
|
11219
11644
|
];
|
|
11645
|
+
var RESERVED_RUNNER_NAMES = new Set(BUILTIN_MANIFESTS.map((m) => m.name.toLowerCase()));
|
|
11646
|
+
function isReservedRunnerName(name) {
|
|
11647
|
+
return RESERVED_RUNNER_NAMES.has(name.toLowerCase());
|
|
11648
|
+
}
|
|
11649
|
+
function gitClone(url, destDir) {
|
|
11650
|
+
execFileSync("git", ["clone", "--depth", "1", "--", url, destDir], {
|
|
11651
|
+
stdio: "pipe",
|
|
11652
|
+
timeout: 3e4,
|
|
11653
|
+
// A repository that demands credentials should fail, not hang on a prompt.
|
|
11654
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }
|
|
11655
|
+
});
|
|
11656
|
+
}
|
|
11220
11657
|
var RunnerRegistry = class {
|
|
11221
11658
|
plugins = /* @__PURE__ */ new Map();
|
|
11222
11659
|
store;
|
|
11223
|
-
|
|
11660
|
+
clone;
|
|
11661
|
+
constructor(store, clone) {
|
|
11224
11662
|
this.store = store ?? new FsPluginStore();
|
|
11663
|
+
this.clone = clone ?? gitClone;
|
|
11225
11664
|
this.loadBuiltins();
|
|
11226
11665
|
}
|
|
11227
11666
|
loadBuiltins() {
|
|
@@ -11232,9 +11671,15 @@ var RunnerRegistry = class {
|
|
|
11232
11671
|
loadUserPlugins() {
|
|
11233
11672
|
const names = this.store.listUserPluginDirs();
|
|
11234
11673
|
for (const name of names) {
|
|
11235
|
-
|
|
11674
|
+
let pluginDir;
|
|
11675
|
+
try {
|
|
11676
|
+
pluginDir = resolvePluginInstallDir(this.store.getUserPluginsDir(), name);
|
|
11677
|
+
} catch {
|
|
11678
|
+
continue;
|
|
11679
|
+
}
|
|
11236
11680
|
const manifest = this.store.loadManifest(pluginDir);
|
|
11237
|
-
if (!manifest) continue;
|
|
11681
|
+
if (!manifest || !isPlainPluginName(manifest.name)) continue;
|
|
11682
|
+
if (isReservedRunnerName(manifest.name)) continue;
|
|
11238
11683
|
this.plugins.set(manifest.name, {
|
|
11239
11684
|
manifest,
|
|
11240
11685
|
source: "user",
|
|
@@ -11263,7 +11708,7 @@ var RunnerRegistry = class {
|
|
|
11263
11708
|
return entry?.source === "builtin";
|
|
11264
11709
|
}
|
|
11265
11710
|
installFromPath(sourcePath) {
|
|
11266
|
-
const absPath =
|
|
11711
|
+
const absPath = path14.resolve(sourcePath);
|
|
11267
11712
|
if (!this.store.dirExists(absPath)) {
|
|
11268
11713
|
throw new Error(`Plugin source must be a directory: ${absPath}`);
|
|
11269
11714
|
}
|
|
@@ -11271,48 +11716,50 @@ var RunnerRegistry = class {
|
|
|
11271
11716
|
if (!manifest) {
|
|
11272
11717
|
throw new Error(`No valid manifest.json found in: ${absPath}`);
|
|
11273
11718
|
}
|
|
11274
|
-
|
|
11275
|
-
this.store.ensureDir(destDir);
|
|
11276
|
-
this.store.copyDir(absPath, destDir);
|
|
11277
|
-
this.plugins.set(manifest.name, {
|
|
11278
|
-
manifest,
|
|
11279
|
-
source: "user",
|
|
11280
|
-
installPath: destDir
|
|
11281
|
-
});
|
|
11282
|
-
return manifest;
|
|
11719
|
+
return this.registerInstalled(manifest, absPath);
|
|
11283
11720
|
}
|
|
11284
11721
|
installFromGit(url) {
|
|
11285
|
-
const
|
|
11286
|
-
const tmpDir =
|
|
11722
|
+
const validated = assertInstallablePluginUrl(url);
|
|
11723
|
+
const tmpDir = path14.join(os5.tmpdir(), `ordewell-plugin-${randomBytes3(12).toString("hex")}`);
|
|
11287
11724
|
this.store.ensureDir(tmpDir);
|
|
11288
11725
|
try {
|
|
11289
|
-
|
|
11290
|
-
|
|
11291
|
-
|
|
11292
|
-
|
|
11293
|
-
|
|
11294
|
-
|
|
11295
|
-
|
|
11296
|
-
|
|
11297
|
-
|
|
11298
|
-
|
|
11299
|
-
|
|
11300
|
-
|
|
11726
|
+
try {
|
|
11727
|
+
this.clone(validated.toString(), tmpDir);
|
|
11728
|
+
} catch (err) {
|
|
11729
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
11730
|
+
throw new Error(`Failed to clone repository: ${message}`);
|
|
11731
|
+
}
|
|
11732
|
+
const contents = this.store.listDir(tmpDir);
|
|
11733
|
+
const hasManifest = contents.some((f) => f === "manifest.json");
|
|
11734
|
+
let sourceDir = tmpDir;
|
|
11735
|
+
if (!hasManifest) {
|
|
11736
|
+
const onlyEntry = contents.length === 1 ? path14.join(tmpDir, contents[0]) : void 0;
|
|
11737
|
+
if (!onlyEntry || !this.store.dirExists(onlyEntry)) {
|
|
11738
|
+
throw new Error(`No manifest.json found in repository: ${validated.toString()}`);
|
|
11739
|
+
}
|
|
11740
|
+
sourceDir = onlyEntry;
|
|
11741
|
+
}
|
|
11742
|
+
const manifest = this.store.loadManifest(sourceDir);
|
|
11743
|
+
if (!manifest) {
|
|
11744
|
+
throw new Error("No valid manifest.json found in cloned repository");
|
|
11745
|
+
}
|
|
11746
|
+
return this.registerInstalled(manifest, sourceDir);
|
|
11747
|
+
} finally {
|
|
11301
11748
|
this.store.removeDir(tmpDir);
|
|
11302
|
-
throw new Error(`No manifest.json found in repository: ${url}`);
|
|
11303
11749
|
}
|
|
11304
|
-
return this.finishInstall(tmpDir, repoName, tmpDir);
|
|
11305
11750
|
}
|
|
11306
|
-
|
|
11307
|
-
|
|
11308
|
-
|
|
11309
|
-
|
|
11310
|
-
|
|
11751
|
+
/**
|
|
11752
|
+
* The single destination-building step both install routes share: the name is
|
|
11753
|
+
* constrained to a plain segment and the resolved destination is asserted to
|
|
11754
|
+
* be inside the plugins directory before anything is copied.
|
|
11755
|
+
*/
|
|
11756
|
+
registerInstalled(manifest, sourceDir) {
|
|
11757
|
+
if (isReservedRunnerName(manifest.name)) {
|
|
11758
|
+
throw new Error(`Cannot install a plugin named after a built-in runner: ${manifest.name}`);
|
|
11311
11759
|
}
|
|
11312
|
-
const destDir =
|
|
11760
|
+
const destDir = resolvePluginInstallDir(this.store.getUserPluginsDir(), manifest.name);
|
|
11313
11761
|
this.store.ensureDir(destDir);
|
|
11314
11762
|
this.store.copyDir(sourceDir, destDir);
|
|
11315
|
-
this.store.removeDir(tmpDir);
|
|
11316
11763
|
this.plugins.set(manifest.name, {
|
|
11317
11764
|
manifest,
|
|
11318
11765
|
source: "user",
|
|
@@ -11333,7 +11780,8 @@ var RunnerRegistry = class {
|
|
|
11333
11780
|
this.plugins.delete(name);
|
|
11334
11781
|
}
|
|
11335
11782
|
createSkeleton(name, outputDir) {
|
|
11336
|
-
|
|
11783
|
+
assertPlainPluginName(name);
|
|
11784
|
+
const dir = path14.resolve(outputDir, name);
|
|
11337
11785
|
this.store.ensureDir(dir);
|
|
11338
11786
|
const manifest = {
|
|
11339
11787
|
name,
|
|
@@ -11365,8 +11813,8 @@ var RunnerRegistry = class {
|
|
|
11365
11813
|
]
|
|
11366
11814
|
}
|
|
11367
11815
|
};
|
|
11368
|
-
this.store.writeFile(
|
|
11369
|
-
const runSh =
|
|
11816
|
+
this.store.writeFile(path14.join(dir, "manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
|
|
11817
|
+
const runSh = path14.join(dir, "run.sh");
|
|
11370
11818
|
const scriptContent = `#!/usr/bin/env bash
|
|
11371
11819
|
# Custom runner script for ${name}
|
|
11372
11820
|
# Receives:
|
|
@@ -11390,13 +11838,6 @@ echo "Running ${name} with prompt: $prompt"
|
|
|
11390
11838
|
return dir;
|
|
11391
11839
|
}
|
|
11392
11840
|
};
|
|
11393
|
-
function fsReaddirSync(dir) {
|
|
11394
|
-
try {
|
|
11395
|
-
return fs7.readdirSync(dir);
|
|
11396
|
-
} catch {
|
|
11397
|
-
return [];
|
|
11398
|
-
}
|
|
11399
|
-
}
|
|
11400
11841
|
function fsChmodSync(fpath, mode) {
|
|
11401
11842
|
try {
|
|
11402
11843
|
fs7.chmodSync(fpath, mode);
|
|
@@ -11406,14 +11847,14 @@ function fsChmodSync(fpath, mode) {
|
|
|
11406
11847
|
|
|
11407
11848
|
// src/utils/stateStore.ts
|
|
11408
11849
|
import * as fs8 from "fs";
|
|
11409
|
-
import * as
|
|
11850
|
+
import * as path15 from "path";
|
|
11410
11851
|
var STATE_FILE = "state.json";
|
|
11411
11852
|
function getStatePath(baseDir) {
|
|
11412
|
-
return
|
|
11853
|
+
return path15.join(getStateDir(baseDir), STATE_FILE);
|
|
11413
11854
|
}
|
|
11414
11855
|
function saveState(plan, baseDir) {
|
|
11415
11856
|
const statePath = getStatePath(baseDir ?? process.cwd());
|
|
11416
|
-
ensureDir(
|
|
11857
|
+
ensureDir(path15.dirname(statePath));
|
|
11417
11858
|
plan.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
|
|
11418
11859
|
fs8.writeFileSync(statePath, JSON.stringify(plan, null, 2));
|
|
11419
11860
|
}
|
|
@@ -11446,7 +11887,7 @@ function stateExists(baseDir) {
|
|
|
11446
11887
|
|
|
11447
11888
|
// src/services/SettingsService.ts
|
|
11448
11889
|
import * as fs9 from "fs";
|
|
11449
|
-
import * as
|
|
11890
|
+
import * as path16 from "path";
|
|
11450
11891
|
import * as os6 from "os";
|
|
11451
11892
|
var DEFAULTS = {
|
|
11452
11893
|
grillMe: { enabled: false },
|
|
@@ -11459,7 +11900,7 @@ var DEFAULTS = {
|
|
|
11459
11900
|
function getSettingsPath() {
|
|
11460
11901
|
const override = process.env.ORDEWELL_SETTINGS_PATH;
|
|
11461
11902
|
if (override && override.trim()) return override.trim();
|
|
11462
|
-
return
|
|
11903
|
+
return path16.join(os6.homedir(), ".config", "ordewell", "settings.json");
|
|
11463
11904
|
}
|
|
11464
11905
|
function readPlannerModels(raw) {
|
|
11465
11906
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
@@ -11624,7 +12065,7 @@ var SettingsService = class {
|
|
|
11624
12065
|
return { ...DEFAULTS, grillMe: { ...DEFAULTS.grillMe }, tdd: { ...DEFAULTS.tdd }, prd: { ...DEFAULTS.prd }, review: { ...DEFAULTS.review }, verification: { ...DEFAULTS.verification }, researchSubagents: { ...DEFAULTS.researchSubagents } };
|
|
11625
12066
|
}
|
|
11626
12067
|
persist() {
|
|
11627
|
-
const dir =
|
|
12068
|
+
const dir = path16.dirname(this.filePath);
|
|
11628
12069
|
if (!fs9.existsSync(dir)) {
|
|
11629
12070
|
fs9.mkdirSync(dir, { recursive: true });
|
|
11630
12071
|
}
|
|
@@ -11668,6 +12109,7 @@ var PlannerModelMemory = class {
|
|
|
11668
12109
|
}
|
|
11669
12110
|
};
|
|
11670
12111
|
export {
|
|
12112
|
+
ALLOWED_PLUGIN_HOSTS,
|
|
11671
12113
|
ALL_PROVIDERS,
|
|
11672
12114
|
AUTO_COMMANDS,
|
|
11673
12115
|
AbstractRunner,
|
|
@@ -11686,6 +12128,8 @@ export {
|
|
|
11686
12128
|
CommandLineTooLongError,
|
|
11687
12129
|
ConsoleLogger,
|
|
11688
12130
|
ContextCollector,
|
|
12131
|
+
DAEMON_SUBPROTOCOL,
|
|
12132
|
+
DAEMON_TOKEN_SUBPROTOCOL_PREFIX,
|
|
11689
12133
|
DENY_ALL,
|
|
11690
12134
|
EmbeddedNewlineError,
|
|
11691
12135
|
EnvConfig,
|
|
@@ -11702,9 +12146,12 @@ export {
|
|
|
11702
12146
|
ModelResolver,
|
|
11703
12147
|
OPENCODE_MANIFEST,
|
|
11704
12148
|
ORCHESTRATOR_SHORTCUTS,
|
|
12149
|
+
ORDEWELL_SETTABLE_ENV,
|
|
11705
12150
|
OpenAiService,
|
|
11706
12151
|
OpenCodeAdapter,
|
|
11707
12152
|
PLAN_ENVELOPE_KEY,
|
|
12153
|
+
PLUGIN_NAME_PATTERN,
|
|
12154
|
+
PROVIDER_CREDENTIAL_ENV,
|
|
11708
12155
|
PROVIDER_DETECT_PRIORITY,
|
|
11709
12156
|
PROVIDER_LABEL,
|
|
11710
12157
|
PROVIDER_PRIORITY,
|
|
@@ -11719,6 +12166,8 @@ export {
|
|
|
11719
12166
|
RunnerInstallation,
|
|
11720
12167
|
RunnerRegistry,
|
|
11721
12168
|
SEARCH_EXCLUSIONS,
|
|
12169
|
+
SETTINGS_ENV_ALLOWLIST,
|
|
12170
|
+
SETTINGS_ENV_REFUSED,
|
|
11722
12171
|
STATE_DIR,
|
|
11723
12172
|
STOPPED_TOOL_RESULT,
|
|
11724
12173
|
SYMBOL_LANGUAGES,
|
|
@@ -11731,13 +12180,19 @@ export {
|
|
|
11731
12180
|
TmuxRunner,
|
|
11732
12181
|
VerdictEngine,
|
|
11733
12182
|
WINDOWS_MAX_COMMAND_LINE,
|
|
12183
|
+
WorkspaceNotAProjectError,
|
|
11734
12184
|
WorkspaceNotFoundError,
|
|
11735
12185
|
addTaskToPlan,
|
|
12186
|
+
admitSettingsEnv,
|
|
11736
12187
|
applyHeadLimit,
|
|
11737
12188
|
applyTaskOps,
|
|
12189
|
+
assertInstallablePluginUrl,
|
|
12190
|
+
assertPlainPluginName,
|
|
11738
12191
|
assertWorkspaceExists,
|
|
12192
|
+
assertWorkspaceIsProject,
|
|
11739
12193
|
augmentPromptWithPriorOutputs,
|
|
11740
12194
|
augmentedPath,
|
|
12195
|
+
bearerHeaderValue,
|
|
11741
12196
|
buildConversationSystemPrompt,
|
|
11742
12197
|
buildFallbackGrepArgs,
|
|
11743
12198
|
buildGlobArgs,
|
|
@@ -11765,7 +12220,9 @@ export {
|
|
|
11765
12220
|
classifyCommand,
|
|
11766
12221
|
classifyOutcome,
|
|
11767
12222
|
classifyPlannerReply,
|
|
12223
|
+
classifyPluginSource,
|
|
11768
12224
|
clearAugmentedPathCache,
|
|
12225
|
+
clearDaemonToken,
|
|
11769
12226
|
clearResearchShellCache,
|
|
11770
12227
|
clearState,
|
|
11771
12228
|
clipboardCopyCommand,
|
|
@@ -11777,6 +12234,7 @@ export {
|
|
|
11777
12234
|
createAiService,
|
|
11778
12235
|
createEmptyPlan,
|
|
11779
12236
|
createTask,
|
|
12237
|
+
daemonTokenPath,
|
|
11780
12238
|
defaultLogger,
|
|
11781
12239
|
definitionPattern,
|
|
11782
12240
|
deleteSession,
|
|
@@ -11794,6 +12252,7 @@ export {
|
|
|
11794
12252
|
extractObjectWithBalance,
|
|
11795
12253
|
extractObjectsWithKey,
|
|
11796
12254
|
extractPrdBlock,
|
|
12255
|
+
extractPresentedToken,
|
|
11797
12256
|
fetchAllProviderModels,
|
|
11798
12257
|
filterFallbackByAnchoredInclude,
|
|
11799
12258
|
filterModelsForPrompt,
|
|
@@ -11811,6 +12270,9 @@ export {
|
|
|
11811
12270
|
isCliProvider,
|
|
11812
12271
|
isExecutableResolved,
|
|
11813
12272
|
isOpenAiProvider,
|
|
12273
|
+
isPlainPluginName,
|
|
12274
|
+
isReservedRunnerName,
|
|
12275
|
+
isValidManifest,
|
|
11814
12276
|
killTree,
|
|
11815
12277
|
knownModelId,
|
|
11816
12278
|
languageForId,
|
|
@@ -11823,6 +12285,8 @@ export {
|
|
|
11823
12285
|
migrateLegacyPlan,
|
|
11824
12286
|
migratePlanState,
|
|
11825
12287
|
migrateTask,
|
|
12288
|
+
mintDaemonToken,
|
|
12289
|
+
mintSessionId,
|
|
11826
12290
|
modelContextBlock,
|
|
11827
12291
|
modifyValidationFeedback,
|
|
11828
12292
|
normalizeAgentArgs,
|
|
@@ -11838,6 +12302,7 @@ export {
|
|
|
11838
12302
|
providerForRunner,
|
|
11839
12303
|
reEmitPlanPrompt,
|
|
11840
12304
|
reEmitTaskOpsPrompt,
|
|
12305
|
+
readDaemonToken,
|
|
11841
12306
|
referencePattern,
|
|
11842
12307
|
removeTaskFromPlan,
|
|
11843
12308
|
renderPlanMap,
|
|
@@ -11849,6 +12314,7 @@ export {
|
|
|
11849
12314
|
resolveArgs,
|
|
11850
12315
|
resolveDefaultMode,
|
|
11851
12316
|
resolveModelShortcut,
|
|
12317
|
+
resolvePluginInstallDir,
|
|
11852
12318
|
resolveProvider,
|
|
11853
12319
|
resolveProviderFromPrefix,
|
|
11854
12320
|
resolveResearchShell,
|
|
@@ -11879,6 +12345,8 @@ export {
|
|
|
11879
12345
|
tmuxSocketName,
|
|
11880
12346
|
tmuxWindowName,
|
|
11881
12347
|
toOrchestratorOptions,
|
|
12348
|
+
tokenSubprotocols,
|
|
12349
|
+
tokensMatch,
|
|
11882
12350
|
truncatedPlanReEmitPrompt,
|
|
11883
12351
|
updateTaskInPlan,
|
|
11884
12352
|
validateModifiedPlan,
|