@ordewell/core 0.4.3 → 0.4.5
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-Bbpe8uts.d.ts → ITerminalRunner-D7DwHYSg.d.ts} +15 -1
- package/dist/{ITerminalRunner-D8Bf-HD4.d.mts → ITerminalRunner-YMVsbfem.d.mts} +15 -1
- package/dist/index.d.mts +35 -13
- package/dist/index.d.ts +35 -13
- package/dist/index.js +129 -37
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +128 -37
- 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
|
@@ -9890,8 +9890,12 @@ var Block = /* @__PURE__ */ ((Block2) => {
|
|
|
9890
9890
|
Block2[Block2["IfInteractive"] = 7] = "IfInteractive";
|
|
9891
9891
|
Block2[Block2["IfHeadlessSession"] = 8] = "IfHeadlessSession";
|
|
9892
9892
|
Block2[Block2["IfInteractiveVariant"] = 9] = "IfInteractiveVariant";
|
|
9893
|
+
Block2[Block2["IfProjectTrust"] = 10] = "IfProjectTrust";
|
|
9893
9894
|
return Block2;
|
|
9894
9895
|
})(Block || {});
|
|
9896
|
+
function isInteractive(ctx) {
|
|
9897
|
+
return ctx.interactive ?? !ctx.headless;
|
|
9898
|
+
}
|
|
9895
9899
|
function resolveArgs(manifest, ctx) {
|
|
9896
9900
|
const args = [];
|
|
9897
9901
|
const env = {};
|
|
@@ -9960,6 +9964,8 @@ function parseBlockOpen(raw) {
|
|
|
9960
9964
|
return 8 /* IfHeadlessSession */;
|
|
9961
9965
|
case "{{if interactiveVariant}}":
|
|
9962
9966
|
return 9 /* IfInteractiveVariant */;
|
|
9967
|
+
case "{{if projectTrust}}":
|
|
9968
|
+
return 10 /* IfProjectTrust */;
|
|
9963
9969
|
default:
|
|
9964
9970
|
return null;
|
|
9965
9971
|
}
|
|
@@ -9981,19 +9987,24 @@ function shouldIncludeBlock(block, ctx) {
|
|
|
9981
9987
|
// `--variant` is a headless-only flag: it exists on `opencode run` but not
|
|
9982
9988
|
// on the interactive TUI, which exits immediately if handed an unknown flag.
|
|
9983
9989
|
case 6 /* IfVariant */:
|
|
9984
|
-
return !!ctx.thinkingEffort &&
|
|
9990
|
+
return !!ctx.thinkingEffort && !isInteractive(ctx);
|
|
9985
9991
|
// Session-shape blocks: unlike IfHeadless (a permission-flag gate with a
|
|
9986
9992
|
// plan-mode carve-out), these pick the CLI invocation shape — e.g.
|
|
9987
9993
|
// opencode's `run` subcommand vs its interactive TUI — so no mode carve-out.
|
|
9988
9994
|
case 7 /* IfInteractive */:
|
|
9989
|
-
return
|
|
9995
|
+
return isInteractive(ctx);
|
|
9990
9996
|
case 8 /* IfHeadlessSession */:
|
|
9991
|
-
return
|
|
9997
|
+
return !isInteractive(ctx);
|
|
9992
9998
|
// Interactive counterpart of IfVariant, for runners whose TUI has no
|
|
9993
9999
|
// variant flag and must receive the variant via env config instead.
|
|
9994
10000
|
// Requires a provider-prefixed model: the config pins variant per model.
|
|
9995
10001
|
case 9 /* IfInteractiveVariant */:
|
|
9996
|
-
return !!ctx.thinkingEffort && !!ctx.model?.includes("/") &&
|
|
10002
|
+
return !!ctx.thinkingEffort && !!ctx.model?.includes("/") && isInteractive(ctx);
|
|
10003
|
+
// Guards the flag/value pair that pre-trusts the workspace directory. The
|
|
10004
|
+
// condition, not the token, is what keeps a bare `-c` out of the args when
|
|
10005
|
+
// there is no cwd to name.
|
|
10006
|
+
case 10 /* IfProjectTrust */:
|
|
10007
|
+
return isInteractive(ctx) && !!ctx.cwd;
|
|
9997
10008
|
default:
|
|
9998
10009
|
return true;
|
|
9999
10010
|
}
|
|
@@ -10014,6 +10025,10 @@ function resolveToken(token, manifest, ctx) {
|
|
|
10014
10025
|
if (token === "{{model}}") return ctx.model || "";
|
|
10015
10026
|
if (token === "{{thinkingEffort}}") return ctx.thinkingEffort || "";
|
|
10016
10027
|
if (token === "{{mode}}") return ctx.mode || "build";
|
|
10028
|
+
if (token === "{{projectTrust}}") {
|
|
10029
|
+
if (!ctx.cwd) return "";
|
|
10030
|
+
return `projects.${JSON.stringify(ctx.cwd)}.trust_level="trusted"`;
|
|
10031
|
+
}
|
|
10017
10032
|
if (token === "{{feature:thinking}}") {
|
|
10018
10033
|
return manifest.features.thinkingFlag || "";
|
|
10019
10034
|
}
|
|
@@ -10100,7 +10115,9 @@ function buildRunnerInvocation(opts) {
|
|
|
10100
10115
|
thinkingEffort: opts.thinkingEffort,
|
|
10101
10116
|
modelVariants: opts.modelVariants,
|
|
10102
10117
|
mode: opts.mode ?? "build",
|
|
10103
|
-
headless: opts.headless
|
|
10118
|
+
headless: opts.headless,
|
|
10119
|
+
interactive: opts.interactive,
|
|
10120
|
+
cwd: opts.cwd
|
|
10104
10121
|
});
|
|
10105
10122
|
}
|
|
10106
10123
|
|
|
@@ -10221,8 +10238,14 @@ var HeadlessRunner = class extends AbstractRunner {
|
|
|
10221
10238
|
hasScriptCmd;
|
|
10222
10239
|
resolvePath;
|
|
10223
10240
|
launchDeps;
|
|
10224
|
-
/**
|
|
10225
|
-
|
|
10241
|
+
/**
|
|
10242
|
+
* Session shape: a piped subprocess is not a terminal, so runners get their
|
|
10243
|
+
* non-interactive subcommand. The VS Code runner owns a pseudoterminal and
|
|
10244
|
+
* overrides this to true. Autonomy is a separate axis (see `ResolveContext`)
|
|
10245
|
+
* and stays on either way — no surface has a human answering permission
|
|
10246
|
+
* prompts on the orchestrator's behalf.
|
|
10247
|
+
*/
|
|
10248
|
+
defaultInteractive = false;
|
|
10226
10249
|
constructor(deps = {}) {
|
|
10227
10250
|
super();
|
|
10228
10251
|
this.spawnImpl = deps.spawnImpl ?? nodeSpawn2;
|
|
@@ -10235,7 +10258,7 @@ var HeadlessRunner = class extends AbstractRunner {
|
|
|
10235
10258
|
}
|
|
10236
10259
|
/** Everything up to, but not including, spawning — so a surface that owns its own child reaches the same decisions. */
|
|
10237
10260
|
async prepareLaunch(opts) {
|
|
10238
|
-
const
|
|
10261
|
+
const interactive = this.defaultInteractive;
|
|
10239
10262
|
const invocation = buildRunnerInvocation({
|
|
10240
10263
|
runner: opts.runner,
|
|
10241
10264
|
prompt: opts.prompt,
|
|
@@ -10243,11 +10266,13 @@ var HeadlessRunner = class extends AbstractRunner {
|
|
|
10243
10266
|
thinkingEffort: opts.thinkingEffort,
|
|
10244
10267
|
modelVariants: opts.modelVariants,
|
|
10245
10268
|
mode: opts.mode,
|
|
10246
|
-
headless,
|
|
10269
|
+
headless: opts.headless ?? true,
|
|
10270
|
+
interactive,
|
|
10271
|
+
cwd: opts.cwd,
|
|
10247
10272
|
registry: opts.registry
|
|
10248
10273
|
});
|
|
10249
10274
|
const manifest = opts.registry?.get(opts.runner)?.manifest;
|
|
10250
|
-
const pty = (manifest?.runner.requiresTty === true ||
|
|
10275
|
+
const pty = (manifest?.runner.requiresTty === true || interactive) && this.hasScriptCmd();
|
|
10251
10276
|
const resolvedPath = await this.resolvePath();
|
|
10252
10277
|
const { command, args } = pty ? wrapWithPty(invocation.command, invocation.args) : { command: invocation.command, args: invocation.args };
|
|
10253
10278
|
return {
|
|
@@ -10300,6 +10325,28 @@ function hasTmux(probe = defaultProbe) {
|
|
|
10300
10325
|
return false;
|
|
10301
10326
|
}
|
|
10302
10327
|
}
|
|
10328
|
+
var defaultHasBin = (bin) => {
|
|
10329
|
+
try {
|
|
10330
|
+
execSync2(`${process.platform === "win32" ? "where" : "which"} ${bin}`, { stdio: "ignore" });
|
|
10331
|
+
return true;
|
|
10332
|
+
} catch {
|
|
10333
|
+
return false;
|
|
10334
|
+
}
|
|
10335
|
+
};
|
|
10336
|
+
function clipboardCopyCommand(hasBin = defaultHasBin, platform = process.platform, env = process.env) {
|
|
10337
|
+
const candidates = platform === "darwin" ? [["pbcopy", "pbcopy"]] : platform === "win32" ? [["clip.exe", "clip.exe"]] : [
|
|
10338
|
+
// Only prefer wl-copy when there is a Wayland display to talk to —
|
|
10339
|
+
// on X11 it is often installed but fails at copy time.
|
|
10340
|
+
...env.WAYLAND_DISPLAY ? [["wl-copy", "wl-copy"]] : [],
|
|
10341
|
+
["xclip", "xclip -selection clipboard"],
|
|
10342
|
+
["xsel", "xsel --clipboard --input"],
|
|
10343
|
+
["wl-copy", "wl-copy"]
|
|
10344
|
+
];
|
|
10345
|
+
for (const [bin, command] of candidates) {
|
|
10346
|
+
if (hasBin(bin)) return command;
|
|
10347
|
+
}
|
|
10348
|
+
return null;
|
|
10349
|
+
}
|
|
10303
10350
|
|
|
10304
10351
|
// src/services/TmuxRunner.ts
|
|
10305
10352
|
var EXIT_RE = /<<<ORDEWELL_TMUX_EXIT:(\d+)>>>/;
|
|
@@ -10409,6 +10456,7 @@ var TmuxRunner = class extends AbstractRunner {
|
|
|
10409
10456
|
resolvePath;
|
|
10410
10457
|
pollIntervalMs;
|
|
10411
10458
|
logDir;
|
|
10459
|
+
clipboardCommand;
|
|
10412
10460
|
/** Retries get a freshly named window so a failed attempt's output stays inspectable. */
|
|
10413
10461
|
attempts = /* @__PURE__ */ new Map();
|
|
10414
10462
|
ready = null;
|
|
@@ -10420,6 +10468,7 @@ var TmuxRunner = class extends AbstractRunner {
|
|
|
10420
10468
|
this.resolvePath = deps.resolvePath ?? augmentedPath;
|
|
10421
10469
|
this.pollIntervalMs = deps.pollIntervalMs ?? 500;
|
|
10422
10470
|
this.logDir = deps.logDir ?? tmpdir();
|
|
10471
|
+
this.clipboardCommand = deps.clipboardCommand ?? (() => clipboardCopyCommand());
|
|
10423
10472
|
}
|
|
10424
10473
|
/**
|
|
10425
10474
|
* Reaps a session orphaned by a crashed prior daemon on the same port, then
|
|
@@ -10448,25 +10497,44 @@ var TmuxRunner = class extends AbstractRunner {
|
|
|
10448
10497
|
await this.configureScrolling();
|
|
10449
10498
|
}
|
|
10450
10499
|
/**
|
|
10451
|
-
*
|
|
10452
|
-
*
|
|
10453
|
-
*
|
|
10454
|
-
*
|
|
10455
|
-
*
|
|
10456
|
-
*
|
|
10457
|
-
*
|
|
10458
|
-
*
|
|
10500
|
+
* Gives an attached runner terminal wheel/PageUp scrolling over a deep
|
|
10501
|
+
* scrollback, and a mouse selection that reaches the system clipboard — none
|
|
10502
|
+
* of which a default tmux session does. Server-wide scoping is harmless: the
|
|
10503
|
+
* daemon owns a private socket (`tmuxSocketName`).
|
|
10504
|
+
*
|
|
10505
|
+
* `mouse on` is what costs the emulator's own drag-select, so tmux must hand
|
|
10506
|
+
* the selection back out itself: via a clipboard binary when there is one,
|
|
10507
|
+
* and via OSC 52 (`set-clipboard`) for what that cannot cover, such as
|
|
10508
|
+
* viewing over SSH. Naming the binary on the binding as well as in
|
|
10509
|
+
* `copy-command` keeps drag-to-copy working on tmux older than 3.2, which has
|
|
10510
|
+
* no `copy-command`.
|
|
10459
10511
|
*/
|
|
10460
10512
|
async configureScrolling() {
|
|
10461
|
-
|
|
10462
|
-
|
|
10463
|
-
|
|
10464
|
-
|
|
10465
|
-
|
|
10466
|
-
|
|
10467
|
-
|
|
10468
|
-
|
|
10469
|
-
|
|
10513
|
+
const clip = this.clipboardCommand();
|
|
10514
|
+
const copySelection = clip ? ["copy-pipe-and-cancel", clip] : ["copy-pipe-and-cancel"];
|
|
10515
|
+
const commands = [
|
|
10516
|
+
// `history-limit` only governs windows created after it is set, so it
|
|
10517
|
+
// must run before any `new-window` — once, here at session creation.
|
|
10518
|
+
["set-option", "-g", "history-limit", "100000"],
|
|
10519
|
+
["set-option", "-g", "mouse", "on"],
|
|
10520
|
+
["set-option", "-g", "set-clipboard", "on"],
|
|
10521
|
+
...clip ? [["set-option", "-g", "copy-command", clip]] : [],
|
|
10522
|
+
["bind-key", "-T", "copy-mode", "MouseDragEnd1Pane", "send-keys", "-X", ...copySelection],
|
|
10523
|
+
["bind-key", "-T", "copy-mode-vi", "MouseDragEnd1Pane", "send-keys", "-X", ...copySelection],
|
|
10524
|
+
// Root-table PageUp; otherwise the key goes to the inner app and never
|
|
10525
|
+
// reaches tmux's scrollback. Both mode tables, so `mode-keys` can't
|
|
10526
|
+
// decide whether paging works.
|
|
10527
|
+
["bind-key", "-n", "PageUp", "copy-mode", "-u"],
|
|
10528
|
+
["bind-key", "-T", "copy-mode", "PageUp", "send-keys", "-X", "page-up"],
|
|
10529
|
+
["bind-key", "-T", "copy-mode", "PageDown", "send-keys", "-X", "page-down"],
|
|
10530
|
+
["bind-key", "-T", "copy-mode-vi", "PageUp", "send-keys", "-X", "page-up"],
|
|
10531
|
+
["bind-key", "-T", "copy-mode-vi", "PageDown", "send-keys", "-X", "page-down"]
|
|
10532
|
+
];
|
|
10533
|
+
for (const args of commands) {
|
|
10534
|
+
try {
|
|
10535
|
+
await this.tmux(args);
|
|
10536
|
+
} catch {
|
|
10537
|
+
}
|
|
10470
10538
|
}
|
|
10471
10539
|
}
|
|
10472
10540
|
/**
|
|
@@ -10491,7 +10559,14 @@ var TmuxRunner = class extends AbstractRunner {
|
|
|
10491
10559
|
thinkingEffort: opts.thinkingEffort,
|
|
10492
10560
|
modelVariants: opts.modelVariants,
|
|
10493
10561
|
mode: opts.mode,
|
|
10562
|
+
// A tmux window is a real TTY the user can attach to (ADR-0007), so the
|
|
10563
|
+
// runner's own TUI is the point — `interactive`. It is still an
|
|
10564
|
+
// unattended run, so autonomy stays on: the two are separate axes, and
|
|
10565
|
+
// conflating them is what made Codex tasks stream `codex exec` output
|
|
10566
|
+
// into a window that was supposed to show its TUI.
|
|
10494
10567
|
headless: opts.headless ?? true,
|
|
10568
|
+
interactive: true,
|
|
10569
|
+
cwd: opts.cwd,
|
|
10495
10570
|
registry: opts.registry
|
|
10496
10571
|
});
|
|
10497
10572
|
await this.ensureSession();
|
|
@@ -10729,18 +10804,33 @@ var CODEX_MANIFEST = {
|
|
|
10729
10804
|
version: "1.0.0",
|
|
10730
10805
|
runner: {
|
|
10731
10806
|
command: "codex",
|
|
10732
|
-
// Headless surfaces (
|
|
10733
|
-
// (`--skip-git-repo-check`: task workspaces aren't always git
|
|
10734
|
-
// exec hard-fails outside one by default); interactive surfaces
|
|
10735
|
-
// terminal) launch the TUI with the prompt as
|
|
10736
|
-
// Reasoning effort has no dedicated flag — it
|
|
10737
|
-
// override (see {{feature:reasoningEffortConfig}}).
|
|
10738
|
-
// TUI accept `-m`, `-c`, and `--sandbox`.
|
|
10807
|
+
// Headless surfaces (a piped subprocess) use the non-interactive `exec`
|
|
10808
|
+
// subcommand (`--skip-git-repo-check`: task workspaces aren't always git
|
|
10809
|
+
// repos, and exec hard-fails outside one by default); interactive surfaces
|
|
10810
|
+
// (a tmux window, the VS Code terminal) launch the TUI with the prompt as
|
|
10811
|
+
// its positional argument. Reasoning effort has no dedicated flag — it
|
|
10812
|
+
// travels as a `-c` config override (see {{feature:reasoningEffortConfig}}).
|
|
10813
|
+
// Both `exec` and the TUI accept `-m`, `-c`, and `--sandbox`.
|
|
10814
|
+
//
|
|
10815
|
+
// The two interactive-only entries restore what `exec` gives implicitly and
|
|
10816
|
+
// the TUI does not: `exec` is non-interactive, so it can neither ask for
|
|
10817
|
+
// command approval nor ask whether the directory is trusted. The TUI asks
|
|
10818
|
+
// for both by default, and an orchestrated task has nobody to answer —
|
|
10819
|
+
// without these it stalls on a menu instead of working. `-a` does not exist
|
|
10820
|
+
// on `exec`, hence the shape gate rather than a `{{if headless}}` one.
|
|
10739
10821
|
argsTemplate: [
|
|
10740
10822
|
"{{if headlessSession}}",
|
|
10741
10823
|
"exec",
|
|
10742
10824
|
"--skip-git-repo-check",
|
|
10743
10825
|
"{{/if}}",
|
|
10826
|
+
"{{if interactive}}",
|
|
10827
|
+
"-a",
|
|
10828
|
+
"never",
|
|
10829
|
+
"{{/if}}",
|
|
10830
|
+
"{{if projectTrust}}",
|
|
10831
|
+
"-c",
|
|
10832
|
+
"{{projectTrust}}",
|
|
10833
|
+
"{{/if}}",
|
|
10744
10834
|
"{{if model}}",
|
|
10745
10835
|
"-m",
|
|
10746
10836
|
"{{model}}",
|
|
@@ -10760,9 +10850,9 @@ var CODEX_MANIFEST = {
|
|
|
10760
10850
|
planMode: true,
|
|
10761
10851
|
planModeFlag: "--sandbox",
|
|
10762
10852
|
permissionModeValues: {
|
|
10763
|
-
// Map mode IDs to --sandbox CLI values.
|
|
10764
|
-
//
|
|
10765
|
-
// story for
|
|
10853
|
+
// Map mode IDs to --sandbox CLI values. Approvals are off on both shapes
|
|
10854
|
+
// (implicitly under `exec`, via `-a never` in the TUI), so the sandbox
|
|
10855
|
+
// axis is the whole permission story for a Codex task.
|
|
10766
10856
|
"agent": "workspace-write",
|
|
10767
10857
|
"plan": "read-only",
|
|
10768
10858
|
"fullAccess": "danger-full-access",
|
|
@@ -11369,6 +11459,7 @@ export {
|
|
|
11369
11459
|
clearAugmentedPathCache,
|
|
11370
11460
|
clearResearchShellCache,
|
|
11371
11461
|
clearState,
|
|
11462
|
+
clipboardCopyCommand,
|
|
11372
11463
|
coerceAssignments,
|
|
11373
11464
|
collectDirectDependencyOutputs,
|
|
11374
11465
|
collectProviderCredentials,
|