@odla-ai/cli 0.16.3 → 0.16.5
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 +158 -83
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-YWC7F5T3.js → chunk-GLY5BN6D.js} +148 -74
- package/dist/chunk-GLY5BN6D.js.map +1 -0
- package/dist/index.cjs +160 -83
- 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/index.cjs
CHANGED
|
@@ -61,6 +61,7 @@ __export(index_exports, {
|
|
|
61
61
|
isTerminalHostedSecurityStatus: () => isTerminalHostedSecurityStatus,
|
|
62
62
|
listGitHubSecuritySources: () => listGitHubSecuritySources,
|
|
63
63
|
listHostedSecurityJobs: () => listHostedSecurityJobs,
|
|
64
|
+
prepareCodeImages: () => prepareCodeImages,
|
|
64
65
|
printCapabilities: () => printCapabilities,
|
|
65
66
|
provision: () => provision,
|
|
66
67
|
redactSecrets: () => redactSecrets,
|
|
@@ -1992,8 +1993,8 @@ function printStatus(status, json, out) {
|
|
|
1992
1993
|
|
|
1993
1994
|
// src/code-connect.ts
|
|
1994
1995
|
var import_node_fs7 = require("fs");
|
|
1995
|
-
var
|
|
1996
|
-
var
|
|
1996
|
+
var import_node_os2 = require("os");
|
|
1997
|
+
var import_node_path5 = require("path");
|
|
1997
1998
|
|
|
1998
1999
|
// ../harness/dist/chunk-QTUEF2HZ.js
|
|
1999
2000
|
var HARNESS_PROTOCOL_VERSION = 1;
|
|
@@ -2076,7 +2077,7 @@ function encodeAgentInput(message2) {
|
|
|
2076
2077
|
`;
|
|
2077
2078
|
}
|
|
2078
2079
|
|
|
2079
|
-
// ../harness/dist/chunk-
|
|
2080
|
+
// ../harness/dist/chunk-IONC45N6.js
|
|
2080
2081
|
var import_child_process = require("child_process");
|
|
2081
2082
|
var import_fs = require("fs");
|
|
2082
2083
|
var import_promises2 = require("fs/promises");
|
|
@@ -2129,7 +2130,7 @@ async function selectContainerEngine(requested = "auto", options = {}) {
|
|
|
2129
2130
|
throw new TypeError("no rootless Podman found; install Podman or explicitly choose --engine docker after reviewing its daemon boundary");
|
|
2130
2131
|
}
|
|
2131
2132
|
if (platform === "darwin") {
|
|
2132
|
-
throw new TypeError("
|
|
2133
|
+
throw new TypeError("Apple container is not installed; on Apple Silicon macOS 26 run `brew install container`, then retry (Podman Machine is the fallback)");
|
|
2133
2134
|
}
|
|
2134
2135
|
throw new TypeError("no supported container engine found");
|
|
2135
2136
|
}
|
|
@@ -2534,7 +2535,7 @@ async function captureGitDiff(root, maxBytes) {
|
|
|
2534
2535
|
if (code !== 0 && code !== 1) {
|
|
2535
2536
|
throw new Error(`git diff failed: ${Buffer.concat(stderr).toString("utf8").slice(0, 1e3)}`);
|
|
2536
2537
|
}
|
|
2537
|
-
return Buffer.concat(stdout).toString("utf8").replaceAll("a/baseline/", "a/").replaceAll("b/workspace/", "b/").replaceAll("--- a/baseline", "--- a").replaceAll("+++ b/workspace", "+++ b");
|
|
2538
|
+
return Buffer.concat(stdout).toString("utf8").replaceAll("a/baseline/", "a/").replaceAll("a/workspace/", "a/").replaceAll("b/baseline/", "b/").replaceAll("b/workspace/", "b/").replaceAll("--- a/baseline", "--- a").replaceAll("+++ b/workspace", "+++ b");
|
|
2538
2539
|
}
|
|
2539
2540
|
async function stageWorkspace(source, options = {}) {
|
|
2540
2541
|
const sourceDir = await (0, import_promises4.realpath)((0, import_path4.resolve)(source));
|
|
@@ -2593,7 +2594,7 @@ async function stageWorkspacePair(baselineSource, workspaceSource, options = {})
|
|
|
2593
2594
|
}
|
|
2594
2595
|
}
|
|
2595
2596
|
|
|
2596
|
-
// ../harness/dist/chunk-
|
|
2597
|
+
// ../harness/dist/chunk-QGDLTDYH.js
|
|
2597
2598
|
var import_crypto = require("crypto");
|
|
2598
2599
|
var import_promises5 = require("fs/promises");
|
|
2599
2600
|
var import_path5 = require("path");
|
|
@@ -2930,7 +2931,7 @@ function validateSnapshot(snapshot, limits) {
|
|
|
2930
2931
|
}
|
|
2931
2932
|
}
|
|
2932
2933
|
|
|
2933
|
-
// ../harness/dist/chunk-
|
|
2934
|
+
// ../harness/dist/chunk-QGDLTDYH.js
|
|
2934
2935
|
var import_child_process4 = require("child_process");
|
|
2935
2936
|
var import_promises6 = require("fs/promises");
|
|
2936
2937
|
var import_path6 = require("path");
|
|
@@ -3223,7 +3224,7 @@ function looksLikeDestination(value) {
|
|
|
3223
3224
|
return /^(?:[a-z][a-z0-9+.-]*:\/\/|\/|\\\\)/i.test(text) || /^[\w.-]+\.[a-z]{2,}(?:[/:]|$)/i.test(text);
|
|
3224
3225
|
}
|
|
3225
3226
|
|
|
3226
|
-
// ../harness/dist/chunk-
|
|
3227
|
+
// ../harness/dist/chunk-QGDLTDYH.js
|
|
3227
3228
|
var import_crypto4 = require("crypto");
|
|
3228
3229
|
async function digestStagedWorkspace(root, limits) {
|
|
3229
3230
|
const files = [];
|
|
@@ -4589,6 +4590,7 @@ function runtimeResultError(value) {
|
|
|
4589
4590
|
var CodePiRuntimeEngine = class {
|
|
4590
4591
|
constructor(options) {
|
|
4591
4592
|
this.options = options;
|
|
4593
|
+
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");
|
|
4592
4594
|
this.#run = options.runAttempt ?? runContainerAttempt;
|
|
4593
4595
|
this.#buildPolicyDigest = digestRuntimeValue(JSON.stringify(options.recipes));
|
|
4594
4596
|
this.#checkpoints = new CodeRuntimeCheckpointManager({
|
|
@@ -4754,6 +4756,7 @@ var CodePiRuntimeEngine = class {
|
|
|
4754
4756
|
const result = await this.#run({
|
|
4755
4757
|
engine: this.options.engine,
|
|
4756
4758
|
image: this.options.image,
|
|
4759
|
+
allowUnpinnedImage: this.options.imageAuthorization === "cli_embedded",
|
|
4757
4760
|
workspaceDir: active.workspace.workspaceDir,
|
|
4758
4761
|
workspaceAccess: "none",
|
|
4759
4762
|
task: lease.task,
|
|
@@ -5263,23 +5266,18 @@ function digestText(value) {
|
|
|
5263
5266
|
|
|
5264
5267
|
// src/code-images.ts
|
|
5265
5268
|
var import_node_child_process4 = require("child_process");
|
|
5266
|
-
|
|
5267
|
-
|
|
5268
|
-
|
|
5269
|
-
|
|
5270
|
-
|
|
5271
|
-
if (error) reject(new Error(`could not prepare pinned Code image ${image}`));
|
|
5272
|
-
else accept();
|
|
5273
|
-
});
|
|
5274
|
-
});
|
|
5275
|
-
}
|
|
5276
|
-
}
|
|
5269
|
+
var import_node_crypto2 = require("crypto");
|
|
5270
|
+
var import_promises10 = require("fs/promises");
|
|
5271
|
+
var import_node_os = require("os");
|
|
5272
|
+
var import_node_path4 = require("path");
|
|
5273
|
+
var import_node_url2 = require("url");
|
|
5277
5274
|
|
|
5278
5275
|
// src/code-runtime-config.ts
|
|
5279
|
-
var CODE_PI_IMAGE = "
|
|
5276
|
+
var CODE_PI_IMAGE = "odla-ai/pi-agent:embedded";
|
|
5277
|
+
var CODE_NODE_IMAGE = "node:24-alpine@sha256:a0b9bf06e4e6193cf7a0f58816cc935ff8c2a908f81e6f1a95432d679c54fbfd";
|
|
5280
5278
|
var CODE_BUILD_RECIPES = Object.freeze([{
|
|
5281
5279
|
id: "odla-code-contracts",
|
|
5282
|
-
image:
|
|
5280
|
+
image: CODE_NODE_IMAGE,
|
|
5283
5281
|
command: [
|
|
5284
5282
|
"node",
|
|
5285
5283
|
// The clean source mount deliberately has no node_modules. Reuse the
|
|
@@ -5299,10 +5297,84 @@ var CODE_BUILD_RECIPES = Object.freeze([{
|
|
|
5299
5297
|
pids: 128
|
|
5300
5298
|
}]);
|
|
5301
5299
|
|
|
5300
|
+
// src/code-images.ts
|
|
5301
|
+
var runCodeImageCommand = (command, args, stdio) => new Promise((accept, reject) => {
|
|
5302
|
+
const child = (0, import_node_child_process4.spawn)(command, [...args], { shell: false, stdio });
|
|
5303
|
+
child.once("error", reject);
|
|
5304
|
+
child.once("exit", (code, signal) => {
|
|
5305
|
+
if (code === 0) accept();
|
|
5306
|
+
else reject(new Error(`${command} ${args.join(" ")} exited ${code ?? signal ?? "without a status"}`));
|
|
5307
|
+
});
|
|
5308
|
+
});
|
|
5309
|
+
async function prepareCodeImages(engine, images, run = runCodeImageCommand, buildEmbedded = buildEmbeddedPiImage, nameEmbedded = embeddedPiImageName) {
|
|
5310
|
+
if (engine === "container") {
|
|
5311
|
+
try {
|
|
5312
|
+
await run(engine, ["system", "start"], "inherit");
|
|
5313
|
+
} catch {
|
|
5314
|
+
throw new Error("Apple container could not start; run `container system start` once to complete its lightweight VM setup, then retry");
|
|
5315
|
+
}
|
|
5316
|
+
}
|
|
5317
|
+
const prepared = [];
|
|
5318
|
+
for (const image of images) {
|
|
5319
|
+
const runtimeImage = image === CODE_PI_IMAGE ? await nameEmbedded() : image;
|
|
5320
|
+
const inspectArgs = ["image", "inspect", runtimeImage];
|
|
5321
|
+
try {
|
|
5322
|
+
await run(engine, inspectArgs, "ignore");
|
|
5323
|
+
prepared.push(runtimeImage);
|
|
5324
|
+
continue;
|
|
5325
|
+
} catch {
|
|
5326
|
+
}
|
|
5327
|
+
if (image === CODE_PI_IMAGE) {
|
|
5328
|
+
try {
|
|
5329
|
+
await buildEmbedded(engine, runtimeImage, run);
|
|
5330
|
+
} catch (error) {
|
|
5331
|
+
const detail = error instanceof Error && error.message ? `: ${error.message}` : "";
|
|
5332
|
+
throw new Error(`could not prepare CLI-embedded Code image${detail}`);
|
|
5333
|
+
}
|
|
5334
|
+
prepared.push(runtimeImage);
|
|
5335
|
+
continue;
|
|
5336
|
+
}
|
|
5337
|
+
const args = engine === "container" ? ["image", "pull", image] : ["pull", image];
|
|
5338
|
+
try {
|
|
5339
|
+
await run(engine, args, "inherit");
|
|
5340
|
+
} catch (error) {
|
|
5341
|
+
const detail = error instanceof Error && error.message ? `: ${error.message}` : "";
|
|
5342
|
+
throw new Error(`could not prepare pinned Code image ${image}${detail}`);
|
|
5343
|
+
}
|
|
5344
|
+
prepared.push(image);
|
|
5345
|
+
}
|
|
5346
|
+
return prepared;
|
|
5347
|
+
}
|
|
5348
|
+
function embeddedPiAssetPath() {
|
|
5349
|
+
return (0, import_node_url2.fileURLToPath)(new URL("./runtime/pi-agent.js", importMetaUrl));
|
|
5350
|
+
}
|
|
5351
|
+
async function embeddedPiImageName() {
|
|
5352
|
+
const bundle = await (0, import_promises10.readFile)(embeddedPiAssetPath()).catch(() => {
|
|
5353
|
+
throw new Error("CLI-embedded Pi runtime is missing; reinstall this exact @odla-ai/cli version");
|
|
5354
|
+
});
|
|
5355
|
+
return `odla-ai/pi-agent:embedded-sha256-${(0, import_node_crypto2.createHash)("sha256").update(bundle).digest("hex")}`;
|
|
5356
|
+
}
|
|
5357
|
+
async function buildEmbeddedPiImage(engine, image, run) {
|
|
5358
|
+
const context = await (0, import_promises10.mkdtemp)((0, import_node_path4.join)((0, import_node_os.tmpdir)(), "odla-code-pi-"));
|
|
5359
|
+
try {
|
|
5360
|
+
await (0, import_promises10.copyFile)(embeddedPiAssetPath(), (0, import_node_path4.join)(context, "pi-agent.js"));
|
|
5361
|
+
await (0, import_promises10.writeFile)((0, import_node_path4.join)(context, "Dockerfile"), [
|
|
5362
|
+
`FROM ${CODE_NODE_IMAGE}`,
|
|
5363
|
+
"COPY pi-agent.js /opt/odla/pi-agent.js",
|
|
5364
|
+
"WORKDIR /workspace",
|
|
5365
|
+
'ENTRYPOINT ["node", "/opt/odla/pi-agent.js"]',
|
|
5366
|
+
""
|
|
5367
|
+
].join("\n"), { mode: 384 });
|
|
5368
|
+
await run(engine, ["build", "--tag", image, context], "inherit");
|
|
5369
|
+
} finally {
|
|
5370
|
+
await (0, import_promises10.rm)(context, { recursive: true, force: true });
|
|
5371
|
+
}
|
|
5372
|
+
}
|
|
5373
|
+
|
|
5302
5374
|
// src/code-connect.ts
|
|
5303
5375
|
async function codeConnect(options) {
|
|
5304
5376
|
const cwd = options.cwd ?? process.cwd();
|
|
5305
|
-
const configPath = (0,
|
|
5377
|
+
const configPath = (0, import_node_path5.resolve)(cwd, options.configPath);
|
|
5306
5378
|
const cfg = (0, import_node_fs7.existsSync)(configPath) ? await loadProjectConfig(configPath) : null;
|
|
5307
5379
|
const requestedAppId = options.appId?.trim();
|
|
5308
5380
|
if (requestedAppId && !/^[a-z0-9][a-z0-9-]{1,62}$/.test(requestedAppId)) {
|
|
@@ -5331,12 +5403,13 @@ async function codeConnect(options) {
|
|
|
5331
5403
|
const out = options.stdout ?? console;
|
|
5332
5404
|
const doFetch = options.fetch ?? fetch;
|
|
5333
5405
|
const engine = await (options.selectEngine ?? selectContainerEngine)(options.engine ?? "auto");
|
|
5334
|
-
await (options.prepareImages ?? prepareCodeImages)(
|
|
5335
|
-
|
|
5336
|
-
...new Set(CODE_BUILD_RECIPES.map((recipe2) => recipe2.image))
|
|
5337
|
-
|
|
5406
|
+
const [piImage] = await (options.prepareImages ?? prepareCodeImages)(
|
|
5407
|
+
engine,
|
|
5408
|
+
[CODE_PI_IMAGE, ...new Set(CODE_BUILD_RECIPES.map((recipe2) => recipe2.image))]
|
|
5409
|
+
);
|
|
5410
|
+
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");
|
|
5338
5411
|
const hostPlatform = process.platform === "darwin" ? "macos" : "linux";
|
|
5339
|
-
const hostName = (options.name ?? (0,
|
|
5412
|
+
const hostName = (options.name ?? (0, import_node_os2.hostname)()).trim();
|
|
5340
5413
|
if (!hostName || hostName.length > 120) throw new Error("--name must contain 1 to 120 characters");
|
|
5341
5414
|
const repository = await inferGitHubRepository(cwd, options.readGitOrigin);
|
|
5342
5415
|
const localSource = await (options.prepareLocalSource ?? prepareCodeLocalSource)(
|
|
@@ -5373,12 +5446,13 @@ async function codeConnect(options) {
|
|
|
5373
5446
|
platform: hostPlatform,
|
|
5374
5447
|
arch: process.arch,
|
|
5375
5448
|
engines: [engine],
|
|
5376
|
-
cpuCount: (0,
|
|
5377
|
-
memoryBytes: (0,
|
|
5449
|
+
cpuCount: (0, import_node_os2.cpus)().length,
|
|
5450
|
+
memoryBytes: (0, import_node_os2.totalmem)(),
|
|
5378
5451
|
source: descriptor2,
|
|
5379
5452
|
images: {
|
|
5380
5453
|
ready: true,
|
|
5381
|
-
pi:
|
|
5454
|
+
pi: piImage,
|
|
5455
|
+
piSource: "cli_embedded",
|
|
5382
5456
|
recipes: CODE_BUILD_RECIPES.map((recipe2) => ({ id: recipe2.id, image: recipe2.image }))
|
|
5383
5457
|
}
|
|
5384
5458
|
};
|
|
@@ -5393,6 +5467,7 @@ async function codeConnect(options) {
|
|
|
5393
5467
|
engine,
|
|
5394
5468
|
capabilities,
|
|
5395
5469
|
localSource,
|
|
5470
|
+
piImage,
|
|
5396
5471
|
heartbeatMs,
|
|
5397
5472
|
once: options.once === true,
|
|
5398
5473
|
signal: options.signal,
|
|
@@ -5422,7 +5497,8 @@ async function runCodeRuntime(input) {
|
|
|
5422
5497
|
const commandEngine = new CodePiRuntimeEngine({
|
|
5423
5498
|
control,
|
|
5424
5499
|
engine: input.engine,
|
|
5425
|
-
image:
|
|
5500
|
+
image: input.piImage ?? input.capabilities.images.pi,
|
|
5501
|
+
imageAuthorization: "cli_embedded",
|
|
5426
5502
|
recipes: CODE_BUILD_RECIPES,
|
|
5427
5503
|
recipeAuthorization: "registered_recipe",
|
|
5428
5504
|
localSource: input.localSource,
|
|
@@ -5519,12 +5595,12 @@ async function codeCommand(parsed, dependencies) {
|
|
|
5519
5595
|
// src/doctor-checks.ts
|
|
5520
5596
|
var import_node_child_process6 = require("child_process");
|
|
5521
5597
|
var import_node_fs9 = require("fs");
|
|
5522
|
-
var
|
|
5598
|
+
var import_node_path7 = require("path");
|
|
5523
5599
|
|
|
5524
5600
|
// src/wrangler.ts
|
|
5525
5601
|
var import_node_child_process5 = require("child_process");
|
|
5526
5602
|
var import_node_fs8 = require("fs");
|
|
5527
|
-
var
|
|
5603
|
+
var import_node_path6 = require("path");
|
|
5528
5604
|
var defaultRunner = (cmd, args, opts) => new Promise((resolvePromise, reject) => {
|
|
5529
5605
|
const child = (0, import_node_child_process5.spawn)(cmd, args, { cwd: opts?.cwd, stdio: ["pipe", "pipe", "pipe"] });
|
|
5530
5606
|
let stdout = "";
|
|
@@ -5538,7 +5614,7 @@ var defaultRunner = (cmd, args, opts) => new Promise((resolvePromise, reject) =>
|
|
|
5538
5614
|
var WRANGLER_CONFIG_FILES = ["wrangler.jsonc", "wrangler.json", "wrangler.toml"];
|
|
5539
5615
|
function findWranglerConfig(rootDir) {
|
|
5540
5616
|
for (const name of WRANGLER_CONFIG_FILES) {
|
|
5541
|
-
const path = (0,
|
|
5617
|
+
const path = (0, import_node_path6.join)(rootDir, name);
|
|
5542
5618
|
if ((0, import_node_fs8.existsSync)(path)) return path;
|
|
5543
5619
|
}
|
|
5544
5620
|
return null;
|
|
@@ -5644,10 +5720,10 @@ function wranglerWarnings(rootDir) {
|
|
|
5644
5720
|
for (const { label, block } of blocks) {
|
|
5645
5721
|
const assets = block.assets;
|
|
5646
5722
|
if (assets?.directory) {
|
|
5647
|
-
const dir = (0,
|
|
5648
|
-
if (dir === (0,
|
|
5723
|
+
const dir = (0, import_node_path7.resolve)(rootDir, assets.directory);
|
|
5724
|
+
if (dir === (0, import_node_path7.resolve)(rootDir)) {
|
|
5649
5725
|
warnings.push(`${label}assets.directory is the project root \u2014 point it at a dedicated build dir (wrangler dev fails with "spawn EBADF")`);
|
|
5650
|
-
} else if ((0, import_node_fs9.existsSync)((0,
|
|
5726
|
+
} else if ((0, import_node_fs9.existsSync)((0, import_node_path7.join)(dir, "node_modules"))) {
|
|
5651
5727
|
warnings.push(`${label}assets.directory contains node_modules \u2014 wrangler dev's watcher will exhaust file descriptors`);
|
|
5652
5728
|
}
|
|
5653
5729
|
}
|
|
@@ -5682,7 +5758,7 @@ function o11yProjectWarnings(rootDir) {
|
|
|
5682
5758
|
warnings.push("cannot verify o11y Worker instrumentation \u2014 add a parseable wrangler.jsonc/json config");
|
|
5683
5759
|
return warnings;
|
|
5684
5760
|
}
|
|
5685
|
-
const main = typeof config.main === "string" ? (0,
|
|
5761
|
+
const main = typeof config.main === "string" ? (0, import_node_path7.resolve)(rootDir, config.main) : null;
|
|
5686
5762
|
if (!main || !(0, import_node_fs9.existsSync)(main)) {
|
|
5687
5763
|
warnings.push("cannot verify o11y Worker instrumentation \u2014 wrangler main is missing or unreadable");
|
|
5688
5764
|
} else {
|
|
@@ -5712,7 +5788,7 @@ function calendarProjectWarnings(rootDir) {
|
|
|
5712
5788
|
}
|
|
5713
5789
|
function readPackageJson(rootDir) {
|
|
5714
5790
|
try {
|
|
5715
|
-
return JSON.parse((0, import_node_fs9.readFileSync)((0,
|
|
5791
|
+
return JSON.parse((0, import_node_fs9.readFileSync)((0, import_node_path7.join)(rootDir, "package.json"), "utf8"));
|
|
5716
5792
|
} catch {
|
|
5717
5793
|
return null;
|
|
5718
5794
|
}
|
|
@@ -5914,11 +5990,11 @@ function harnessOption(value, flag) {
|
|
|
5914
5990
|
|
|
5915
5991
|
// src/init.ts
|
|
5916
5992
|
var import_node_fs10 = require("fs");
|
|
5917
|
-
var
|
|
5993
|
+
var import_node_path8 = require("path");
|
|
5918
5994
|
function initProject(options) {
|
|
5919
5995
|
const out = options.stdout ?? console;
|
|
5920
|
-
const rootDir = (0,
|
|
5921
|
-
const configPath = (0,
|
|
5996
|
+
const rootDir = (0, import_node_path8.resolve)(options.rootDir ?? process.cwd());
|
|
5997
|
+
const configPath = (0, import_node_path8.resolve)(rootDir, options.configPath ?? "odla.config.mjs");
|
|
5922
5998
|
if ((0, import_node_fs10.existsSync)(configPath) && !options.force) {
|
|
5923
5999
|
throw new Error(`${configPath} already exists. Pass --force to overwrite.`);
|
|
5924
6000
|
}
|
|
@@ -5929,12 +6005,12 @@ function initProject(options) {
|
|
|
5929
6005
|
const services = options.services?.length ? options.services : ["db", "ai"];
|
|
5930
6006
|
if (services.includes("calendar") && !services.includes("db")) throw new Error("--services calendar requires db");
|
|
5931
6007
|
const aiProvider = options.aiProvider ?? "anthropic";
|
|
5932
|
-
(0, import_node_fs10.mkdirSync)((0,
|
|
5933
|
-
(0, import_node_fs10.mkdirSync)((0,
|
|
5934
|
-
(0, import_node_fs10.mkdirSync)((0,
|
|
6008
|
+
(0, import_node_fs10.mkdirSync)((0, import_node_path8.dirname)(configPath), { recursive: true });
|
|
6009
|
+
(0, import_node_fs10.mkdirSync)((0, import_node_path8.resolve)(rootDir, "src/odla"), { recursive: true });
|
|
6010
|
+
(0, import_node_fs10.mkdirSync)((0, import_node_path8.resolve)(rootDir, ".odla"), { recursive: true });
|
|
5935
6011
|
(0, import_node_fs10.writeFileSync)(configPath, configTemplate({ appId: options.appId, name: options.name, envs, services, aiProvider }));
|
|
5936
|
-
writeIfMissing((0,
|
|
5937
|
-
writeIfMissing((0,
|
|
6012
|
+
writeIfMissing((0, import_node_path8.resolve)(rootDir, "src/odla/schema.mjs"), schemaTemplate());
|
|
6013
|
+
writeIfMissing((0, import_node_path8.resolve)(rootDir, "src/odla/rules.mjs"), rulesTemplate());
|
|
5938
6014
|
ensureGitignore(rootDir);
|
|
5939
6015
|
out.log(`created ${relativeDisplay(configPath, rootDir)}`);
|
|
5940
6016
|
out.log("created src/odla/schema.mjs and src/odla/rules.mjs");
|
|
@@ -6584,7 +6660,7 @@ async function resolveVaultWrite(options) {
|
|
|
6584
6660
|
}
|
|
6585
6661
|
|
|
6586
6662
|
// src/security-command-context.ts
|
|
6587
|
-
var
|
|
6663
|
+
var import_promises11 = require("readline/promises");
|
|
6588
6664
|
async function hostedSecurityContext(parsed, dependencies) {
|
|
6589
6665
|
const configPath = stringOpt(parsed.options.config) ?? "odla.config.mjs";
|
|
6590
6666
|
const cfg = await loadProjectConfig(configPath);
|
|
@@ -6610,7 +6686,7 @@ async function hostedSecurityContext(parsed, dependencies) {
|
|
|
6610
6686
|
async function interactiveConfirmation(message2, dependencies) {
|
|
6611
6687
|
if (dependencies.confirm) return dependencies.confirm(message2);
|
|
6612
6688
|
if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
|
|
6613
|
-
const prompt = (0,
|
|
6689
|
+
const prompt = (0, import_promises11.createInterface)({ input: process.stdin, output: process.stdout });
|
|
6614
6690
|
try {
|
|
6615
6691
|
const answer = await prompt.question(`${message2} [y/N] `);
|
|
6616
6692
|
return /^y(?:es)?$/i.test(answer.trim());
|
|
@@ -6737,7 +6813,7 @@ function hostedSeverity(value, flag) {
|
|
|
6737
6813
|
var import_security2 = require("@odla-ai/security");
|
|
6738
6814
|
|
|
6739
6815
|
// src/security.ts
|
|
6740
|
-
var
|
|
6816
|
+
var import_node_path9 = require("path");
|
|
6741
6817
|
var import_security = require("@odla-ai/security");
|
|
6742
6818
|
var import_node3 = require("@odla-ai/security/node");
|
|
6743
6819
|
async function runHostedSecurity(options) {
|
|
@@ -6749,9 +6825,9 @@ async function runHostedSecurity(options) {
|
|
|
6749
6825
|
const appId = selfAudit ? "odla-ai" : cfg.app.id;
|
|
6750
6826
|
const env = selfAudit ? "prod" : selectEnv(options.env, cfg.envs, cfg.configPath, cfg.rootDir);
|
|
6751
6827
|
const platform = options.platform ?? cfg?.platformUrl ?? "https://odla.ai";
|
|
6752
|
-
const target = (0,
|
|
6753
|
-
const output = (0,
|
|
6754
|
-
const outputRelative = (0,
|
|
6828
|
+
const target = (0, import_node_path9.resolve)(options.target ?? cfg?.rootDir ?? ".");
|
|
6829
|
+
const output = (0, import_node_path9.resolve)(options.out ?? (0, import_node_path9.resolve)(target, ".odla/security/hosted"));
|
|
6830
|
+
const outputRelative = (0, import_node_path9.relative)(target, output).split(import_node_path9.sep).join("/");
|
|
6755
6831
|
if (!outputRelative) throw new Error("Hosted security output cannot be the repository root");
|
|
6756
6832
|
const profile = profileFor(options.profile ?? "odla", options.maxHuntTasks ?? 12);
|
|
6757
6833
|
const tokenRequest = {
|
|
@@ -6763,7 +6839,7 @@ async function runHostedSecurity(options) {
|
|
|
6763
6839
|
};
|
|
6764
6840
|
const token = await injectedToken(options, tokenRequest);
|
|
6765
6841
|
const snapshot = await (0, import_node3.snapshotDirectory)(target, {
|
|
6766
|
-
exclude: !outputRelative.startsWith("../") && !(0,
|
|
6842
|
+
exclude: !outputRelative.startsWith("../") && !(0, import_node_path9.isAbsolute)(outputRelative) ? [outputRelative] : []
|
|
6767
6843
|
});
|
|
6768
6844
|
const hosted = await (0, import_security.createPlatformSecurityReasoners)({
|
|
6769
6845
|
platform,
|
|
@@ -6781,7 +6857,7 @@ async function runHostedSecurity(options) {
|
|
|
6781
6857
|
});
|
|
6782
6858
|
const harness = (0, import_security.createSecurityHarness)({
|
|
6783
6859
|
profile,
|
|
6784
|
-
store: new import_node3.FileRunStore((0,
|
|
6860
|
+
store: new import_node3.FileRunStore((0, import_node_path9.resolve)(output, "state")),
|
|
6785
6861
|
discoveryReasoner: hosted.discoveryReasoner,
|
|
6786
6862
|
validationReasoner: hosted.validationReasoner,
|
|
6787
6863
|
policy: {
|
|
@@ -6805,7 +6881,7 @@ async function runHostedSecurity(options) {
|
|
|
6805
6881
|
function selectEnv(requested, declared, configPath, rootDir) {
|
|
6806
6882
|
const env = requested ?? (declared.includes("dev") ? "dev" : declared[0]);
|
|
6807
6883
|
if (!env || !declared.includes(env)) {
|
|
6808
|
-
const shown = (0,
|
|
6884
|
+
const shown = (0, import_node_path9.relative)(rootDir, configPath) || configPath;
|
|
6809
6885
|
throw new Error(`env "${env ?? ""}" is not declared in ${shown}`);
|
|
6810
6886
|
}
|
|
6811
6887
|
return env;
|
|
@@ -6834,7 +6910,7 @@ function printSummary(out, appId, env, run, report2, output) {
|
|
|
6834
6910
|
out.log(` coverage: ${report2.coverageStatus} ${complete}/${report2.coverage.length} blocked=${report2.metrics.blockedCells} shallow=${report2.metrics.shallowCells} unscheduled=${report2.metrics.unscheduledCells} budget_exhausted=${report2.metrics.budgetExhaustedCells}`);
|
|
6835
6911
|
if (report2.callBudget) out.log(` calls: discovery=${formatBudget(report2.callBudget.discovery)} validation=${formatBudget(report2.callBudget.validation)}`);
|
|
6836
6912
|
out.log(` findings: confirmed=${report2.metrics.confirmed} needs_reproduction=${report2.metrics.needsReproduction} candidates=${report2.metrics.candidates}`);
|
|
6837
|
-
out.log(` report: ${(0,
|
|
6913
|
+
out.log(` report: ${(0, import_node_path9.resolve)(output, "REPORT.md")}`);
|
|
6838
6914
|
}
|
|
6839
6915
|
function formatBudget(usage) {
|
|
6840
6916
|
return usage ? `${usage.usedCalls}/${usage.maxCalls} skipped=${usage.skippedCalls}` : "caller-managed";
|
|
@@ -7284,9 +7360,9 @@ async function securityStatus(parsed, dependencies) {
|
|
|
7284
7360
|
|
|
7285
7361
|
// src/skill.ts
|
|
7286
7362
|
var import_node_fs11 = require("fs");
|
|
7287
|
-
var
|
|
7288
|
-
var
|
|
7289
|
-
var
|
|
7363
|
+
var import_node_os3 = require("os");
|
|
7364
|
+
var import_node_path10 = require("path");
|
|
7365
|
+
var import_node_url3 = require("url");
|
|
7290
7366
|
|
|
7291
7367
|
// src/skill-adapters.ts
|
|
7292
7368
|
var PROJECT_INSTRUCTIONS = `<!-- odla-ai agent setup:start -->
|
|
@@ -7342,12 +7418,12 @@ runbook. Do not substitute a remote documentation page for the installed copy.
|
|
|
7342
7418
|
var AGENT_HARNESSES = ["claude", "codex", "cursor", "copilot", "gemini", "agents"];
|
|
7343
7419
|
function installSkill(options = {}) {
|
|
7344
7420
|
const out = options.stdout ?? console;
|
|
7345
|
-
const sourceDir = options.sourceDir ?? (0,
|
|
7421
|
+
const sourceDir = options.sourceDir ?? (0, import_node_url3.fileURLToPath)(new URL("../skills", importMetaUrl));
|
|
7346
7422
|
const files = listFiles(sourceDir);
|
|
7347
7423
|
if (files.length === 0) throw new Error(`no bundled skills found at ${sourceDir}`);
|
|
7348
7424
|
const harnesses = normalizeHarnesses(options.harnesses, options.global === true);
|
|
7349
|
-
const root = (0,
|
|
7350
|
-
const home = (0,
|
|
7425
|
+
const root = (0, import_node_path10.resolve)(options.dir ?? process.cwd());
|
|
7426
|
+
const home = (0, import_node_path10.resolve)(options.homeDir ?? (0, import_node_os3.homedir)());
|
|
7351
7427
|
const plans = /* @__PURE__ */ new Map();
|
|
7352
7428
|
const targets = /* @__PURE__ */ new Map();
|
|
7353
7429
|
const rememberTarget = (harness, target) => {
|
|
@@ -7361,48 +7437,48 @@ function installSkill(options = {}) {
|
|
|
7361
7437
|
plans.set(target, { target, content, boundary, managedMerge });
|
|
7362
7438
|
};
|
|
7363
7439
|
const planSkillTree = (targetDir2, boundary = root) => {
|
|
7364
|
-
for (const rel of files) plan((0,
|
|
7440
|
+
for (const rel of files) plan((0, import_node_path10.join)(targetDir2, rel), (0, import_node_fs11.readFileSync)((0, import_node_path10.join)(sourceDir, rel), "utf8"), false, boundary);
|
|
7365
7441
|
};
|
|
7366
7442
|
let targetDir;
|
|
7367
7443
|
if (options.global) {
|
|
7368
|
-
const claudeRoot = (0,
|
|
7369
|
-
const codexRoot = (0,
|
|
7444
|
+
const claudeRoot = (0, import_node_path10.join)(home, ".claude", "skills");
|
|
7445
|
+
const codexRoot = (0, import_node_path10.resolve)(options.codexHomeDir ?? process.env.CODEX_HOME ?? (0, import_node_path10.join)(home, ".codex"), "skills");
|
|
7370
7446
|
targetDir = harnesses[0] === "codex" ? codexRoot : claudeRoot;
|
|
7371
7447
|
for (const harness of harnesses) {
|
|
7372
7448
|
const skillRoot = harness === "claude" ? claudeRoot : codexRoot;
|
|
7373
|
-
planSkillTree(skillRoot, harness === "claude" ? home : (0,
|
|
7449
|
+
planSkillTree(skillRoot, harness === "claude" ? home : (0, import_node_path10.dirname)((0, import_node_path10.dirname)(codexRoot)));
|
|
7374
7450
|
rememberTarget(harness, skillRoot);
|
|
7375
7451
|
}
|
|
7376
7452
|
} else {
|
|
7377
|
-
const sharedRoot = (0,
|
|
7453
|
+
const sharedRoot = (0, import_node_path10.join)(root, ".agents", "skills");
|
|
7378
7454
|
planSkillTree(sharedRoot);
|
|
7379
|
-
const claudeRoot = (0,
|
|
7455
|
+
const claudeRoot = (0, import_node_path10.join)(root, ".claude", "skills");
|
|
7380
7456
|
targetDir = harnesses.includes("claude") ? claudeRoot : sharedRoot;
|
|
7381
7457
|
for (const harness of harnesses) rememberTarget(harness, sharedRoot);
|
|
7382
7458
|
if (harnesses.includes("claude")) {
|
|
7383
7459
|
for (const skill of skillNames(files)) {
|
|
7384
|
-
const canonical = (0, import_node_fs11.readFileSync)((0,
|
|
7385
|
-
plan((0,
|
|
7460
|
+
const canonical = (0, import_node_fs11.readFileSync)((0, import_node_path10.join)(sourceDir, skill, "SKILL.md"), "utf8");
|
|
7461
|
+
plan((0, import_node_path10.join)(claudeRoot, skill, "SKILL.md"), claudeAdapter(skill, canonical));
|
|
7386
7462
|
}
|
|
7387
7463
|
rememberTarget("claude", claudeRoot);
|
|
7388
7464
|
}
|
|
7389
7465
|
if (harnesses.includes("cursor")) {
|
|
7390
|
-
const cursorRule = (0,
|
|
7466
|
+
const cursorRule = (0, import_node_path10.join)(root, ".cursor", "rules", "odla.mdc");
|
|
7391
7467
|
plan(cursorRule, CURSOR_RULE);
|
|
7392
7468
|
rememberTarget("cursor", cursorRule);
|
|
7393
7469
|
}
|
|
7394
7470
|
if (harnesses.includes("agents")) {
|
|
7395
|
-
const agentsFile = (0,
|
|
7471
|
+
const agentsFile = (0, import_node_path10.join)(root, "AGENTS.md");
|
|
7396
7472
|
plan(agentsFile, managedFileContent(agentsFile, PROJECT_INSTRUCTIONS, options.force === true, root), true);
|
|
7397
7473
|
rememberTarget("agents", agentsFile);
|
|
7398
7474
|
}
|
|
7399
7475
|
if (harnesses.includes("copilot")) {
|
|
7400
|
-
const copilotFile = (0,
|
|
7476
|
+
const copilotFile = (0, import_node_path10.join)(root, ".github", "copilot-instructions.md");
|
|
7401
7477
|
plan(copilotFile, managedFileContent(copilotFile, PROJECT_INSTRUCTIONS, options.force === true, root), true);
|
|
7402
7478
|
rememberTarget("copilot", copilotFile);
|
|
7403
7479
|
}
|
|
7404
7480
|
if (harnesses.includes("gemini")) {
|
|
7405
|
-
const geminiFile = (0,
|
|
7481
|
+
const geminiFile = (0, import_node_path10.join)(root, "GEMINI.md");
|
|
7406
7482
|
plan(geminiFile, managedFileContent(geminiFile, PROJECT_INSTRUCTIONS, options.force === true, root), true);
|
|
7407
7483
|
rememberTarget("gemini", geminiFile);
|
|
7408
7484
|
}
|
|
@@ -7438,7 +7514,7 @@ ${conflicts.map((f) => ` - ${f}`).join("\n")}`
|
|
|
7438
7514
|
}
|
|
7439
7515
|
for (const file of plans.values()) {
|
|
7440
7516
|
if (!(0, import_node_fs11.existsSync)(file.target) || (0, import_node_fs11.readFileSync)(file.target, "utf8") !== file.content) {
|
|
7441
|
-
(0, import_node_fs11.mkdirSync)((0,
|
|
7517
|
+
(0, import_node_fs11.mkdirSync)((0, import_node_path10.dirname)(file.target), { recursive: true });
|
|
7442
7518
|
(0, import_node_fs11.writeFileSync)(file.target, file.content);
|
|
7443
7519
|
}
|
|
7444
7520
|
}
|
|
@@ -7458,7 +7534,7 @@ ${conflicts.map((f) => ` - ${f}`).join("\n")}`
|
|
|
7458
7534
|
};
|
|
7459
7535
|
}
|
|
7460
7536
|
function pathsUnder(root, paths) {
|
|
7461
|
-
return [...paths].map((path) => (0,
|
|
7537
|
+
return [...paths].map((path) => (0, import_node_path10.relative)(root, path)).filter((path) => path !== ".." && !path.startsWith(`..${import_node_path10.sep}`) && !(0, import_node_path10.isAbsolute)(path)).sort();
|
|
7462
7538
|
}
|
|
7463
7539
|
function normalizeHarnesses(values, global) {
|
|
7464
7540
|
const requested = values?.length ? values : ["claude"];
|
|
@@ -7503,13 +7579,13 @@ function managedFileContent(path, block, force, boundary) {
|
|
|
7503
7579
|
return `${current.slice(0, startAt)}${block}${current.slice(afterEnd)}`;
|
|
7504
7580
|
}
|
|
7505
7581
|
function symlinkedComponent(boundary, target) {
|
|
7506
|
-
const rel = (0,
|
|
7507
|
-
if (rel === ".." || rel.startsWith(`..${
|
|
7582
|
+
const rel = (0, import_node_path10.relative)(boundary, target);
|
|
7583
|
+
if (rel === ".." || rel.startsWith(`..${import_node_path10.sep}`) || (0, import_node_path10.isAbsolute)(rel)) {
|
|
7508
7584
|
throw new Error(`agent setup target escapes its install root: ${target}`);
|
|
7509
7585
|
}
|
|
7510
7586
|
let current = boundary;
|
|
7511
|
-
for (const part of rel.split(
|
|
7512
|
-
current = (0,
|
|
7587
|
+
for (const part of rel.split(import_node_path10.sep).filter(Boolean)) {
|
|
7588
|
+
current = (0, import_node_path10.join)(current, part);
|
|
7513
7589
|
try {
|
|
7514
7590
|
if ((0, import_node_fs11.lstatSync)(current).isSymbolicLink()) return current;
|
|
7515
7591
|
} catch (error) {
|
|
@@ -7526,9 +7602,9 @@ function listFiles(dir) {
|
|
|
7526
7602
|
const results = [];
|
|
7527
7603
|
const walk = (current) => {
|
|
7528
7604
|
for (const entry of (0, import_node_fs11.readdirSync)(current, { withFileTypes: true })) {
|
|
7529
|
-
const path = (0,
|
|
7605
|
+
const path = (0, import_node_path10.join)(current, entry.name);
|
|
7530
7606
|
if (entry.isDirectory()) walk(path);
|
|
7531
|
-
else results.push((0,
|
|
7607
|
+
else results.push((0, import_node_path10.relative)(dir, path));
|
|
7532
7608
|
}
|
|
7533
7609
|
};
|
|
7534
7610
|
walk(dir);
|
|
@@ -7900,6 +7976,7 @@ async function calendarCommand(parsed, dependencies) {
|
|
|
7900
7976
|
isTerminalHostedSecurityStatus,
|
|
7901
7977
|
listGitHubSecuritySources,
|
|
7902
7978
|
listHostedSecurityJobs,
|
|
7979
|
+
prepareCodeImages,
|
|
7903
7980
|
printCapabilities,
|
|
7904
7981
|
provision,
|
|
7905
7982
|
redactSecrets,
|