omnirush 0.10.3 → 0.10.4

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.
@@ -199,11 +199,18 @@ export const ROLE_PRESETS: Record<AgentRole, RolePreset> = {
199
199
  },
200
200
  };
201
201
 
202
- /** Resolve the child entry: this running script + the current runtime. */
203
- export function childInvocation(args: string[]): {
202
+ /**
203
+ * Resolve the child entry: the core's entry as the launcher started it
204
+ * (OMNIRUSH_CORE_ENTRY: through <package>/engine, so process listings name
205
+ * omnirush; the runtime reports the resolved path in argv[1]), else this
206
+ * running script, with the current runtime.
207
+ */
208
+ export function childInvocation(args: string[], env: NodeJS.ProcessEnv = process.env): {
204
209
  command: string;
205
210
  args: string[];
206
211
  } {
212
+ const launched = (env.OMNIRUSH_CORE_ENTRY || "").trim();
213
+ if (launched && existsSync(launched)) return { command: process.execPath, args: [launched, ...args] };
207
214
  const currentScript = process.argv[1];
208
215
  const isBunVirtualScript = currentScript?.startsWith("/$bunfs/root/");
209
216
  if (currentScript && !isBunVirtualScript && existsSync(currentScript)) {
@@ -214,8 +221,8 @@ export function childInvocation(args: string[]): {
214
221
  if (!isGenericRuntime) {
215
222
  return { command: process.execPath, args };
216
223
  }
217
- // Packaged bun builds: fall back to the pi on PATH.
218
- return { command: "pi", args };
224
+ // Packaged bun builds: fall back to the omnirush on PATH (it forwards core flags).
225
+ return { command: "omnirush", args };
219
226
  }
220
227
 
221
228
  /** The folder, inside a session dir, that holds its sub-agents' sessions. */
@@ -5,11 +5,55 @@ const SECRET_ENV_NAMES = new Set([
5
5
  "OMNIRUSH_APPROVAL_TOKEN",
6
6
  ]);
7
7
 
8
- /** Keep provider credentials in the agent process, never in shell/MCP children. */
8
+ /**
9
+ * The agent core's own PI_<NAME> variables (src/compat.js
10
+ * CORE_ONLY_ENV_NAMES; a test keeps the lists equal). Shell commands and
11
+ * MCP servers see their OMNIRUSH_<NAME> copies only; any other PI_*
12
+ * variable (a user's own) passes through.
13
+ */
14
+ export const CORE_ONLY_ENV_NAMES = [
15
+ "CODING_AGENT",
16
+ "CODING_AGENT_DIR",
17
+ "CODING_AGENT_SESSION_DIR",
18
+ "SESSION_ID",
19
+ "SESSION_FILE",
20
+ "PROVIDER",
21
+ "MODEL",
22
+ "REASONING_LEVEL",
23
+ "OFFLINE",
24
+ "TELEMETRY",
25
+ "INSTALLER_API_BASE",
26
+ "MANAGED_INSTALL_ROOT",
27
+ "CACHE_RETENTION",
28
+ "CLEAR_ON_SHRINK",
29
+ "EXPERIMENTAL",
30
+ "HARDWARE_CURSOR",
31
+ "HYPERLINKS",
32
+ "IMAGE_PROTOCOL",
33
+ "OAUTH_CALLBACK_HOST",
34
+ "PACKAGE_DIR",
35
+ "RADIUS_GATEWAY",
36
+ "SHARE_VIEWER_URL",
37
+ "SKIP_VERSION_CHECK",
38
+ "STARTUP_BENCHMARK",
39
+ "TIMING",
40
+ "TRUE_COLOR",
41
+ "TUI_DEBUG",
42
+ "TUI_DEBUG_REDRAW",
43
+ "TUI_ESC_TIMEOUT",
44
+ "TUI_WRITE_LOG",
45
+ ];
46
+ const CORE_ONLY_ENV = new Set(CORE_ONLY_ENV_NAMES.map((name) => `PI_${name}`));
47
+
48
+ /**
49
+ * Keep provider credentials in the agent process, never in shell/MCP
50
+ * children; the core's PI_* variables stay there too (the children get the
51
+ * OMNIRUSH_* spellings).
52
+ */
9
53
  export function sanitizeToolEnvironment(input: NodeJS.ProcessEnv = process.env): NodeJS.ProcessEnv {
10
54
  const output: NodeJS.ProcessEnv = {};
11
55
  for (const [key, value] of Object.entries(input)) {
12
- if (!SECRET_ENV_NAMES.has(key) && value !== undefined) output[key] = value;
56
+ if (!SECRET_ENV_NAMES.has(key) && !CORE_ONLY_ENV.has(key) && value !== undefined) output[key] = value;
13
57
  }
14
58
  return output;
15
59
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnirush",
3
- "version": "0.10.3",
3
+ "version": "0.10.4",
4
4
  "description": "Omnirush — free daily tokens for the most powerful coding model on earth.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -23,10 +23,16 @@
23
23
  // folders), OMNIRUSH_* copies of the env the core exports to shell
24
24
  // commands, AI_AGENT, the HTTP User-Agent and temp-file names.
25
25
  //
26
+ // 4. <package>/engine, a link to the core (src/compat.js
27
+ // ensureEngineLink): the launcher runs the core through it, so process
28
+ // listings and the doc paths in the system prompt name omnirush, not
29
+ // the core's npm package.
30
+ //
26
31
  // Not renamed (internal, never shown): package ids and imports, code
27
32
  // identifiers, session entry/customType ids, telemetry attribute keys,
28
33
  // protocol values third-party providers expect, and the PI_* env names the
29
- // core reads (the launcher maps OMNIRUSH_* spellings onto them).
34
+ // core reads (the launcher maps OMNIRUSH_* spellings onto them; shells the
35
+ // core starts get the OMNIRUSH_* copies only).
30
36
  //
31
37
  // Maintenance: after bumping the core, run `node scripts/brand-engine.js`
32
38
  // and `node --test test/branding.test.js`; a target that moved is reported
@@ -38,11 +44,16 @@ import fs from "node:fs";
38
44
  import path from "node:path";
39
45
  import { fileURLToPath } from "node:url";
40
46
 
47
+ import { CORE_ONLY_ENV_NAMES, ensureEngineLink } from "../src/compat.js";
48
+
41
49
  const PKG = "@earendil-works/pi-coding-agent";
42
50
  const BRAND = "omnirush";
43
51
  export const BRAND_CONFIG_DIR = ".omnirush";
44
52
  const OUR_CHANGELOG = path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "assets", "CHANGELOG.md");
45
53
 
54
+ /** Matches the core's own PI_<NAME> variables (src/compat.js CORE_ONLY_ENV_NAMES), as JS regex source. */
55
+ export const CORE_ENV_PATTERN = `/^PI_(${CORE_ONLY_ENV_NAMES.join("|")})$/`;
56
+
46
57
  // `from` must match the installed dist exactly; applied with replaceAll to
47
58
  // every dist/**/*.js. A `to` must never contain its own `from` (idempotency).
48
59
  export const REPLACEMENTS = [
@@ -157,13 +168,37 @@ export const REPLACEMENTS = [
157
168
  {
158
169
  label: "/bug disclaimer",
159
170
  from: "This report goes to the Pi developers (Earendil) and is not shared publicly. It includes your pi version,",
160
- to: "This report goes to the agent core's upstream developers (Earendil) and is not shared publicly. It includes your omnirush version,",
171
+ to: "This report is not shared publicly. It includes your omnirush version,",
161
172
  },
162
173
  {
163
174
  label: "announcement easter egg",
164
175
  from: '"pi has joined Earendil"',
165
- to: '"The agent core has joined Earendil"',
176
+ to: '"omnirush"',
177
+ },
178
+ {
179
+ // Upstream easter eggs typed as commands (/arminsayshi, /dementedelves;
180
+ // the third only fires for one third-party model): shown nothing.
181
+ label: "hidden /arminsayshi is inert (bundle)",
182
+ from: "handleArminSaysHi(){",
183
+ to: "handleArminSaysHi(_off){return;",
184
+ },
185
+ {
186
+ label: "hidden /dementedelves is inert (bundle)",
187
+ from: "handleDementedDelves(){",
188
+ to: "handleDementedDelves(_off){return;",
166
189
  },
190
+ { label: "upstream easter egg is inert (bundle)", from: "handleDaxnuts(){", to: "handleDaxnuts(_off){return;" },
191
+ {
192
+ label: "hidden /arminsayshi is inert (dist)",
193
+ from: " handleArminSaysHi() {",
194
+ to: " handleArminSaysHi(_off) { return;",
195
+ },
196
+ {
197
+ label: "hidden /dementedelves is inert (dist)",
198
+ from: " handleDementedDelves() {",
199
+ to: " handleDementedDelves(_off) { return;",
200
+ },
201
+ { label: "upstream easter egg is inert (dist)", from: " handleDaxnuts() {", to: " handleDaxnuts(_off) { return;" },
167
202
  {
168
203
  label: "external editor note",
169
204
  from: "Pi will resume when the editor exits.",
@@ -345,7 +380,20 @@ export const REPLACEMENTS = [
345
380
  label: "OMNIRUSH_* session env for shell commands",
346
381
  from: "ctx.thinkingLevel&&(env2.PI_REASONING_LEVEL=ctx.thinkingLevel)}let baseContext={command,cwd,env:env2}",
347
382
  to:
348
- 'ctx.thinkingLevel&&(env2.PI_REASONING_LEVEL=ctx.thinkingLevel)}for(let k of["SESSION_ID","SESSION_FILE","PROVIDER","MODEL","REASONING_LEVEL"])env2["PI_"+k]===void 0?delete env2["OMNIRUSH_"+k]:env2["OMNIRUSH_"+k]=env2["PI_"+k];let baseContext={command,cwd,env:env2}',
383
+ 'ctx.thinkingLevel&&(env2.PI_REASONING_LEVEL=ctx.thinkingLevel)}for(let k of["SESSION_ID","SESSION_FILE","PROVIDER","MODEL","REASONING_LEVEL"])env2["PI_"+k]===void 0?delete env2["OMNIRUSH_"+k]:(env2["OMNIRUSH_"+k]=env2["PI_"+k],delete env2["PI_"+k]);let baseContext={command,cwd,env:env2}',
384
+ },
385
+ {
386
+ // The env every shell the core starts inherits (the bash tool, `!`
387
+ // commands, package installs): the core's own PI_* variables stay in
388
+ // the agent process; their OMNIRUSH_* copies are what commands see.
389
+ label: "no core PI_* variables in shell commands (bundle)",
390
+ from: "return{...process.env,[pathKey]:updatedPath}}function sanitizeBinaryOutput",
391
+ to: `let _env={...process.env,[pathKey]:updatedPath};for(let k of Object.keys(_env))${CORE_ENV_PATTERN}.test(k)&&delete _env[k];return _env}function sanitizeBinaryOutput`,
392
+ },
393
+ {
394
+ label: "no core PI_* variables in shell commands (dist)",
395
+ from: " return {\n ...process.env,\n [pathKey]: updatedPath,\n };\n}",
396
+ to: ` const _env = { ...process.env, [pathKey]: updatedPath };\n for (const k of Object.keys(_env)) if (${CORE_ENV_PATTERN}.test(k)) delete _env[k];\n return _env;\n}`,
349
397
  },
350
398
 
351
399
  // --- HTTP User-Agent (the omnirush gateway sees it) --------------------
@@ -377,6 +425,9 @@ export const REPLACEMENTS = [
377
425
  { label: "bug report zip", from: "`pi-bug-report-${id}.zip`", to: "`omnirush-bug-report-${id}.zip`" },
378
426
  { label: "TUI crash log", from: '"pi-tui-crash.log"', to: '"omnirush-tui-crash.log"' },
379
427
  { label: "TUI debug log", from: '"pi-tui-debug.log"', to: '"omnirush-tui-debug.log"' },
428
+ { label: "git package update marker", from: ".pi-update-incomplete", to: ".omnirush-update-incomplete" },
429
+ { label: "native module quarantine dir", from: '".pi-native-quarantine"', to: '".omnirush-native-quarantine"' },
430
+ { label: "package install root package.json name", from: '"pi-extensions"', to: '"omnirush-extensions"' },
380
431
 
381
432
  // --- update banner (belt-and-braces; the launcher sets PI_OFFLINE) -----
382
433
  // showNewVersionNotification returns before its body (the parameter is
@@ -507,6 +558,9 @@ function main() {
507
558
  console.log("omnirush: agent core not installed; skipped branding patch");
508
559
  return;
509
560
  }
561
+ // <package>/engine -> the core (what process listings and the system
562
+ // prompt's doc paths show; the launcher re-creates it when missing).
563
+ ensureEngineLink(repoRoot, report.piRoot);
510
564
  const patched = report.packageJsonPatched ? "package.json + " : "";
511
565
  const notes = report.changelogReplaced ? " + release notes" : "";
512
566
  console.log(
package/src/bin.js CHANGED
@@ -54,7 +54,7 @@ import {
54
54
  yoloBanner,
55
55
  } from "./lib.js";
56
56
  import { installManagedTools } from "./tools.js";
57
- import { engineEnvAliases, migrateAgentDir, projectConfigDirName, resolveAgentDir } from "./compat.js";
57
+ import { engineEnvAliases, ensureEngineLink, migrateAgentDir, projectConfigDirName, resolveAgentDir } from "./compat.js";
58
58
  import { customSessionDir, moveLegacySubagentSessions } from "./sessions.js";
59
59
  import { ensureRuntime, managedBunPath } from "../scripts/postinstall.js";
60
60
  import {
@@ -144,12 +144,31 @@ function piPackage() {
144
144
  return null;
145
145
  }
146
146
 
147
+ // The core as users see it (process listings, the doc paths in the system
148
+ // prompt, sub-agent command lines): <package>/engine, a link to the core's
149
+ // folder (src/compat.js ensureEngineLink); null when the link cannot be made.
150
+ let ENGINE_LINK_DIR = null;
151
+ let ENGINE_ENTRY = null;
152
+
147
153
  function piEntry() {
148
154
  const found = piPackage();
149
- if (found?.pkg?.bin?.pi) return path.join(found.dir, found.pkg.bin.pi);
155
+ if (found?.pkg?.bin?.pi) {
156
+ const dir = ensureEngineLink(path.resolve(__dirname, ".."), found.dir);
157
+ ENGINE_LINK_DIR = dir === path.resolve(found.dir) ? null : dir;
158
+ ENGINE_ENTRY = path.join(dir, found.pkg.bin.pi);
159
+ return ENGINE_ENTRY;
160
+ }
150
161
  throw new Error("could not locate the pinned agent core (broken install). Fix: npm install -g omnirush@latest");
151
162
  }
152
163
 
164
+ /** The core's package dir as the link, unless the user points it elsewhere. */
165
+ function engineDirEnv(env = process.env) {
166
+ const env2 = {};
167
+ if (ENGINE_ENTRY) env2.OMNIRUSH_CORE_ENTRY = ENGINE_ENTRY; // sub-agents start the core through the same path
168
+ if (ENGINE_LINK_DIR && !env.PI_PACKAGE_DIR && !env.OMNIRUSH_PACKAGE_DIR) env2.PI_PACKAGE_DIR = ENGINE_LINK_DIR;
169
+ return env2;
170
+ }
171
+
153
172
  function ensureDirs() {
154
173
  fs.mkdirSync(OMNI_DIR, { recursive: true, mode: 0o700 });
155
174
  migrateLegacyAgentData();
@@ -875,6 +894,7 @@ function childEnv(auth) {
875
894
  const origin = (process.env.OMNIRUSH_ORIGIN || "").trim().replace(/\/+$/, "") ||
876
895
  gateway.replace(/\/+$/, "").replace(/\/v1$/, ""); // provider base -> manager origin
877
896
  return {
897
+ ...engineDirEnv(process.env),
878
898
  // OMNIRUSH_* spellings of the core's own settings (PI_* still work).
879
899
  ...engineEnvAliases(process.env),
880
900
  // Bootstrap values only: the agent (and every sub-agent it spawns)
@@ -1090,8 +1110,7 @@ Environment:
1090
1110
  (default 50% of RAM), and none start below this
1091
1111
  (default 10%); e.g. 25% or 6G. OMNIRUSH_AGENT_MEMORY=off
1092
1112
  starts them without checking memory
1093
- OMNIRUSH_<SETTING> the agent core's own settings (e.g. OMNIRUSH_CACHE_RETENTION;
1094
- the older PI_<SETTING> names still work)
1113
+ OMNIRUSH_<SETTING> the agent core's own settings (e.g. OMNIRUSH_CACHE_RETENTION)
1095
1114
 
1096
1115
  Docs: https://omnirush.ai/omnirush — state is stored 0600 in ~/.omnirush`);
1097
1116
  }
package/src/compat.js CHANGED
@@ -270,3 +270,68 @@ export function engineEnvAliases(env = process.env) {
270
270
  }
271
271
  return out;
272
272
  }
273
+
274
+ /**
275
+ * The core's own variables the launcher and the core set for themselves
276
+ * (PI_<NAME>). Shell commands the agent runs, background jobs and MCP
277
+ * servers see their OMNIRUSH_<NAME> copies only; a PI_ variable that is
278
+ * not on this list (a user's own) passes through. Mirrored in
279
+ * scripts/brand-engine.js (the core's shell env) and
280
+ * assets/extensions/omnirush/secret-env.ts (tests keep them equal).
281
+ */
282
+ export const CORE_ONLY_ENV_NAMES = [
283
+ "CODING_AGENT",
284
+ "CODING_AGENT_DIR",
285
+ "CODING_AGENT_SESSION_DIR",
286
+ "SESSION_ID",
287
+ "SESSION_FILE",
288
+ "PROVIDER",
289
+ "MODEL",
290
+ "REASONING_LEVEL",
291
+ "OFFLINE",
292
+ "TELEMETRY",
293
+ "INSTALLER_API_BASE",
294
+ "MANAGED_INSTALL_ROOT",
295
+ ...ENGINE_ENV_NAMES,
296
+ ];
297
+
298
+ /** Folder, in the omnirush package, that links to the installed agent core. */
299
+ export const ENGINE_LINK = "engine";
300
+
301
+ /**
302
+ * The agent core as users see it: <package root>/engine, a link to the
303
+ * core's folder in node_modules (a junction on Windows). The launcher runs
304
+ * the core through it and hands it over as the core's package dir, so
305
+ * process listings, the doc paths in the system prompt and the sub-agent
306
+ * command lines name omnirush instead of the core's npm package. Made by
307
+ * the branding step at install and, when missing (archives, a read-only
308
+ * reinstall), here at launch. Never replaces a real folder. Returns the
309
+ * link, or the core's own folder when the link cannot be made.
310
+ */
311
+ export function ensureEngineLink(packageRoot, coreDir, { fsImpl = fs, platform = process.platform } = {}) {
312
+ const link = path.join(packageRoot, ENGINE_LINK);
313
+ const real = path.resolve(coreDir);
314
+ const points = () => {
315
+ try {
316
+ return fsImpl.realpathSync(link) === fsImpl.realpathSync(real);
317
+ } catch {
318
+ return false;
319
+ }
320
+ };
321
+ if (points()) return link;
322
+ try {
323
+ let stat = null;
324
+ try {
325
+ stat = fsImpl.lstatSync(link);
326
+ } catch {
327
+ /* absent */
328
+ }
329
+ if (stat && !stat.isSymbolicLink()) return real;
330
+ if (stat) fsImpl.unlinkSync(link); // a stale link (the core moved)
331
+ if (platform === "win32") fsImpl.symlinkSync(real, link, "junction");
332
+ else fsImpl.symlinkSync(path.relative(path.dirname(link), real) || ".", link, "dir");
333
+ } catch {
334
+ /* read-only install or a concurrent launch: checked below */
335
+ }
336
+ return points() ? link : real;
337
+ }