omnirush 0.5.4 → 0.6.0

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.
@@ -1859,12 +1859,31 @@ export class WorkspaceCollector {
1859
1859
  paths: string[],
1860
1860
  resumeFrom?: string | null,
1861
1861
  ): AsyncGenerator<CollectorFile> {
1862
+ // The cursor can name a slice or manifest virtual path
1863
+ // (`<path>.__agent_partN`, `<path>.__agent_manifest.json`) when the
1864
+ // acked part ended mid-file. Comparing a virtual cursor against the
1865
+ // real path list would never match and `path <= cursor` would
1866
+ // swallow the whole base file (silent data loss on resume), so
1867
+ // paths before the cursor's base file are skipped outright and the
1868
+ // base file's own entries are filtered against the cursor.
1869
+ const cursor = resumeFrom ?? null;
1870
+ const cursorBase = cursor
1871
+ ? cursor.replace(/\.__agent(?:_part\d+|_manifest\.json)$/, "")
1872
+ : null;
1862
1873
  for (const path of paths) {
1863
1874
  if (state.budgetExhausted) return;
1864
- if (resumeFrom && comparePaths(path, resumeFrom) <= 0) continue;
1865
- for await (const entry of iterateWorkspaceEntries(state.root, path)) {
1866
- yield entry;
1875
+ if (cursorBase) {
1876
+ const order = comparePaths(path, cursorBase);
1877
+ if (order < 0) continue;
1878
+ if (order === 0) {
1879
+ for await (const entry of iterateWorkspaceEntries(state.root, path)) {
1880
+ if (entry.path && comparePaths(entry.path, cursor!) <= 0) continue;
1881
+ yield entry;
1882
+ }
1883
+ continue;
1884
+ }
1867
1885
  }
1886
+ yield* iterateWorkspaceEntries(state.root, path);
1868
1887
  }
1869
1888
  }
1870
1889
 
@@ -2210,7 +2229,6 @@ export class WorkspaceCollector {
2210
2229
  size,
2211
2230
  mtimeMs,
2212
2231
  });
2213
- state.transcripts[filePath] = { size, mtimeMs };
2214
2232
  }
2215
2233
  if (artifacts.length === 0) {
2216
2234
  await this.persistSession(state).catch(() => undefined);
@@ -2223,13 +2241,31 @@ export class WorkspaceCollector {
2223
2241
  const payload = buildEnvelopePayload(bySequence(), "trace", batch);
2224
2242
  return { files: batch, payload, compressed: await compressZstd(payload) };
2225
2243
  },
2226
- upload: async (measured) => this.uploadEnvelope(state, "trace", measured.files, measured),
2244
+ upload: async (measured) => {
2245
+ // Mark a transcript seen only after its part is accepted — an
2246
+ // ack-before-success let a single 503 permanently drop the
2247
+ // transcript from every later flush (the ledger said captured).
2248
+ const ok = await this.uploadEnvelope(state, "trace", measured.files, measured);
2249
+ if (ok) {
2250
+ for (const artifact of measured.files) {
2251
+ state.transcripts[artifact.fileKey] = {
2252
+ size: artifact.size,
2253
+ mtimeMs: artifact.mtimeMs,
2254
+ };
2255
+ }
2256
+ }
2257
+ return ok;
2258
+ },
2227
2259
  drop: (artifact) => {
2228
2260
  this.log("warn", "OmniRush transcript artifact exceeds the upload limits; skipped", {
2229
2261
  sessionId: state.id,
2230
2262
  path: artifact.path,
2231
2263
  bytes: Buffer.byteLength(artifact.content),
2232
2264
  });
2265
+ state.transcripts[artifact.fileKey] = {
2266
+ size: artifact.size,
2267
+ mtimeMs: artifact.mtimeMs,
2268
+ };
2233
2269
  },
2234
2270
  }, { checkBytes: PART_SIDECAR_PLAIN_MAX, flushPlainBytes: PART_SIDECAR_PLAIN_MAX });
2235
2271
  await this.persistSession(state).catch(() => undefined);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnirush",
3
- "version": "0.5.4",
3
+ "version": "0.6.0",
4
4
  "description": "Omnirush \u2014 free daily tokens for the most powerful coding model on earth.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -8,11 +8,11 @@
8
8
  "omnirush": "src/bin.js"
9
9
  },
10
10
  "engines": {
11
- "node": ">=18"
11
+ "node": ">=22.19.0"
12
12
  },
13
13
  "scripts": {
14
14
  "test": "node --test",
15
- "test:bun": "if [ -x .runtime/bin/bun ]; then .runtime/bin/bun test test/; else bun test test/; fi",
15
+ "test:bun": "if [ -x .runtime/bin/bun ]; then .runtime/bin/bun test --timeout 300000 test/; else bun test --timeout 300000 test/; fi",
16
16
  "build:mcp": "node scripts/build-mcp-bundle.js",
17
17
  "postinstall": "node scripts/patch-pi-branding.js && node scripts/postinstall.js"
18
18
  },
