omnirush 0.2.0 → 0.3.1
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/assets/collect-once.ts +46 -32
- package/assets/extensions/omnirush/auth.js +21 -12
- package/assets/extensions/omnirush/collector-lib.ts +937 -226
- package/assets/extensions/omnirush/collector.ts +7 -3
- package/assets/extensions/omnirush/usage.ts +16 -0
- package/package.json +2 -1
- package/scripts/patch-pi-branding.js +36 -1
- package/src/bin.js +38 -1
package/assets/collect-once.ts
CHANGED
|
@@ -15,11 +15,11 @@ import readline from "node:readline";
|
|
|
15
15
|
|
|
16
16
|
import { omniDir, resolveOrigin, gatewayUrlForOrigin } from "./extensions/omnirush/auth";
|
|
17
17
|
import {
|
|
18
|
-
|
|
18
|
+
buildEnvelopeParts,
|
|
19
19
|
collectFiles,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
MAX_PART_COMPRESSED_BYTES,
|
|
21
|
+
MAX_PART_COMPRESSED_HARD,
|
|
22
|
+
MAX_SESSION_BYTES,
|
|
23
23
|
} from "./extensions/omnirush/collector-lib";
|
|
24
24
|
|
|
25
25
|
function parseArgs(argv: string[]): { dir: string; yes: boolean; dryRun: boolean } {
|
|
@@ -55,7 +55,7 @@ async function main() {
|
|
|
55
55
|
const sessionId = `manual-${randomBytes(6).toString("hex")}`;
|
|
56
56
|
const workspaceId = path.basename(dir) || "workspace";
|
|
57
57
|
|
|
58
|
-
const files = await collectFiles(dir,
|
|
58
|
+
const files = await collectFiles(dir, MAX_SESSION_BYTES, workspaceId, {
|
|
59
59
|
id: sessionId,
|
|
60
60
|
segment: 1,
|
|
61
61
|
resumed: false,
|
|
@@ -65,15 +65,23 @@ async function main() {
|
|
|
65
65
|
console.error("omnirush collect: nothing to upload (empty or fully filtered workspace)");
|
|
66
66
|
process.exit(1);
|
|
67
67
|
}
|
|
68
|
-
console.log(
|
|
69
|
-
`collect: ${files.length - 1} files (${bytes} bytes, denylist/caps applied) as session ${sessionId}`,
|
|
70
|
-
);
|
|
71
68
|
|
|
72
69
|
const state = { id: sessionId, segment: 1, resumed: false };
|
|
73
|
-
const
|
|
74
|
-
|
|
70
|
+
const parts = await buildEnvelopeParts(
|
|
71
|
+
state,
|
|
72
|
+
"start",
|
|
73
|
+
files,
|
|
74
|
+
MAX_PART_COMPRESSED_BYTES,
|
|
75
|
+
(message, attributes) => console.error(`omnirush collect: ${message} (${JSON.stringify(attributes ?? {})})`),
|
|
76
|
+
);
|
|
77
|
+
const plainBytes = parts.reduce((total, part) => total + part.payload.length, 0);
|
|
78
|
+
const compressedBytes = parts.reduce((total, part) => total + part.compressed.length, 0);
|
|
79
|
+
console.log(
|
|
80
|
+
`collect: ${files.length - 1} files (${bytes} bytes, denylist applied) as session ${sessionId}`,
|
|
81
|
+
);
|
|
75
82
|
console.log(
|
|
76
|
-
`envelope: ${
|
|
83
|
+
`envelope: ${parts.length} part(s), ${plainBytes} bytes plain, ${compressedBytes} bytes zstd ` +
|
|
84
|
+
`(target <= ${MAX_PART_COMPRESSED_BYTES}, rail ${MAX_PART_COMPRESSED_HARD})`,
|
|
77
85
|
);
|
|
78
86
|
|
|
79
87
|
if (dryRun) {
|
|
@@ -96,28 +104,34 @@ async function main() {
|
|
|
96
104
|
console.error("omnirush collect: no access token (run `omnirush login`)");
|
|
97
105
|
process.exit(1);
|
|
98
106
|
}
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
compressed.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
107
|
+
for (const part of parts) {
|
|
108
|
+
const response = await fetch(collectUrl, {
|
|
109
|
+
method: "POST",
|
|
110
|
+
headers: {
|
|
111
|
+
Authorization: `Bearer ${accessToken}`,
|
|
112
|
+
"Content-Type": "application/zstd",
|
|
113
|
+
"X-Omnirush-Session-ID": sessionId,
|
|
114
|
+
},
|
|
115
|
+
body: part.compressed.buffer.slice(
|
|
116
|
+
part.compressed.byteOffset,
|
|
117
|
+
part.compressed.byteOffset + part.compressed.byteLength,
|
|
118
|
+
) as ArrayBuffer,
|
|
119
|
+
signal: AbortSignal.timeout(120_000),
|
|
120
|
+
});
|
|
121
|
+
if (!response.ok) {
|
|
122
|
+
await response.body?.cancel().catch(() => undefined);
|
|
123
|
+
console.error(`upload failed: HTTP ${response.status}`);
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
const extra = [...response.headers]
|
|
127
|
+
.filter(([name]) => name.toLowerCase().startsWith("x-omnirush-"))
|
|
128
|
+
.map(([name, value]) => `${name}: ${value}`);
|
|
129
|
+
const sequence = JSON.parse(part.payload.toString("utf8")).sequence;
|
|
130
|
+
console.log(
|
|
131
|
+
`uploaded part sequence=${sequence} (${part.compressed.length} bytes, HTTP ${response.status})` +
|
|
132
|
+
`${extra.length ? "\n " + extra.join("\n ") : ""}`,
|
|
133
|
+
);
|
|
116
134
|
}
|
|
117
|
-
const extra = [...response.headers]
|
|
118
|
-
.filter(([name]) => name.toLowerCase().startsWith("x-omnirush-"))
|
|
119
|
-
.map(([name, value]) => `${name}: ${value}`);
|
|
120
|
-
console.log(`uploaded (HTTP ${response.status})${extra.length ? "\n " + extra.join("\n ") : ""}`);
|
|
121
135
|
}
|
|
122
136
|
|
|
123
137
|
main().catch((error) => {
|
|
@@ -400,20 +400,29 @@ export function createRefresher({ dir, origin, fetchImpl, now = () => Date.now()
|
|
|
400
400
|
};
|
|
401
401
|
}
|
|
402
402
|
|
|
403
|
-
/** Best-effort browser open
|
|
403
|
+
/** Best-effort browser open. NEVER throws or crashes: the spawned child's
|
|
404
|
+
* 'error' event is always handled (ENOENT on a headless Linux box would
|
|
405
|
+
* otherwise take the CLI down — Foxtran's login crash). Linux tries a
|
|
406
|
+
* chain of openers; if all fail the caller's printed URL still works. */
|
|
404
407
|
export function openBrowser(url) {
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
spawn(
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
if (process.platform === "win32") {
|
|
411
|
-
spawn("cmd", ["/c", "start", "", url], { detached: true, stdio: "ignore" }).unref();
|
|
408
|
+
const spawnSafe = (cmd, args) => {
|
|
409
|
+
try {
|
|
410
|
+
const child = spawn(cmd, args, { detached: true, stdio: "ignore" });
|
|
411
|
+
child.on("error", () => undefined);
|
|
412
|
+
child.unref();
|
|
412
413
|
return true;
|
|
414
|
+
} catch {
|
|
415
|
+
return false;
|
|
413
416
|
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
417
|
+
};
|
|
418
|
+
if (process.platform === "darwin") {
|
|
419
|
+
return spawnSafe("open", [url]);
|
|
420
|
+
}
|
|
421
|
+
if (process.platform === "win32") {
|
|
422
|
+
return spawnSafe("cmd", ["/c", "start", "", url]);
|
|
423
|
+
}
|
|
424
|
+
for (const opener of ["xdg-open", "sensible-browser", "gnome-open", "kde-open", "wslview"]) {
|
|
425
|
+
if (spawnSafe(opener, [url])) return true;
|
|
418
426
|
}
|
|
427
|
+
return false;
|
|
419
428
|
}
|