opencode-swarm 7.83.0 → 7.85.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.
- package/.opencode/skills/codebase-review-swarm/references/review-protocol-v8.2.md +4 -0
- package/.opencode/skills/council/SKILL.md +6 -1
- package/.opencode/skills/deep-dive/SKILL.md +2 -0
- package/.opencode/skills/deep-research/SKILL.md +6 -0
- package/.opencode/skills/swarm-pr-feedback/SKILL.md +6 -0
- package/.opencode/skills/swarm-pr-review/SKILL.md +4 -0
- package/README.md +3 -1
- package/dist/background/lane-output-store.d.ts +72 -0
- package/dist/background/pending-delegations.d.ts +6 -0
- package/dist/cli/capability-probe-jevmgwmf.js +18 -0
- package/dist/cli/config-doctor-zejarrr6.js +35 -0
- package/dist/cli/dispatch-k86d928w.js +477 -0
- package/dist/cli/evidence-summary-service-g2znnd33.js +320 -0
- package/dist/cli/explorer-gz70sm9b.js +16 -0
- package/dist/cli/gate-evidence-y8zn7fe2.js +29 -0
- package/dist/cli/guardrail-explain-w4txg349.js +30 -0
- package/dist/cli/guardrail-log-80116wmz.js +15 -0
- package/dist/cli/index-0sxvwjt0.js +1241 -0
- package/dist/cli/index-293f68mj.js +13538 -0
- package/dist/cli/index-5cb86007.js +110 -0
- package/dist/cli/index-a76rekgs.js +67 -0
- package/dist/cli/index-b9v501fr.js +371 -0
- package/dist/cli/index-bcp79s17.js +1673 -0
- package/dist/cli/index-ckntc5gf.js +91 -0
- package/dist/cli/index-d9fbxaqd.js +2314 -0
- package/dist/cli/index-e7h9bb6v.js +233 -0
- package/dist/cli/index-e8pk68cc.js +540 -0
- package/dist/cli/index-eb85wtx9.js +242 -0
- package/dist/cli/index-f8r50m3h.js +14505 -0
- package/dist/cli/index-fjwwrwr5.js +37 -0
- package/dist/cli/index-hw9b2xng.js +2046 -0
- package/dist/cli/index-hz59hg4h.js +452 -0
- package/dist/cli/index-jtqkh8jf.js +119 -0
- package/dist/cli/index-p0arc26j.js +28 -0
- package/dist/cli/index-p0ye10nd.js +222 -0
- package/dist/cli/index-qqabjns2.js +412 -0
- package/dist/cli/index-red8fm8p.js +2914 -0
- package/dist/cli/index-vq2321gg.js +2391 -0
- package/dist/cli/index-x7qck34v.js +583 -0
- package/dist/cli/index-yhqt45de.js +29027 -0
- package/dist/cli/index-yhsmmv2z.js +339 -0
- package/dist/cli/index-yx44zd0p.js +40 -0
- package/dist/cli/index-zfsbaaqh.js +29 -0
- package/dist/cli/index.js +73 -69708
- package/dist/cli/knowledge-store-n4x6zyk7.js +73 -0
- package/dist/cli/pending-delegations-rd40tv9s.js +261 -0
- package/dist/cli/pr-subscriptions-y1nn36e5.js +33 -0
- package/dist/cli/schema-8d32b2v6.js +168 -0
- package/dist/cli/skill-generator-a5ehggyg.js +55 -0
- package/dist/cli/task-envelope-qn0qtnh0.js +90 -0
- package/dist/cli/telemetry-9bbyxrvn.js +20 -0
- package/dist/cli/workspace-snapshot-w58jr2ga.js +90 -0
- package/dist/commands/guardrail-explain.d.ts +1 -0
- package/dist/commands/guardrail-log.d.ts +1 -0
- package/dist/commands/index.d.ts +2 -0
- package/dist/commands/registry.d.ts +14 -0
- package/dist/hooks/guardrails/audit-log.d.ts +114 -0
- package/dist/index.js +4005 -2432
- package/dist/services/diagnose-service.d.ts +5 -0
- package/dist/services/guardrail-explain-service.d.ts +42 -0
- package/dist/services/guardrail-log-service.d.ts +10 -0
- package/dist/tools/dispatch-lanes.d.ts +14 -3
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/manifest.d.ts +1 -0
- package/dist/tools/retrieve-lane-output.d.ts +2 -0
- package/dist/tools/tool-metadata.d.ts +4 -0
- package/package.json +2 -2
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
redactPath,
|
|
4
|
+
redactShellCommand
|
|
5
|
+
} from "./index-vq2321gg.js";
|
|
6
|
+
|
|
7
|
+
// src/services/guardrail-log-service.ts
|
|
8
|
+
import * as fs from "fs/promises";
|
|
9
|
+
import * as path from "path";
|
|
10
|
+
var BLOCK_TYPES = new Set([
|
|
11
|
+
"file_write",
|
|
12
|
+
"scope_violation",
|
|
13
|
+
"destructive_block"
|
|
14
|
+
]);
|
|
15
|
+
function isBlockEntry(entry) {
|
|
16
|
+
if (entry.type === null || entry.type === undefined)
|
|
17
|
+
return false;
|
|
18
|
+
return BLOCK_TYPES.has(entry.type);
|
|
19
|
+
}
|
|
20
|
+
function redactSummary(entry) {
|
|
21
|
+
if (entry.type === "file_write" || entry.type === "scope_violation") {
|
|
22
|
+
const raw = entry.path ?? "";
|
|
23
|
+
return redactPath(raw);
|
|
24
|
+
}
|
|
25
|
+
if (entry.type === "destructive_block" || entry.type === "sandbox_wrap" || entry.type === "sandbox_skip" || entry.type === "shell" || entry.type === null || entry.type === undefined) {
|
|
26
|
+
const raw = entry.command ?? "";
|
|
27
|
+
return redactShellCommand(raw);
|
|
28
|
+
}
|
|
29
|
+
return "";
|
|
30
|
+
}
|
|
31
|
+
function formatEntry(entry) {
|
|
32
|
+
const decisionType = entry.type ?? "shell";
|
|
33
|
+
const summary = redactSummary(entry);
|
|
34
|
+
return `- [${entry.ts}] ${decisionType} | agent: ${entry.agent} | ${summary}`;
|
|
35
|
+
}
|
|
36
|
+
async function handleGuardrailLog(directory, args) {
|
|
37
|
+
const auditPath = path.join(directory, ".swarm", "session", "shell-audit.jsonl");
|
|
38
|
+
let raw;
|
|
39
|
+
try {
|
|
40
|
+
raw = await fs.readFile(auditPath, "utf-8");
|
|
41
|
+
} catch (error) {
|
|
42
|
+
if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT") {
|
|
43
|
+
return "No guardrail decisions recorded yet.";
|
|
44
|
+
}
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
const lines = raw.split(/\r?\n/);
|
|
48
|
+
const entries = [];
|
|
49
|
+
for (const line of lines) {
|
|
50
|
+
if (line.trim().length === 0)
|
|
51
|
+
continue;
|
|
52
|
+
let parsed;
|
|
53
|
+
try {
|
|
54
|
+
parsed = JSON.parse(line);
|
|
55
|
+
} catch {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (!isPlainObject(parsed))
|
|
59
|
+
continue;
|
|
60
|
+
if (typeof parsed.ts !== "string")
|
|
61
|
+
continue;
|
|
62
|
+
if (typeof parsed.sessionID !== "string")
|
|
63
|
+
continue;
|
|
64
|
+
if (typeof parsed.agent !== "string")
|
|
65
|
+
continue;
|
|
66
|
+
if (typeof parsed.tool !== "string")
|
|
67
|
+
continue;
|
|
68
|
+
const entry = {
|
|
69
|
+
ts: parsed.ts,
|
|
70
|
+
sessionID: parsed.sessionID,
|
|
71
|
+
agent: parsed.agent,
|
|
72
|
+
tool: parsed.tool
|
|
73
|
+
};
|
|
74
|
+
if (typeof parsed.type === "string") {
|
|
75
|
+
entry.type = parsed.type;
|
|
76
|
+
}
|
|
77
|
+
if (typeof parsed.command === "string") {
|
|
78
|
+
entry.command = parsed.command;
|
|
79
|
+
}
|
|
80
|
+
if (typeof parsed.path === "string") {
|
|
81
|
+
entry.path = parsed.path;
|
|
82
|
+
}
|
|
83
|
+
entries.push(entry);
|
|
84
|
+
}
|
|
85
|
+
if (entries.length === 0) {
|
|
86
|
+
return "No guardrail decisions recorded yet.";
|
|
87
|
+
}
|
|
88
|
+
const blocksOnly = args.includes("--blocks-only");
|
|
89
|
+
const filtered = blocksOnly ? entries.filter(isBlockEntry) : entries;
|
|
90
|
+
if (filtered.length === 0) {
|
|
91
|
+
if (blocksOnly) {
|
|
92
|
+
return "No guardrail block decisions recorded yet.";
|
|
93
|
+
}
|
|
94
|
+
return "No guardrail decisions recorded yet.";
|
|
95
|
+
}
|
|
96
|
+
filtered.sort((a, b) => {
|
|
97
|
+
const diff = b.ts.localeCompare(a.ts);
|
|
98
|
+
return diff === 0 ? 0 : diff;
|
|
99
|
+
});
|
|
100
|
+
const header = blocksOnly ? "# Guardrail Block Log (most-recent-first)" : "# Guardrail Decision Log (most-recent-first)";
|
|
101
|
+
const body = filtered.map(formatEntry).join(`
|
|
102
|
+
`);
|
|
103
|
+
return `${header}
|
|
104
|
+
|
|
105
|
+
${body}`;
|
|
106
|
+
}
|
|
107
|
+
function isPlainObject(value) {
|
|
108
|
+
return typeof value === "object" && value !== null && (value.constructor === Object || Object.getPrototypeOf(value) === null);
|
|
109
|
+
}
|
|
110
|
+
export { handleGuardrailLog };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
function __accessProp(key) {
|
|
9
|
+
return this[key];
|
|
10
|
+
}
|
|
11
|
+
var __toESMCache_node;
|
|
12
|
+
var __toESMCache_esm;
|
|
13
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
14
|
+
var canCache = mod != null && typeof mod === "object";
|
|
15
|
+
if (canCache) {
|
|
16
|
+
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
17
|
+
var cached = cache.get(mod);
|
|
18
|
+
if (cached)
|
|
19
|
+
return cached;
|
|
20
|
+
}
|
|
21
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
22
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
23
|
+
for (let key of __getOwnPropNames(mod))
|
|
24
|
+
if (!__hasOwnProp.call(to, key))
|
|
25
|
+
__defProp(to, key, {
|
|
26
|
+
get: __accessProp.bind(mod, key),
|
|
27
|
+
enumerable: true
|
|
28
|
+
});
|
|
29
|
+
if (canCache)
|
|
30
|
+
cache.set(mod, to);
|
|
31
|
+
return to;
|
|
32
|
+
};
|
|
33
|
+
var __toCommonJS = (from) => {
|
|
34
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
35
|
+
if (entry)
|
|
36
|
+
return entry;
|
|
37
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
38
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
39
|
+
for (var key of __getOwnPropNames(from))
|
|
40
|
+
if (!__hasOwnProp.call(entry, key))
|
|
41
|
+
__defProp(entry, key, {
|
|
42
|
+
get: __accessProp.bind(from, key),
|
|
43
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
__moduleCache.set(from, entry);
|
|
47
|
+
return entry;
|
|
48
|
+
};
|
|
49
|
+
var __moduleCache;
|
|
50
|
+
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
51
|
+
var __returnValue = (v) => v;
|
|
52
|
+
function __exportSetter(name, newValue) {
|
|
53
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
54
|
+
}
|
|
55
|
+
var __export = (target, all) => {
|
|
56
|
+
for (var name in all)
|
|
57
|
+
__defProp(target, name, {
|
|
58
|
+
get: all[name],
|
|
59
|
+
enumerable: true,
|
|
60
|
+
configurable: true,
|
|
61
|
+
set: __exportSetter.bind(all, name)
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
65
|
+
var __require = import.meta.require;
|
|
66
|
+
|
|
67
|
+
export { __toESM, __toCommonJS, __commonJS, __export, __esm, __require };
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/utils/bun-compat.ts
|
|
3
|
+
import {
|
|
4
|
+
spawn as nodeSpawn,
|
|
5
|
+
spawnSync as nodeSpawnSync
|
|
6
|
+
} from "child_process";
|
|
7
|
+
import * as fsSync from "fs";
|
|
8
|
+
import * as fsPromises from "fs/promises";
|
|
9
|
+
import * as path from "path";
|
|
10
|
+
var WINDOWS_RENAME_MAX_RETRIES = 3;
|
|
11
|
+
var WINDOWS_RENAME_RETRY_DELAY_MS = 50;
|
|
12
|
+
var tempCounter = 0;
|
|
13
|
+
function getBun() {
|
|
14
|
+
const g = globalThis;
|
|
15
|
+
return g.Bun;
|
|
16
|
+
}
|
|
17
|
+
function bunFile(filePath) {
|
|
18
|
+
const bun = getBun();
|
|
19
|
+
if (bun?.file) {
|
|
20
|
+
return bun.file(filePath);
|
|
21
|
+
}
|
|
22
|
+
let cachedSize;
|
|
23
|
+
return {
|
|
24
|
+
async text() {
|
|
25
|
+
return fsPromises.readFile(filePath, "utf-8");
|
|
26
|
+
},
|
|
27
|
+
async arrayBuffer() {
|
|
28
|
+
const buf = await fsPromises.readFile(filePath);
|
|
29
|
+
const ab = new ArrayBuffer(buf.byteLength);
|
|
30
|
+
new Uint8Array(ab).set(buf);
|
|
31
|
+
return ab;
|
|
32
|
+
},
|
|
33
|
+
async exists() {
|
|
34
|
+
try {
|
|
35
|
+
await fsPromises.access(filePath, fsSync.constants.F_OK);
|
|
36
|
+
return true;
|
|
37
|
+
} catch {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
get size() {
|
|
42
|
+
if (cachedSize !== undefined)
|
|
43
|
+
return cachedSize;
|
|
44
|
+
try {
|
|
45
|
+
cachedSize = fsSync.statSync(filePath).size;
|
|
46
|
+
} catch {
|
|
47
|
+
cachedSize = 0;
|
|
48
|
+
}
|
|
49
|
+
return cachedSize;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
async function bunWrite(filePath, data) {
|
|
54
|
+
const bun = getBun();
|
|
55
|
+
if (bun?.write) {
|
|
56
|
+
return bun.write(filePath, data);
|
|
57
|
+
}
|
|
58
|
+
const dir = path.dirname(filePath);
|
|
59
|
+
const tempName = `.${path.basename(filePath)}.${process.pid}.${Date.now()}.${tempCounter++}.${Math.random().toString(36).slice(2, 10)}.tmp`;
|
|
60
|
+
const tempPath = path.join(dir, tempName);
|
|
61
|
+
let buffer;
|
|
62
|
+
if (typeof data === "string") {
|
|
63
|
+
buffer = data;
|
|
64
|
+
} else if (data instanceof ArrayBuffer) {
|
|
65
|
+
buffer = new Uint8Array(data);
|
|
66
|
+
} else if (ArrayBuffer.isView(data)) {
|
|
67
|
+
buffer = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
68
|
+
} else {
|
|
69
|
+
buffer = new Uint8Array(0);
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
await fsPromises.mkdir(dir, { recursive: true });
|
|
73
|
+
} catch {}
|
|
74
|
+
await fsPromises.writeFile(tempPath, buffer);
|
|
75
|
+
let lastError;
|
|
76
|
+
for (let attempt = 0;attempt < WINDOWS_RENAME_MAX_RETRIES; attempt++) {
|
|
77
|
+
try {
|
|
78
|
+
await fsPromises.rename(tempPath, filePath);
|
|
79
|
+
lastError = undefined;
|
|
80
|
+
break;
|
|
81
|
+
} catch (err) {
|
|
82
|
+
lastError = err;
|
|
83
|
+
const code = err.code;
|
|
84
|
+
if (code !== "EEXIST" && code !== "EBUSY" && code !== "EPERM") {
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
await new Promise((r) => setTimeout(r, WINDOWS_RENAME_RETRY_DELAY_MS));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (lastError) {
|
|
91
|
+
try {
|
|
92
|
+
await fsPromises.unlink(tempPath);
|
|
93
|
+
} catch {}
|
|
94
|
+
throw lastError;
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
const dirFd = await fsPromises.open(dir, "r");
|
|
98
|
+
try {
|
|
99
|
+
await dirFd.sync();
|
|
100
|
+
} finally {
|
|
101
|
+
await dirFd.close();
|
|
102
|
+
}
|
|
103
|
+
} catch {}
|
|
104
|
+
const stats = await fsPromises.stat(filePath);
|
|
105
|
+
return stats.size;
|
|
106
|
+
}
|
|
107
|
+
function bunHash(input) {
|
|
108
|
+
const bun = getBun();
|
|
109
|
+
if (bun?.hash) {
|
|
110
|
+
const r = bun.hash(input);
|
|
111
|
+
return typeof r === "bigint" ? r : BigInt(r);
|
|
112
|
+
}
|
|
113
|
+
let bytes;
|
|
114
|
+
if (typeof input === "string") {
|
|
115
|
+
bytes = new TextEncoder().encode(input);
|
|
116
|
+
} else if (input instanceof ArrayBuffer) {
|
|
117
|
+
bytes = new Uint8Array(input);
|
|
118
|
+
} else {
|
|
119
|
+
bytes = new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
|
|
120
|
+
}
|
|
121
|
+
let hash = 5381n;
|
|
122
|
+
for (const b of bytes) {
|
|
123
|
+
hash = hash * 33n + BigInt(b) & 0xffffffffffffffffn;
|
|
124
|
+
}
|
|
125
|
+
return hash;
|
|
126
|
+
}
|
|
127
|
+
function killProcessTreeImpl(pid, signal, directKill, wasDetached) {
|
|
128
|
+
if (typeof pid !== "number" || pid <= 0) {
|
|
129
|
+
directKill();
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (process.platform === "win32") {
|
|
133
|
+
try {
|
|
134
|
+
nodeSpawnSync("taskkill", ["/PID", String(pid), "/T", "/F"]);
|
|
135
|
+
} catch {
|
|
136
|
+
directKill();
|
|
137
|
+
}
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (wasDetached) {
|
|
141
|
+
try {
|
|
142
|
+
process.kill(-pid, signal ?? "SIGKILL");
|
|
143
|
+
return;
|
|
144
|
+
} catch {}
|
|
145
|
+
}
|
|
146
|
+
directKill();
|
|
147
|
+
}
|
|
148
|
+
function streamFromNode(pipe) {
|
|
149
|
+
const collected = new Promise((resolve) => {
|
|
150
|
+
if (!pipe) {
|
|
151
|
+
resolve(Buffer.alloc(0));
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const chunks = [];
|
|
155
|
+
pipe.on("data", (chunk) => {
|
|
156
|
+
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
157
|
+
});
|
|
158
|
+
pipe.on("end", () => resolve(Buffer.concat(chunks)));
|
|
159
|
+
pipe.on("error", () => resolve(Buffer.concat(chunks)));
|
|
160
|
+
});
|
|
161
|
+
const toWebReadable = () => {
|
|
162
|
+
if (!pipe) {
|
|
163
|
+
return new ReadableStream({
|
|
164
|
+
start(controller) {
|
|
165
|
+
controller.close();
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
const r = pipe;
|
|
170
|
+
if (typeof r.toWeb === "function") {
|
|
171
|
+
return r.toWeb();
|
|
172
|
+
}
|
|
173
|
+
return new ReadableStream({
|
|
174
|
+
start(controller) {
|
|
175
|
+
pipe.on("data", (chunk) => {
|
|
176
|
+
controller.enqueue(typeof chunk === "string" ? new TextEncoder().encode(chunk) : new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength));
|
|
177
|
+
});
|
|
178
|
+
pipe.on("end", () => controller.close());
|
|
179
|
+
pipe.on("error", (err) => controller.error(err));
|
|
180
|
+
},
|
|
181
|
+
cancel() {
|
|
182
|
+
const destroyable = pipe;
|
|
183
|
+
if (typeof destroyable.destroy === "function") {
|
|
184
|
+
try {
|
|
185
|
+
destroyable.destroy();
|
|
186
|
+
} catch {}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
};
|
|
191
|
+
return {
|
|
192
|
+
async text() {
|
|
193
|
+
return (await collected).toString("utf-8");
|
|
194
|
+
},
|
|
195
|
+
async bytes() {
|
|
196
|
+
const b = await collected;
|
|
197
|
+
return new Uint8Array(b.buffer, b.byteOffset, b.byteLength);
|
|
198
|
+
},
|
|
199
|
+
getReader() {
|
|
200
|
+
return toWebReadable().getReader();
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
function mapStdio(v) {
|
|
205
|
+
return v ?? "pipe";
|
|
206
|
+
}
|
|
207
|
+
function streamFromBun(stream) {
|
|
208
|
+
if (!stream || typeof stream !== "object") {
|
|
209
|
+
const empty = {
|
|
210
|
+
async text() {
|
|
211
|
+
return "";
|
|
212
|
+
},
|
|
213
|
+
async bytes() {
|
|
214
|
+
return new Uint8Array(0);
|
|
215
|
+
},
|
|
216
|
+
getReader() {
|
|
217
|
+
return new ReadableStream({
|
|
218
|
+
start(controller) {
|
|
219
|
+
controller.close();
|
|
220
|
+
}
|
|
221
|
+
}).getReader();
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
return empty;
|
|
225
|
+
}
|
|
226
|
+
const candidate = stream;
|
|
227
|
+
const collect = async () => {
|
|
228
|
+
if (typeof candidate.getReader !== "function") {
|
|
229
|
+
return new Uint8Array(0);
|
|
230
|
+
}
|
|
231
|
+
const reader = candidate.getReader();
|
|
232
|
+
const chunks = [];
|
|
233
|
+
for (;; ) {
|
|
234
|
+
const { done, value } = await reader.read();
|
|
235
|
+
if (done)
|
|
236
|
+
break;
|
|
237
|
+
if (value)
|
|
238
|
+
chunks.push(value);
|
|
239
|
+
}
|
|
240
|
+
const total = chunks.reduce((acc, c) => acc + c.byteLength, 0);
|
|
241
|
+
const out = new Uint8Array(total);
|
|
242
|
+
let off = 0;
|
|
243
|
+
for (const c of chunks) {
|
|
244
|
+
out.set(c, off);
|
|
245
|
+
off += c.byteLength;
|
|
246
|
+
}
|
|
247
|
+
return out;
|
|
248
|
+
};
|
|
249
|
+
const text = typeof candidate.text === "function" ? () => candidate.text() : async () => new TextDecoder().decode(await collect());
|
|
250
|
+
const bytes = typeof candidate.bytes === "function" ? () => candidate.bytes() : collect;
|
|
251
|
+
const getReader = typeof candidate.getReader === "function" ? () => candidate.getReader() : () => new ReadableStream({
|
|
252
|
+
start(controller) {
|
|
253
|
+
controller.close();
|
|
254
|
+
}
|
|
255
|
+
}).getReader();
|
|
256
|
+
return { text, bytes, getReader };
|
|
257
|
+
}
|
|
258
|
+
function bunSpawn(cmd, options) {
|
|
259
|
+
const bun = getBun();
|
|
260
|
+
if (bun?.spawn) {
|
|
261
|
+
const proc2 = bun.spawn(cmd, options);
|
|
262
|
+
return {
|
|
263
|
+
stdout: streamFromBun(proc2.stdout),
|
|
264
|
+
stderr: streamFromBun(proc2.stderr),
|
|
265
|
+
exited: proc2.exited,
|
|
266
|
+
get exitCode() {
|
|
267
|
+
return proc2.exitCode;
|
|
268
|
+
},
|
|
269
|
+
kill(sig) {
|
|
270
|
+
if (options?.killProcessTree) {
|
|
271
|
+
killProcessTreeImpl(proc2.pid, sig, () => proc2.kill(sig), false);
|
|
272
|
+
} else {
|
|
273
|
+
proc2.kill(sig);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
const [file, ...args] = cmd;
|
|
279
|
+
const detached = options?.killProcessTree === true;
|
|
280
|
+
const proc = nodeSpawn(file, args, {
|
|
281
|
+
cwd: options?.cwd,
|
|
282
|
+
env: options?.env,
|
|
283
|
+
detached,
|
|
284
|
+
windowsHide: true,
|
|
285
|
+
stdio: [
|
|
286
|
+
mapStdio(options?.stdin),
|
|
287
|
+
mapStdio(options?.stdout),
|
|
288
|
+
mapStdio(options?.stderr)
|
|
289
|
+
]
|
|
290
|
+
});
|
|
291
|
+
const killChild = (signal) => {
|
|
292
|
+
if (detached) {
|
|
293
|
+
killProcessTreeImpl(proc.pid, signal, () => proc.kill(signal), true);
|
|
294
|
+
} else {
|
|
295
|
+
proc.kill(signal);
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
let timeoutHandle;
|
|
299
|
+
const exited = new Promise((resolve) => {
|
|
300
|
+
proc.on("exit", (code) => resolve(code ?? 0));
|
|
301
|
+
proc.on("error", () => resolve(1));
|
|
302
|
+
if (options?.timeout && options.timeout > 0) {
|
|
303
|
+
timeoutHandle = setTimeout(() => {
|
|
304
|
+
try {
|
|
305
|
+
killChild("SIGKILL");
|
|
306
|
+
} catch {}
|
|
307
|
+
}, options.timeout);
|
|
308
|
+
if (typeof timeoutHandle.unref === "function") {
|
|
309
|
+
timeoutHandle.unref();
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}).finally(() => {
|
|
313
|
+
if (timeoutHandle !== undefined)
|
|
314
|
+
clearTimeout(timeoutHandle);
|
|
315
|
+
});
|
|
316
|
+
return {
|
|
317
|
+
stdout: streamFromNode(proc.stdout),
|
|
318
|
+
stderr: streamFromNode(proc.stderr),
|
|
319
|
+
exited,
|
|
320
|
+
get exitCode() {
|
|
321
|
+
return proc.exitCode;
|
|
322
|
+
},
|
|
323
|
+
kill(signal) {
|
|
324
|
+
killChild(signal);
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
function bunSpawnSync(cmd, options) {
|
|
329
|
+
const bun = getBun();
|
|
330
|
+
if (bun?.spawnSync) {
|
|
331
|
+
const result2 = bun.spawnSync(cmd, options);
|
|
332
|
+
return result2;
|
|
333
|
+
}
|
|
334
|
+
let argv;
|
|
335
|
+
let mergedOptions;
|
|
336
|
+
if (Array.isArray(cmd)) {
|
|
337
|
+
argv = cmd;
|
|
338
|
+
mergedOptions = { ...options ?? {} };
|
|
339
|
+
} else {
|
|
340
|
+
argv = cmd.cmd;
|
|
341
|
+
mergedOptions = {
|
|
342
|
+
cwd: cmd.cwd,
|
|
343
|
+
env: cmd.env,
|
|
344
|
+
stdin: "pipe",
|
|
345
|
+
timeout: cmd.timeout,
|
|
346
|
+
...options ?? {}
|
|
347
|
+
};
|
|
348
|
+
if (cmd.stdin !== undefined) {
|
|
349
|
+
mergedOptions.stdin = cmd.stdin;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
const [file, ...args] = argv;
|
|
353
|
+
const result = nodeSpawnSync(file, args, {
|
|
354
|
+
cwd: mergedOptions.cwd,
|
|
355
|
+
env: mergedOptions.env,
|
|
356
|
+
input: mergedOptions.stdin instanceof Uint8Array || typeof mergedOptions.stdin === "string" ? mergedOptions.stdin : undefined,
|
|
357
|
+
timeout: mergedOptions.timeout,
|
|
358
|
+
windowsHide: true
|
|
359
|
+
});
|
|
360
|
+
const stdout = result.stdout instanceof Buffer ? new Uint8Array(result.stdout.buffer, result.stdout.byteOffset, result.stdout.byteLength) : typeof result.stdout === "string" ? new TextEncoder().encode(result.stdout) : new Uint8Array(0);
|
|
361
|
+
const stderr = result.stderr instanceof Buffer ? new Uint8Array(result.stderr.buffer, result.stderr.byteOffset, result.stderr.byteLength) : typeof result.stderr === "string" ? new TextEncoder().encode(result.stderr) : new Uint8Array(0);
|
|
362
|
+
const exitCode = result.status ?? (result.signal ? 128 : 1);
|
|
363
|
+
return {
|
|
364
|
+
stdout,
|
|
365
|
+
stderr,
|
|
366
|
+
exitCode,
|
|
367
|
+
success: exitCode === 0 && !result.error
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
export { bunFile, bunWrite, bunHash, bunSpawn, bunSpawnSync };
|