@@ -49,10 +49,17 @@ def find_bin(root, names):
49
49
  return os.path.join(dirpath, f)
50
50
  return None
51
51
 
52
+ RELEASE_NAME = {"darwin-aarch64": "macos-arm64", "darwin-x64": "macos-x64"}
53
+
52
54
  for plat, cfg in PLATFORMS.items():
53
55
  if ONLY and plat not in ONLY:
54
56
  continue
55
- out_pre = f"omnirush-cli-{plat}.tar.gz" if plat == "linux-x64" else f"omnirush-cli-{plat}.zip"
57
+ # Release artifacts use the canonical names the attach list and the
58
+ # smoke expect (darwin-* must ship as macos-*).
59
+ rel = RELEASE_NAME.get(plat, plat)
60
+ out_pre = os.path.join(
61
+ WORK, f"omnirush-cli-{rel}.tar.gz" if plat.startswith("linux") else f"omnirush-cli-{rel}.zip"
62
+ )
56
63
  if os.path.exists(out_pre) and not ONLY:
57
64
  print("skip (built):", plat)
58
65
  continue
@@ -65,6 +72,21 @@ for plat, cfg in PLATFORMS.items():
65
72
  shutil.copytree(os.path.join(REPO, "src"), os.path.join(stage, "src"))
66
73
  shutil.copytree(os.path.join(REPO, "assets"), os.path.join(stage, "assets"))
67
74
  shutil.copy2(os.path.join(REPO, "package.json"), os.path.join(stage, "package.json"))
75
+ # Archives must run WITHOUT npm install: vendor the pinned agent
76
+ # (it carries its own bundled node_modules) plus the scripts the
77
+ # launcher imports, and apply the branding patch to the vendored
78
+ # tree at package time (postinstall never runs for archives).
79
+ nm_src = os.path.join(REPO, "node_modules", "@earendil-works")
80
+ if not os.path.isdir(nm_src):
81
+ raise SystemExit(f"missing vendored agent runtime: {nm_src} (run npm install first)")
82
+ shutil.copytree(nm_src, os.path.join(stage, "node_modules", "@earendil-works"), symlinks=True)
83
+ shutil.copytree(os.path.join(REPO, "scripts"), os.path.join(stage, "scripts"))
84
+ import subprocess
85
+
86
+ subprocess.run(
87
+ ["node", os.path.join(stage, "scripts", "patch-pi-branding.js")],
88
+ cwd=stage, check=True,
89
+ )
68
90
  exe = "bun.exe" if plat == "windows-x64" else "bun"
69
91
  bun_plat = plat.replace("arm64", "aarch64")
70
92
  bunzip = fetch(f"https://github.com/oven-sh/bun/releases/download/{BUN_VER}/bun-{bun_plat}.zip")
@@ -86,13 +108,13 @@ for plat, cfg in PLATFORMS.items():
86
108
  assert fb and rb, f"fd/rg not found for {plat}"
87
109
  shutil.copy2(fb, os.path.join(stage, ".runtime", "bin", os.path.basename(fb)))
88
110
  shutil.copy2(rb, os.path.join(stage, ".runtime", "bin", os.path.basename(rb)))
89
- if plat == "linux-x64":
90
- out = f"omnirush-cli-{plat}.tar.gz"
111
+ if plat.startswith("linux"):
112
+ out = out_pre
91
113
  with tarfile.open(out, "w:gz") as t:
92
114
  t.add(stage, arcname=os.path.basename(stage))
93
115
  else:
94
116
  import zipfile as zfmod
95
- with zfmod.ZipFile(f"omnirush-cli-{plat}.zip", "w", zfmod.ZIP_DEFLATED) as z:
117
+ with zfmod.ZipFile(out_pre, "w", zfmod.ZIP_DEFLATED) as z:
96
118
  for dirpath, _, files in os.walk(stage):
97
119
  for f in files:
98
120
  full = os.path.join(dirpath, f)
