@odla-ai/cli 0.16.3 → 0.16.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.
- package/README.md +9 -6
- package/dist/bin.cjs +157 -82
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-YWC7F5T3.js → chunk-GAFC4EPJ.js} +147 -73
- package/dist/chunk-GAFC4EPJ.js.map +1 -0
- package/dist/index.cjs +159 -82
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -4
- package/dist/index.d.ts +16 -4
- package/dist/index.js +3 -1
- package/dist/runtime/pi-agent.js +330317 -0
- package/package.json +2 -2
- package/skills/odla-migrate/references/phase-2-db.md +2 -2
- package/dist/chunk-YWC7F5T3.js.map +0 -1
package/dist/bin.js
CHANGED
|
@@ -1775,10 +1775,11 @@ async function defaultReadOrigin(cwd) {
|
|
|
1775
1775
|
}
|
|
1776
1776
|
|
|
1777
1777
|
// src/code-runtime-config.ts
|
|
1778
|
-
var CODE_PI_IMAGE = "
|
|
1778
|
+
var CODE_PI_IMAGE = "odla-ai/pi-agent:embedded";
|
|
1779
|
+
var CODE_NODE_IMAGE = "node:24-alpine@sha256:a0b9bf06e4e6193cf7a0f58816cc935ff8c2a908f81e6f1a95432d679c54fbfd";
|
|
1779
1780
|
var CODE_BUILD_RECIPES = Object.freeze([{
|
|
1780
1781
|
id: "odla-code-contracts",
|
|
1781
|
-
image:
|
|
1782
|
+
image: CODE_NODE_IMAGE,
|
|
1782
1783
|
command: [
|
|
1783
1784
|
"node",
|
|
1784
1785
|
// The clean source mount deliberately has no node_modules. Reuse the
|
|
@@ -1798,6 +1799,86 @@ var CODE_BUILD_RECIPES = Object.freeze([{
|
|
|
1798
1799
|
pids: 128
|
|
1799
1800
|
}]);
|
|
1800
1801
|
|
|
1802
|
+
// src/code-images.ts
|
|
1803
|
+
import { spawn as spawn2 } from "child_process";
|
|
1804
|
+
import { createHash } from "crypto";
|
|
1805
|
+
import { copyFile, mkdtemp, readFile, rm, writeFile } from "fs/promises";
|
|
1806
|
+
import { tmpdir } from "os";
|
|
1807
|
+
import { join as join2 } from "path";
|
|
1808
|
+
import { fileURLToPath } from "url";
|
|
1809
|
+
var runCodeImageCommand = (command, args, stdio) => new Promise((accept, reject) => {
|
|
1810
|
+
const child = spawn2(command, [...args], { shell: false, stdio });
|
|
1811
|
+
child.once("error", reject);
|
|
1812
|
+
child.once("exit", (code, signal) => {
|
|
1813
|
+
if (code === 0) accept();
|
|
1814
|
+
else reject(new Error(`${command} ${args.join(" ")} exited ${code ?? signal ?? "without a status"}`));
|
|
1815
|
+
});
|
|
1816
|
+
});
|
|
1817
|
+
async function prepareCodeImages(engine, images, run = runCodeImageCommand, buildEmbedded = buildEmbeddedPiImage, nameEmbedded = embeddedPiImageName) {
|
|
1818
|
+
if (engine === "container") {
|
|
1819
|
+
try {
|
|
1820
|
+
await run(engine, ["system", "start"], "inherit");
|
|
1821
|
+
} catch {
|
|
1822
|
+
throw new Error("Apple container could not start; run `container system start` once to complete its lightweight VM setup, then retry");
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1825
|
+
const prepared = [];
|
|
1826
|
+
for (const image of images) {
|
|
1827
|
+
const runtimeImage = image === CODE_PI_IMAGE ? await nameEmbedded() : image;
|
|
1828
|
+
const inspectArgs = ["image", "inspect", runtimeImage];
|
|
1829
|
+
try {
|
|
1830
|
+
await run(engine, inspectArgs, "ignore");
|
|
1831
|
+
prepared.push(runtimeImage);
|
|
1832
|
+
continue;
|
|
1833
|
+
} catch {
|
|
1834
|
+
}
|
|
1835
|
+
if (image === CODE_PI_IMAGE) {
|
|
1836
|
+
try {
|
|
1837
|
+
await buildEmbedded(engine, runtimeImage, run);
|
|
1838
|
+
} catch (error) {
|
|
1839
|
+
const detail = error instanceof Error && error.message ? `: ${error.message}` : "";
|
|
1840
|
+
throw new Error(`could not prepare CLI-embedded Code image${detail}`);
|
|
1841
|
+
}
|
|
1842
|
+
prepared.push(runtimeImage);
|
|
1843
|
+
continue;
|
|
1844
|
+
}
|
|
1845
|
+
const args = engine === "container" ? ["image", "pull", image] : ["pull", image];
|
|
1846
|
+
try {
|
|
1847
|
+
await run(engine, args, "inherit");
|
|
1848
|
+
} catch (error) {
|
|
1849
|
+
const detail = error instanceof Error && error.message ? `: ${error.message}` : "";
|
|
1850
|
+
throw new Error(`could not prepare pinned Code image ${image}${detail}`);
|
|
1851
|
+
}
|
|
1852
|
+
prepared.push(image);
|
|
1853
|
+
}
|
|
1854
|
+
return prepared;
|
|
1855
|
+
}
|
|
1856
|
+
function embeddedPiAssetPath() {
|
|
1857
|
+
return fileURLToPath(new URL("./runtime/pi-agent.js", import.meta.url));
|
|
1858
|
+
}
|
|
1859
|
+
async function embeddedPiImageName() {
|
|
1860
|
+
const bundle = await readFile(embeddedPiAssetPath()).catch(() => {
|
|
1861
|
+
throw new Error("CLI-embedded Pi runtime is missing; reinstall this exact @odla-ai/cli version");
|
|
1862
|
+
});
|
|
1863
|
+
return `odla-ai/pi-agent:embedded-sha256-${createHash("sha256").update(bundle).digest("hex")}`;
|
|
1864
|
+
}
|
|
1865
|
+
async function buildEmbeddedPiImage(engine, image, run) {
|
|
1866
|
+
const context = await mkdtemp(join2(tmpdir(), "odla-code-pi-"));
|
|
1867
|
+
try {
|
|
1868
|
+
await copyFile(embeddedPiAssetPath(), join2(context, "pi-agent.js"));
|
|
1869
|
+
await writeFile(join2(context, "Dockerfile"), [
|
|
1870
|
+
`FROM ${CODE_NODE_IMAGE}`,
|
|
1871
|
+
"COPY pi-agent.js /opt/odla/pi-agent.js",
|
|
1872
|
+
"WORKDIR /workspace",
|
|
1873
|
+
'ENTRYPOINT ["node", "/opt/odla/pi-agent.js"]',
|
|
1874
|
+
""
|
|
1875
|
+
].join("\n"), { mode: 384 });
|
|
1876
|
+
await run(engine, ["build", "--tag", image, context], "inherit");
|
|
1877
|
+
} finally {
|
|
1878
|
+
await rm(context, { recursive: true, force: true });
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1801
1882
|
// src/code-connect.ts
|
|
1802
1883
|
import { existsSync as existsSync4 } from "fs";
|
|
1803
1884
|
import { cpus, hostname, totalmem } from "os";
|
|
@@ -1884,21 +1965,21 @@ function encodeAgentInput(message2) {
|
|
|
1884
1965
|
`;
|
|
1885
1966
|
}
|
|
1886
1967
|
|
|
1887
|
-
// ../harness/dist/chunk-
|
|
1888
|
-
import { execFile as execFile2, spawn as
|
|
1968
|
+
// ../harness/dist/chunk-NOBK6PCT.js
|
|
1969
|
+
import { execFile as execFile2, spawn as spawn3 } from "child_process";
|
|
1889
1970
|
import { constants } from "fs";
|
|
1890
1971
|
import { access } from "fs/promises";
|
|
1891
|
-
import { delimiter, join as
|
|
1972
|
+
import { delimiter, join as join3 } from "path";
|
|
1892
1973
|
import { getgid, getuid } from "process";
|
|
1893
|
-
import { mkdir, mkdtemp, realpath, rm, writeFile } from "fs/promises";
|
|
1894
|
-
import { tmpdir } from "os";
|
|
1974
|
+
import { mkdir, mkdtemp as mkdtemp2, realpath, rm as rm2, writeFile as writeFile2 } from "fs/promises";
|
|
1975
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
1895
1976
|
import { join as join22, resolve as resolve3, sep } from "path";
|
|
1896
1977
|
import { spawn as spawn22 } from "child_process";
|
|
1897
1978
|
import { isAbsolute as isAbsolute3 } from "path";
|
|
1898
|
-
import { chmod, copyFile, lstat, mkdir as mkdir2, mkdtemp as
|
|
1899
|
-
import { tmpdir as
|
|
1900
|
-
import { basename, join as
|
|
1901
|
-
import { spawn as
|
|
1979
|
+
import { chmod, copyFile as copyFile2, lstat, mkdir as mkdir2, mkdtemp as mkdtemp22, readdir, realpath as realpath2, rm as rm22, stat } from "fs/promises";
|
|
1980
|
+
import { tmpdir as tmpdir22 } from "os";
|
|
1981
|
+
import { basename, join as join32, relative as relative2, resolve as resolve22, sep as sep2 } from "path";
|
|
1982
|
+
import { spawn as spawn32 } from "child_process";
|
|
1902
1983
|
var DIGEST_IMAGE = /^[a-z0-9][a-z0-9._/-]*(?::[a-zA-Z0-9._-]+)?@sha256:[0-9a-f]{64}$/;
|
|
1903
1984
|
function assertPinnedImage(image) {
|
|
1904
1985
|
if (!DIGEST_IMAGE.test(image)) throw new TypeError("container image must be pinned by sha256 digest");
|
|
@@ -1906,7 +1987,7 @@ function assertPinnedImage(image) {
|
|
|
1906
1987
|
async function commandAvailable(engine) {
|
|
1907
1988
|
for (const directory of (process.env.PATH ?? "").split(delimiter).filter(Boolean)) {
|
|
1908
1989
|
try {
|
|
1909
|
-
await access(
|
|
1990
|
+
await access(join3(directory, engine), constants.X_OK);
|
|
1910
1991
|
return true;
|
|
1911
1992
|
} catch {
|
|
1912
1993
|
}
|
|
@@ -1937,7 +2018,7 @@ async function selectContainerEngine(requested = "auto", options = {}) {
|
|
|
1937
2018
|
throw new TypeError("no rootless Podman found; install Podman or explicitly choose --engine docker after reviewing its daemon boundary");
|
|
1938
2019
|
}
|
|
1939
2020
|
if (platform === "darwin") {
|
|
1940
|
-
throw new TypeError("
|
|
2021
|
+
throw new TypeError("Apple container is not installed; on Apple Silicon macOS 26 run `brew install container`, then retry (Podman Machine is the fallback)");
|
|
1941
2022
|
}
|
|
1942
2023
|
throw new TypeError("no supported container engine found");
|
|
1943
2024
|
}
|
|
@@ -2030,7 +2111,7 @@ async function runContainerAttempt(options) {
|
|
|
2030
2111
|
await verifyContainerEngineBoundary(options.engine);
|
|
2031
2112
|
const args = buildContainerRunArgs(options);
|
|
2032
2113
|
const name = containerName(args);
|
|
2033
|
-
const child =
|
|
2114
|
+
const child = spawn3(options.engine, args, { stdio: ["pipe", "pipe", "pipe"], shell: false });
|
|
2034
2115
|
let stderr = "";
|
|
2035
2116
|
let outputBytes = 0;
|
|
2036
2117
|
let complete = null;
|
|
@@ -2048,7 +2129,7 @@ async function runContainerAttempt(options) {
|
|
|
2048
2129
|
child.stdin.write(encodeAgentInput(cancel));
|
|
2049
2130
|
}
|
|
2050
2131
|
const removeArgs = options.engine === "container" ? ["delete", "--force", name] : ["rm", "-f", name];
|
|
2051
|
-
const killer =
|
|
2132
|
+
const killer = spawn3(options.engine, removeArgs, { stdio: "ignore", shell: false });
|
|
2052
2133
|
killer.unref();
|
|
2053
2134
|
};
|
|
2054
2135
|
const abort = () => stop("runner_cancelled");
|
|
@@ -2201,7 +2282,7 @@ async function materializeGitTree(source, commitSha, options = {}) {
|
|
|
2201
2282
|
return match && allowedWorkspacePath(match[3]) ? [{ mode: match[1], hash: match[2], path: match[3] }] : [];
|
|
2202
2283
|
});
|
|
2203
2284
|
if (entries.length > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
|
|
2204
|
-
const root = await
|
|
2285
|
+
const root = await mkdtemp2(join22(options.tempRoot ?? tmpdir2(), "odla-git-tree-"));
|
|
2205
2286
|
const targetRoot = join22(root, "source");
|
|
2206
2287
|
await mkdir(targetRoot);
|
|
2207
2288
|
let byteCount = 0;
|
|
@@ -2214,17 +2295,17 @@ async function materializeGitTree(source, commitSha, options = {}) {
|
|
|
2214
2295
|
const target = resolve3(targetRoot, entry.path);
|
|
2215
2296
|
if (!target.startsWith(`${resolve3(targetRoot)}${sep}`)) throw new TypeError("Git tree path escapes workspace");
|
|
2216
2297
|
await mkdir(resolve3(target, ".."), { recursive: true });
|
|
2217
|
-
await
|
|
2298
|
+
await writeFile2(target, content, { flag: "wx", mode: entry.mode === "100755" ? 493 : 420 });
|
|
2218
2299
|
}
|
|
2219
2300
|
return {
|
|
2220
2301
|
root,
|
|
2221
2302
|
sourceDir: targetRoot,
|
|
2222
2303
|
fileCount: entries.length,
|
|
2223
2304
|
byteCount,
|
|
2224
|
-
cleanup: () =>
|
|
2305
|
+
cleanup: () => rm2(root, { recursive: true, force: true })
|
|
2225
2306
|
};
|
|
2226
2307
|
} catch (error) {
|
|
2227
|
-
await
|
|
2308
|
+
await rm2(root, { recursive: true, force: true });
|
|
2228
2309
|
throw error;
|
|
2229
2310
|
}
|
|
2230
2311
|
}
|
|
@@ -2235,7 +2316,7 @@ async function sourceFiles(sourceDir, maxFiles, maxBytes) {
|
|
|
2235
2316
|
for (const entry of await readdir(dir, { withFileTypes: true })) {
|
|
2236
2317
|
if (entry.isDirectory() && SKIP_WORKSPACE_DIRS.has(entry.name)) continue;
|
|
2237
2318
|
if (!entry.isDirectory() && SECRET_WORKSPACE_FILE.test(entry.name)) continue;
|
|
2238
|
-
const path =
|
|
2319
|
+
const path = join32(dir, entry.name);
|
|
2239
2320
|
if (entry.isSymbolicLink()) continue;
|
|
2240
2321
|
if (entry.isDirectory()) {
|
|
2241
2322
|
await walk(path);
|
|
@@ -2258,7 +2339,7 @@ async function sourceFiles(sourceDir, maxFiles, maxBytes) {
|
|
|
2258
2339
|
return files.sort((left, right) => left.relativePath.localeCompare(right.relativePath));
|
|
2259
2340
|
}
|
|
2260
2341
|
async function gitSourceFiles(sourceDir, maxFiles, maxBytes) {
|
|
2261
|
-
const child =
|
|
2342
|
+
const child = spawn32("git", ["ls-files", "-z", "--cached", "--others", "--exclude-standard"], {
|
|
2262
2343
|
cwd: sourceDir,
|
|
2263
2344
|
stdio: ["ignore", "pipe", "pipe"],
|
|
2264
2345
|
shell: false
|
|
@@ -2305,14 +2386,14 @@ async function gitSourceFiles(sourceDir, maxFiles, maxBytes) {
|
|
|
2305
2386
|
}
|
|
2306
2387
|
async function copyTree(files, destination) {
|
|
2307
2388
|
for (const file of files) {
|
|
2308
|
-
const target =
|
|
2389
|
+
const target = join32(destination, file.relativePath);
|
|
2309
2390
|
await mkdir2(resolve22(target, ".."), { recursive: true });
|
|
2310
|
-
await
|
|
2391
|
+
await copyFile2(file.source, target);
|
|
2311
2392
|
await chmod(target, file.mode);
|
|
2312
2393
|
}
|
|
2313
2394
|
}
|
|
2314
2395
|
async function captureGitDiff(root, maxBytes) {
|
|
2315
|
-
const child =
|
|
2396
|
+
const child = spawn32("git", [
|
|
2316
2397
|
"diff",
|
|
2317
2398
|
"--no-index",
|
|
2318
2399
|
"--binary",
|
|
@@ -2348,9 +2429,9 @@ async function stageWorkspace(source, options = {}) {
|
|
|
2348
2429
|
const sourceDir = await realpath2(resolve22(source));
|
|
2349
2430
|
const sourceStat = await stat(sourceDir);
|
|
2350
2431
|
if (!sourceStat.isDirectory()) throw new TypeError("workspace source must be a directory");
|
|
2351
|
-
const root = await
|
|
2352
|
-
const baselineDir =
|
|
2353
|
-
const workspaceDir =
|
|
2432
|
+
const root = await mkdtemp22(join32(options.tempRoot ?? tmpdir22(), "odla-harness-"));
|
|
2433
|
+
const baselineDir = join32(root, "baseline");
|
|
2434
|
+
const workspaceDir = join32(root, "workspace");
|
|
2354
2435
|
await Promise.all([mkdir2(baselineDir), mkdir2(workspaceDir)]);
|
|
2355
2436
|
try {
|
|
2356
2437
|
const maxFiles = options.maxFiles ?? 2e4;
|
|
@@ -2364,10 +2445,10 @@ async function stageWorkspace(source, options = {}) {
|
|
|
2364
2445
|
fileCount: files.length,
|
|
2365
2446
|
byteCount: files.reduce((sum, file) => sum + file.bytes, 0),
|
|
2366
2447
|
patch: (maxBytes2) => captureGitDiff(root, maxBytes2),
|
|
2367
|
-
cleanup: () =>
|
|
2448
|
+
cleanup: () => rm22(root, { recursive: true, force: true })
|
|
2368
2449
|
};
|
|
2369
2450
|
} catch (error) {
|
|
2370
|
-
await
|
|
2451
|
+
await rm22(root, { recursive: true, force: true });
|
|
2371
2452
|
throw error;
|
|
2372
2453
|
}
|
|
2373
2454
|
}
|
|
@@ -2380,9 +2461,9 @@ async function stageWorkspacePair(baselineSource, workspaceSource, options = {})
|
|
|
2380
2461
|
sourceFiles(baselineDirSource, maxFiles, maxBytes),
|
|
2381
2462
|
sourceFiles(workspaceDirSource, maxFiles, maxBytes)
|
|
2382
2463
|
]);
|
|
2383
|
-
const root = await
|
|
2384
|
-
const baselineDir =
|
|
2385
|
-
const workspaceDir =
|
|
2464
|
+
const root = await mkdtemp22(join32(options.tempRoot ?? tmpdir22(), "odla-harness-"));
|
|
2465
|
+
const baselineDir = join32(root, "baseline");
|
|
2466
|
+
const workspaceDir = join32(root, "workspace");
|
|
2386
2467
|
await Promise.all([mkdir2(baselineDir), mkdir2(workspaceDir)]);
|
|
2387
2468
|
try {
|
|
2388
2469
|
await Promise.all([copyTree(baselineFiles, baselineDir), copyTree(workspaceFiles, workspaceDir)]);
|
|
@@ -2393,17 +2474,17 @@ async function stageWorkspacePair(baselineSource, workspaceSource, options = {})
|
|
|
2393
2474
|
fileCount: workspaceFiles.length,
|
|
2394
2475
|
byteCount: workspaceFiles.reduce((sum, file) => sum + file.bytes, 0),
|
|
2395
2476
|
patch: (maxPatchBytes) => captureGitDiff(root, maxPatchBytes),
|
|
2396
|
-
cleanup: () =>
|
|
2477
|
+
cleanup: () => rm22(root, { recursive: true, force: true })
|
|
2397
2478
|
};
|
|
2398
2479
|
} catch (error) {
|
|
2399
|
-
await
|
|
2480
|
+
await rm22(root, { recursive: true, force: true });
|
|
2400
2481
|
throw error;
|
|
2401
2482
|
}
|
|
2402
2483
|
}
|
|
2403
2484
|
|
|
2404
|
-
// ../harness/dist/chunk-
|
|
2405
|
-
import { createHash } from "crypto";
|
|
2406
|
-
import { readFile, readdir as readdir2 } from "fs/promises";
|
|
2485
|
+
// ../harness/dist/chunk-6J2ZETST.js
|
|
2486
|
+
import { createHash as createHash2 } from "crypto";
|
|
2487
|
+
import { readFile as readFile2, readdir as readdir2 } from "fs/promises";
|
|
2407
2488
|
import { relative as relative3, resolve as resolve4 } from "path";
|
|
2408
2489
|
|
|
2409
2490
|
// ../camel/dist/chunk-7FHPOQVP.js
|
|
@@ -2738,21 +2819,21 @@ function validateSnapshot(snapshot, limits) {
|
|
|
2738
2819
|
}
|
|
2739
2820
|
}
|
|
2740
2821
|
|
|
2741
|
-
// ../harness/dist/chunk-
|
|
2822
|
+
// ../harness/dist/chunk-6J2ZETST.js
|
|
2742
2823
|
import { spawn as spawn4 } from "child_process";
|
|
2743
2824
|
import { lstat as lstat2 } from "fs/promises";
|
|
2744
2825
|
import { resolve as resolve23, sep as sep3 } from "path";
|
|
2745
2826
|
import { spawn as spawn23 } from "child_process";
|
|
2746
2827
|
import { getgid as getgid2, getuid as getuid2 } from "process";
|
|
2747
2828
|
import { randomUUID } from "crypto";
|
|
2748
|
-
import { createHash as
|
|
2829
|
+
import { createHash as createHash22, randomUUID as randomUUID2 } from "crypto";
|
|
2749
2830
|
import { createReadStream } from "fs";
|
|
2750
2831
|
import { lstat as lstat22 } from "fs/promises";
|
|
2751
2832
|
import { join as join4 } from "path";
|
|
2752
|
-
import { mkdir as mkdir3, mkdtemp as mkdtemp3, rm as rm3, writeFile as
|
|
2833
|
+
import { mkdir as mkdir3, mkdtemp as mkdtemp3, rm as rm3, writeFile as writeFile3 } from "fs/promises";
|
|
2753
2834
|
import { tmpdir as tmpdir3 } from "os";
|
|
2754
2835
|
import { dirname as dirname4, join as join23, resolve as resolve32, sep as sep22 } from "path";
|
|
2755
|
-
import { readFile as
|
|
2836
|
+
import { readFile as readFile22, readdir as readdir22, stat as stat2 } from "fs/promises";
|
|
2756
2837
|
import { relative as relative22, resolve as resolve42 } from "path";
|
|
2757
2838
|
|
|
2758
2839
|
// ../camel/dist/chunk-LAXU2AVK.js
|
|
@@ -3031,7 +3112,7 @@ function looksLikeDestination(value) {
|
|
|
3031
3112
|
return /^(?:[a-z][a-z0-9+.-]*:\/\/|\/|\\\\)/i.test(text) || /^[\w.-]+\.[a-z]{2,}(?:[/:]|$)/i.test(text);
|
|
3032
3113
|
}
|
|
3033
3114
|
|
|
3034
|
-
// ../harness/dist/chunk-
|
|
3115
|
+
// ../harness/dist/chunk-6J2ZETST.js
|
|
3035
3116
|
import { createHash as createHash3 } from "crypto";
|
|
3036
3117
|
async function digestStagedWorkspace(root, limits) {
|
|
3037
3118
|
const files = [];
|
|
@@ -3048,10 +3129,10 @@ async function digestStagedWorkspace(root, limits) {
|
|
|
3048
3129
|
}
|
|
3049
3130
|
};
|
|
3050
3131
|
await walk(resolve4(root));
|
|
3051
|
-
const hash =
|
|
3132
|
+
const hash = createHash2("sha256");
|
|
3052
3133
|
let bytes = 0;
|
|
3053
3134
|
for (const file of files.sort((left, right) => left.path.localeCompare(right.path))) {
|
|
3054
|
-
const content = await
|
|
3135
|
+
const content = await readFile2(file.target);
|
|
3055
3136
|
bytes += Buffer.byteLength(file.path) + content.byteLength;
|
|
3056
3137
|
if (bytes > limits.maxBytes) throw new TypeError("workspace digest exceeds its byte bound");
|
|
3057
3138
|
hash.update(`${Buffer.byteLength(file.path)}:${file.path}:${content.byteLength}:`);
|
|
@@ -3685,7 +3766,7 @@ async function inspectArtifacts(workspaceDir, recipe2) {
|
|
|
3685
3766
|
}
|
|
3686
3767
|
function hashFile(path) {
|
|
3687
3768
|
return new Promise((accept, reject) => {
|
|
3688
|
-
const hash =
|
|
3769
|
+
const hash = createHash22("sha256");
|
|
3689
3770
|
const stream = createReadStream(path);
|
|
3690
3771
|
stream.on("data", (chunk) => {
|
|
3691
3772
|
hash.update(chunk);
|
|
@@ -3743,7 +3824,7 @@ function digestJson(value) {
|
|
|
3743
3824
|
return digestBytes(JSON.stringify(value));
|
|
3744
3825
|
}
|
|
3745
3826
|
function digestBytes(value) {
|
|
3746
|
-
return `sha256:${
|
|
3827
|
+
return `sha256:${createHash22("sha256").update(value).digest("hex")}`;
|
|
3747
3828
|
}
|
|
3748
3829
|
function integer(value, minimum, maximum) {
|
|
3749
3830
|
return Number.isSafeInteger(value) && value >= minimum && value <= maximum;
|
|
@@ -3864,7 +3945,7 @@ async function materializeCodeRuntimeSource(snapshot, tempRoot = tmpdir3()) {
|
|
|
3864
3945
|
const target = resolve32(sourceDir, file.path);
|
|
3865
3946
|
if (!target.startsWith(`${resolve32(sourceDir)}${sep22}`)) throw new TypeError("Code source path escapes its root");
|
|
3866
3947
|
await mkdir3(dirname4(target), { recursive: true });
|
|
3867
|
-
await
|
|
3948
|
+
await writeFile3(target, file.content, { flag: "wx", mode: 420 });
|
|
3868
3949
|
}
|
|
3869
3950
|
for (const reference of snapshot.references ?? []) {
|
|
3870
3951
|
validateAlias(reference.alias);
|
|
@@ -3879,7 +3960,7 @@ async function materializeCodeRuntimeSource(snapshot, tempRoot = tmpdir3()) {
|
|
|
3879
3960
|
const target = resolve32(sourceDir, path);
|
|
3880
3961
|
if (!target.startsWith(`${resolve32(sourceDir)}${sep22}`)) throw new TypeError("Code reference path escapes its root");
|
|
3881
3962
|
await mkdir3(dirname4(target), { recursive: true });
|
|
3882
|
-
await
|
|
3963
|
+
await writeFile3(target, file.content, { flag: "wx", mode: 292 });
|
|
3883
3964
|
}
|
|
3884
3965
|
}
|
|
3885
3966
|
return { sourceDir, cleanup: () => rm3(root, { recursive: true, force: true }) };
|
|
@@ -3906,7 +3987,7 @@ async function attachCodeRuntimeReferences(workspace, references) {
|
|
|
3906
3987
|
const target = resolve32(root, path);
|
|
3907
3988
|
if (!target.startsWith(`${resolve32(root)}${sep22}`)) throw new TypeError("Code reference path escapes its root");
|
|
3908
3989
|
await mkdir3(dirname4(target), { recursive: true });
|
|
3909
|
-
await
|
|
3990
|
+
await writeFile3(target, file.content, { flag: "wx", mode: 292 });
|
|
3910
3991
|
}
|
|
3911
3992
|
}
|
|
3912
3993
|
}
|
|
@@ -4096,7 +4177,7 @@ async function read(context, request, options, policy) {
|
|
|
4096
4177
|
if (!info.isFile() || info.size > Math.max(options.maxReadBytes ?? 128 * 1024, 2 * 1024 * 1024)) {
|
|
4097
4178
|
throw new TypeError("file is not a bounded regular source file");
|
|
4098
4179
|
}
|
|
4099
|
-
const source = await
|
|
4180
|
+
const source = await readFile22(target);
|
|
4100
4181
|
if (source.includes(0)) throw new TypeError("binary files are not readable through this tool");
|
|
4101
4182
|
const lines = source.toString("utf8").split("\n");
|
|
4102
4183
|
const content = lines.slice(startLine - 1, endLine).join("\n");
|
|
@@ -4397,6 +4478,7 @@ function runtimeResultError(value) {
|
|
|
4397
4478
|
var CodePiRuntimeEngine = class {
|
|
4398
4479
|
constructor(options) {
|
|
4399
4480
|
this.options = options;
|
|
4481
|
+
if (options.imageAuthorization === "cli_embedded" && !/^odla-ai\/pi-agent:embedded-sha256-[0-9a-f]{64}$/.test(options.image)) throw new TypeError("CLI-embedded Pi image must use its content-addressed local tag");
|
|
4400
4482
|
this.#run = options.runAttempt ?? runContainerAttempt;
|
|
4401
4483
|
this.#buildPolicyDigest = digestRuntimeValue(JSON.stringify(options.recipes));
|
|
4402
4484
|
this.#checkpoints = new CodeRuntimeCheckpointManager({
|
|
@@ -4562,6 +4644,7 @@ var CodePiRuntimeEngine = class {
|
|
|
4562
4644
|
const result = await this.#run({
|
|
4563
4645
|
engine: this.options.engine,
|
|
4564
4646
|
image: this.options.image,
|
|
4647
|
+
allowUnpinnedImage: this.options.imageAuthorization === "cli_embedded",
|
|
4565
4648
|
workspaceDir: active.workspace.workspaceDir,
|
|
4566
4649
|
workspaceAccess: "none",
|
|
4567
4650
|
task: lease.task,
|
|
@@ -4855,20 +4938,6 @@ function digestText(value) {
|
|
|
4855
4938
|
return `sha256:${createHash4("sha256").update(value).digest("hex")}`;
|
|
4856
4939
|
}
|
|
4857
4940
|
|
|
4858
|
-
// src/code-images.ts
|
|
4859
|
-
import { execFile as execFile4 } from "child_process";
|
|
4860
|
-
async function prepareCodeImages(engine, images) {
|
|
4861
|
-
for (const image of images) {
|
|
4862
|
-
await new Promise((accept, reject) => {
|
|
4863
|
-
const args = engine === "container" ? ["image", "pull", image] : ["pull", image];
|
|
4864
|
-
execFile4(engine, args, { encoding: "utf8", maxBuffer: 2 * 1024 * 1024, timeout: 10 * 6e4 }, (error) => {
|
|
4865
|
-
if (error) reject(new Error(`could not prepare pinned Code image ${image}`));
|
|
4866
|
-
else accept();
|
|
4867
|
-
});
|
|
4868
|
-
});
|
|
4869
|
-
}
|
|
4870
|
-
}
|
|
4871
|
-
|
|
4872
4941
|
// src/code-connect.ts
|
|
4873
4942
|
async function codeConnect(options) {
|
|
4874
4943
|
const cwd = options.cwd ?? process.cwd();
|
|
@@ -4901,10 +4970,11 @@ async function codeConnect(options) {
|
|
|
4901
4970
|
const out = options.stdout ?? console;
|
|
4902
4971
|
const doFetch = options.fetch ?? fetch;
|
|
4903
4972
|
const engine = await (options.selectEngine ?? selectContainerEngine)(options.engine ?? "auto");
|
|
4904
|
-
await (options.prepareImages ?? prepareCodeImages)(
|
|
4905
|
-
|
|
4906
|
-
...new Set(CODE_BUILD_RECIPES.map((recipe2) => recipe2.image))
|
|
4907
|
-
|
|
4973
|
+
const [piImage] = await (options.prepareImages ?? prepareCodeImages)(
|
|
4974
|
+
engine,
|
|
4975
|
+
[CODE_PI_IMAGE, ...new Set(CODE_BUILD_RECIPES.map((recipe2) => recipe2.image))]
|
|
4976
|
+
);
|
|
4977
|
+
if (!piImage || !/^odla-ai\/pi-agent:embedded-sha256-[0-9a-f]{64}$/.test(piImage)) throw new Error("Code image preflight did not produce the content-addressed embedded Pi runtime");
|
|
4908
4978
|
const hostPlatform = process.platform === "darwin" ? "macos" : "linux";
|
|
4909
4979
|
const hostName = (options.name ?? hostname()).trim();
|
|
4910
4980
|
if (!hostName || hostName.length > 120) throw new Error("--name must contain 1 to 120 characters");
|
|
@@ -4948,7 +5018,8 @@ async function codeConnect(options) {
|
|
|
4948
5018
|
source: descriptor2,
|
|
4949
5019
|
images: {
|
|
4950
5020
|
ready: true,
|
|
4951
|
-
pi:
|
|
5021
|
+
pi: piImage,
|
|
5022
|
+
piSource: "cli_embedded",
|
|
4952
5023
|
recipes: CODE_BUILD_RECIPES.map((recipe2) => ({ id: recipe2.id, image: recipe2.image }))
|
|
4953
5024
|
}
|
|
4954
5025
|
};
|
|
@@ -4963,6 +5034,7 @@ async function codeConnect(options) {
|
|
|
4963
5034
|
engine,
|
|
4964
5035
|
capabilities,
|
|
4965
5036
|
localSource,
|
|
5037
|
+
piImage,
|
|
4966
5038
|
heartbeatMs,
|
|
4967
5039
|
once: options.once === true,
|
|
4968
5040
|
signal: options.signal,
|
|
@@ -4992,7 +5064,8 @@ async function runCodeRuntime(input) {
|
|
|
4992
5064
|
const commandEngine = new CodePiRuntimeEngine({
|
|
4993
5065
|
control,
|
|
4994
5066
|
engine: input.engine,
|
|
4995
|
-
image:
|
|
5067
|
+
image: input.piImage ?? input.capabilities.images.pi,
|
|
5068
|
+
imageAuthorization: "cli_embedded",
|
|
4996
5069
|
recipes: CODE_BUILD_RECIPES,
|
|
4997
5070
|
recipeAuthorization: "registered_recipe",
|
|
4998
5071
|
localSource: input.localSource,
|
|
@@ -6370,7 +6443,7 @@ function securityExecutionDigest(value) {
|
|
|
6370
6443
|
import { existsSync as existsSync8, lstatSync, mkdirSync as mkdirSync3, readFileSync as readFileSync6, readdirSync, writeFileSync as writeFileSync3 } from "fs";
|
|
6371
6444
|
import { homedir } from "os";
|
|
6372
6445
|
import { dirname as dirname6, isAbsolute as isAbsolute5, join as join7, relative as relative5, resolve as resolve9, sep as sep5 } from "path";
|
|
6373
|
-
import { fileURLToPath } from "url";
|
|
6446
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
6374
6447
|
|
|
6375
6448
|
// src/skill-adapters.ts
|
|
6376
6449
|
var PROJECT_INSTRUCTIONS = `<!-- odla-ai agent setup:start -->
|
|
@@ -6426,7 +6499,7 @@ runbook. Do not substitute a remote documentation page for the installed copy.
|
|
|
6426
6499
|
var AGENT_HARNESSES = ["claude", "codex", "cursor", "copilot", "gemini", "agents"];
|
|
6427
6500
|
function installSkill(options = {}) {
|
|
6428
6501
|
const out = options.stdout ?? console;
|
|
6429
|
-
const sourceDir = options.sourceDir ??
|
|
6502
|
+
const sourceDir = options.sourceDir ?? fileURLToPath2(new URL("../skills", import.meta.url));
|
|
6430
6503
|
const files = listFiles(sourceDir);
|
|
6431
6504
|
if (files.length === 0) throw new Error(`no bundled skills found at ${sourceDir}`);
|
|
6432
6505
|
const harnesses = normalizeHarnesses(options.harnesses, options.global === true);
|
|
@@ -7813,6 +7886,7 @@ export {
|
|
|
7813
7886
|
inferGitHubRepository,
|
|
7814
7887
|
CODE_PI_IMAGE,
|
|
7815
7888
|
CODE_BUILD_RECIPES,
|
|
7889
|
+
prepareCodeImages,
|
|
7816
7890
|
codeConnect,
|
|
7817
7891
|
runCodeRuntime,
|
|
7818
7892
|
doctor,
|
|
@@ -7836,4 +7910,4 @@ export {
|
|
|
7836
7910
|
exitCodeFor,
|
|
7837
7911
|
runCli
|
|
7838
7912
|
};
|
|
7839
|
-
//# sourceMappingURL=chunk-
|
|
7913
|
+
//# sourceMappingURL=chunk-GAFC4EPJ.js.map
|