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 (
|
|
1865
|
-
|
|
1866
|
-
|
|
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) =>
|
|
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.
|
|
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": ">=
|
|
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
|
-
|
|
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
|
|
90
|
-
out =
|
|
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(
|
|
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()
|