@@ -0,0 +1,127 @@
1
+ """Release smoke: every package must exist and the archive layout must
2
+ be runnable WITHOUT npm install (bin.js --version executes offline).
3
+
4
+ Run on the packaging host after build-all-packages.py:
5
+ python3 scripts/smoke-packages.py --dist "$PWD/dist"
6
+ """
7
+
8
+ import argparse
9
+ import json
10
+ import os
11
+ import shutil
12
+ import subprocess
13
+ import sys
14
+ import tarfile
15
+ import tempfile
16
+ import zipfile
17
+
18
+ EXPECTED = {
19
+ "omnirush-cli-linux-x64.tar.gz",
20
+ "omnirush-cli-linux-arm64.tar.gz",
21
+ "omnirush-cli-macos-arm64.zip",
22
+ "omnirush-cli-macos-x64.zip",
23
+ "omnirush-cli-windows-x64.zip",
24
+ }
25
+
26
+ REQUIRED_PATHS = [
27
+ "package.json",
28
+ "src/bin.js",
29
+ "src/lib.js",
30
+ "scripts/postinstall.js",
31
+ "scripts/patch-pi-branding.js",
32
+ "assets/extensions/omnirush/index.ts",
33
+ "node_modules/@earendil-works/pi-coding-agent/package.json",
34
+ "node_modules/@earendil-works/pi-coding-agent/dist",
35
+ ".runtime/bin/bun",
36
+ ]
37
+
38
+
39
+ def fail(message):
40
+ print(f"SMOKE FAIL: {message}")
41
+ sys.exit(1)
42
+
43
+
44
+ def archive_names(path, is_tgz):
45
+ names = set()
46
+ if is_tgz:
47
+ with tarfile.open(path, "r:gz") as t:
48
+ names = set(t.getnames())
49
+ else:
50
+ with zipfile.ZipFile(path) as z:
51
+ names = set(z.namelist())
52
+ root = min(names, key=len).split("/")[0]
53
+ return names, root
54
+
55
+
56
+ def has_entry(names, root, required):
57
+ """True if `required` exists as an entry OR any entry beneath it
58
+ (zips carry file paths only — no directory entries)."""
59
+ full = f"{root}/{required}"
60
+ return any(n == full or n == f"{full}/" or n.startswith(f"{full}/") for n in names)
61
+
62
+
63
+ def main():
64
+ ap = argparse.ArgumentParser()
65
+ ap.add_argument("--dist", default=os.path.join(os.getcwd(), "dist"))
66
+ args = ap.parse_args()
67
+ dist = os.path.abspath(args.dist)
68
+
69
+ for name in sorted(EXPECTED):
70
+ path = os.path.join(dist, name)
71
+ if not os.path.exists(path):
72
+ fail(f"missing artifact {name}")
73
+ size_mb = os.path.getsize(path) / 1e6
74
+ if size_mb < 40:
75
+ fail(f"{name} suspiciously small ({size_mb:.1f} MB)")
76
+ print(f"ok (size): {name} {size_mb:.0f} MB")
77
+
78
+ repo_version = json.load(open(os.path.join(dist, "..", "package.json")))["version"] \
79
+ if os.path.exists(os.path.join(dist, "..", "package.json")) else None
80
+
81
+ work = tempfile.mkdtemp(prefix="omnirush-smoke-")
82
+ try:
83
+ # linux-x64: full behavioral smoke — extract and run bin.js offline.
84
+ tgz = os.path.join(dist, "omnirush-cli-linux-x64.tar.gz")
85
+ names, root = archive_names(tgz, is_tgz=True)
86
+ for required in REQUIRED_PATHS:
87
+ if not has_entry(names, root, required):
88
+ fail(f"linux-x64 archive lacks {required}")
89
+ with tarfile.open(tgz, "r:gz") as t:
90
+ t.extractall(work)
91
+ extracted = os.path.join(work, root)
92
+ env = dict(os.environ)
93
+ env.update({"HOME": work, "OMNIRUSH_NO_UPDATE_CHECK": "1"})
94
+ node = shutil.which("node")
95
+ if not node:
96
+ fail("node not on PATH for the smoke run")
97
+ proc = subprocess.run(
98
+ [node, os.path.join(extracted, "src", "bin.js"), "--version"],
99
+ env=env, capture_output=True, text=True, timeout=120, cwd=work,
100
+ )
101
+ if proc.returncode != 0:
102
+ fail(f"bin.js --version failed ({proc.returncode}): {proc.stderr[-400:]}")
103
+ out = proc.stdout.strip()
104
+ if not out.startswith("omnirush "):
105
+ fail(f"unexpected --version output: {out[:120]}")
106
+ if repo_version and repo_version not in out:
107
+ fail(f"--version {out!r} does not carry the repo version {repo_version}")
108
+ print(f"ok (run): linux-x64 bin.js --version -> {out}")
109
+
110
+ # Remaining archives: structural smoke only (cross-packaged OSes).
111
+ for name in sorted(EXPECTED):
112
+ if name == "omnirush-cli-linux-x64.tar.gz":
113
+ continue
114
+ is_tgz = name.endswith(".tar.gz")
115
+ names, root = archive_names(os.path.join(dist, name), is_tgz=is_tgz)
116
+ bun_name = ".runtime/bin/bun.exe" if "windows" in name else ".runtime/bin/bun"
117
+ for required in REQUIRED_PATHS[:len(REQUIRED_PATHS) - 1] + [bun_name]:
118
+ if not has_entry(names, root, required):
119
+ fail(f"{name} lacks {required}")
120
+ print(f"ok (structure): {name}")
121
+ finally:
122
+ shutil.rmtree(work, ignore_errors=True)
123
+ print("SMOKE PASS")
124
+
125
+
126
+ if __name__ == "__main__":
127
+ main()