@odla-ai/cli 0.26.2 → 0.27.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/dist/bin.cjs +290 -135
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-MBZXWPZP.js → chunk-DS64H4FY.js} +174 -14
- package/dist/chunk-DS64H4FY.js.map +1 -0
- package/dist/index.cjs +290 -135
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -1
- package/dist/chunk-MBZXWPZP.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -314,7 +314,7 @@ var import_node_process2 = __toESM(require("process"), 1);
|
|
|
314
314
|
async function openUrl(url, options = {}) {
|
|
315
315
|
const command = openerFor(options.platform ?? import_node_process2.default.platform);
|
|
316
316
|
const doSpawn = options.spawnImpl ?? import_node_child_process.spawn;
|
|
317
|
-
await new Promise((
|
|
317
|
+
await new Promise((resolve13, reject) => {
|
|
318
318
|
const child = doSpawn(command.cmd, [...command.args, url], {
|
|
319
319
|
stdio: "ignore",
|
|
320
320
|
detached: true
|
|
@@ -322,7 +322,7 @@ async function openUrl(url, options = {}) {
|
|
|
322
322
|
child.once("error", reject);
|
|
323
323
|
child.once("spawn", () => {
|
|
324
324
|
child.unref();
|
|
325
|
-
|
|
325
|
+
resolve13();
|
|
326
326
|
});
|
|
327
327
|
});
|
|
328
328
|
}
|
|
@@ -2243,6 +2243,153 @@ async function appCommand(parsed, dependencies = {}) {
|
|
|
2243
2243
|
else await appRestore(options);
|
|
2244
2244
|
}
|
|
2245
2245
|
|
|
2246
|
+
// src/brand-command.ts
|
|
2247
|
+
var import_promises2 = require("fs/promises");
|
|
2248
|
+
var import_node_path7 = require("path");
|
|
2249
|
+
|
|
2250
|
+
// src/brand-design-unpack.ts
|
|
2251
|
+
var import_node_zlib = require("zlib");
|
|
2252
|
+
var import_brand = require("@odla-ai/brand");
|
|
2253
|
+
var EXTENSIONS = {
|
|
2254
|
+
"image/png": "png",
|
|
2255
|
+
"image/jpeg": "jpg",
|
|
2256
|
+
"image/gif": "gif",
|
|
2257
|
+
"image/webp": "webp",
|
|
2258
|
+
"image/svg+xml": "svg",
|
|
2259
|
+
"image/avif": "avif",
|
|
2260
|
+
"font/woff2": "woff2",
|
|
2261
|
+
"font/woff": "woff",
|
|
2262
|
+
"font/ttf": "ttf",
|
|
2263
|
+
"font/otf": "otf",
|
|
2264
|
+
"text/javascript": "js",
|
|
2265
|
+
"application/javascript": "js",
|
|
2266
|
+
"text/css": "css",
|
|
2267
|
+
"text/html": "html",
|
|
2268
|
+
"application/json": "json"
|
|
2269
|
+
};
|
|
2270
|
+
var encode = (text2) => new TextEncoder().encode(text2);
|
|
2271
|
+
function assetFileName(uuid, mime) {
|
|
2272
|
+
const ext = EXTENSIONS[mime.split(";")[0].trim().toLowerCase()] ?? "bin";
|
|
2273
|
+
return `${uuid.replace(/[^a-zA-Z0-9._-]/g, "_")}.${ext}`;
|
|
2274
|
+
}
|
|
2275
|
+
function decodePayload(data, compressed) {
|
|
2276
|
+
const raw = Buffer.from(data, "base64");
|
|
2277
|
+
return new Uint8Array(compressed ? (0, import_node_zlib.gunzipSync)(raw) : raw);
|
|
2278
|
+
}
|
|
2279
|
+
function rewriteReferences(template, assetPaths, pagePaths) {
|
|
2280
|
+
let out = template;
|
|
2281
|
+
for (const [uuid, path] of pagePaths) {
|
|
2282
|
+
out = out.split(`about:blank#${uuid}`).join(path);
|
|
2283
|
+
}
|
|
2284
|
+
for (const [uuid, path] of assetPaths) {
|
|
2285
|
+
out = out.split(uuid).join(path);
|
|
2286
|
+
}
|
|
2287
|
+
return out;
|
|
2288
|
+
}
|
|
2289
|
+
function tokensCss(digest) {
|
|
2290
|
+
if (Object.keys(digest.tokens.light).length === 0) return null;
|
|
2291
|
+
return (0, import_brand.renderTokensCss)(digest.tokens.light, { dark: digest.tokens.dark });
|
|
2292
|
+
}
|
|
2293
|
+
function unpackDesign(html) {
|
|
2294
|
+
const bundle = (0, import_brand.parseDesignBundle)(html);
|
|
2295
|
+
const manifest = (0, import_brand.readDesignManifest)(html);
|
|
2296
|
+
const digest = (0, import_brand.digestDesignBundle)(bundle);
|
|
2297
|
+
const pageUuids = new Set(bundle.pageOrder);
|
|
2298
|
+
const files = [];
|
|
2299
|
+
const failed = [];
|
|
2300
|
+
const assetPaths = /* @__PURE__ */ new Map();
|
|
2301
|
+
const pagePaths = /* @__PURE__ */ new Map();
|
|
2302
|
+
for (const [uuid, entry] of Object.entries(manifest)) {
|
|
2303
|
+
let bytes;
|
|
2304
|
+
try {
|
|
2305
|
+
bytes = decodePayload(entry.data, entry.compressed);
|
|
2306
|
+
} catch {
|
|
2307
|
+
failed.push(uuid);
|
|
2308
|
+
continue;
|
|
2309
|
+
}
|
|
2310
|
+
if (pageUuids.has(uuid)) {
|
|
2311
|
+
const path2 = `pages/${assetFileName(uuid, "text/html")}`;
|
|
2312
|
+
pagePaths.set(uuid, `./${path2}`);
|
|
2313
|
+
files.push({ path: path2, bytes });
|
|
2314
|
+
continue;
|
|
2315
|
+
}
|
|
2316
|
+
const path = `assets/${assetFileName(uuid, entry.mime)}`;
|
|
2317
|
+
assetPaths.set(uuid, `./${path}`);
|
|
2318
|
+
files.push({ path, bytes });
|
|
2319
|
+
}
|
|
2320
|
+
files.push({
|
|
2321
|
+
path: "index.html",
|
|
2322
|
+
bytes: encode(rewriteReferences(bundle.template, assetPaths, pagePaths))
|
|
2323
|
+
});
|
|
2324
|
+
files.push({ path: "digest.json", bytes: encode(`${JSON.stringify(digest, null, 2)}
|
|
2325
|
+
`) });
|
|
2326
|
+
const css = tokensCss(digest);
|
|
2327
|
+
if (css !== null) files.push({ path: "tokens.css", bytes: encode(css) });
|
|
2328
|
+
if (bundle.thumbnailSvg) files.push({ path: "thumbnail.svg", bytes: encode(bundle.thumbnailSvg) });
|
|
2329
|
+
return { files, digest, failed };
|
|
2330
|
+
}
|
|
2331
|
+
function describeUnpack(result, outDir) {
|
|
2332
|
+
const { digest } = result;
|
|
2333
|
+
const lines = [
|
|
2334
|
+
`Unpacked ${digest.title ? `"${digest.title}"` : "design"} into ${outDir}`,
|
|
2335
|
+
` index.html the design, offline-runnable (${digest.templateBytes} bytes)`,
|
|
2336
|
+
` assets/ ${digest.assetCount} embedded files (${digest.assetBytes} bytes)`,
|
|
2337
|
+
` digest.json ${Object.keys(digest.tokens.light).length} --ui-* tokens, ${digest.props.length} props, ${digest.outline.length} headings`
|
|
2338
|
+
];
|
|
2339
|
+
if (result.files.some((f) => f.path === "tokens.css"))
|
|
2340
|
+
lines.push(" tokens.css the design's tokens as an @odla-ai/ui theme sheet");
|
|
2341
|
+
if (digest.fonts.length > 0) lines.push(`Typefaces: ${digest.fonts.join(", ")}`);
|
|
2342
|
+
if (result.failed.length > 0)
|
|
2343
|
+
lines.push(`WARNING: ${result.failed.length} embedded asset(s) could not be decoded.`);
|
|
2344
|
+
return lines;
|
|
2345
|
+
}
|
|
2346
|
+
|
|
2347
|
+
// src/brand-command.ts
|
|
2348
|
+
var USAGE = "usage: odla-ai brand design unpack <bundle.html|-> [--out <dir>] [--json]";
|
|
2349
|
+
async function readBundle(source, deps) {
|
|
2350
|
+
if (source !== "-") return (0, import_promises2.readFile)((0, import_node_path7.resolve)(source), "utf8");
|
|
2351
|
+
const readStdin = deps.readStdin;
|
|
2352
|
+
if (!readStdin) throw new Error("reading a bundle from stdin is not supported here");
|
|
2353
|
+
return readStdin();
|
|
2354
|
+
}
|
|
2355
|
+
async function writeAll(result, outDir) {
|
|
2356
|
+
for (const file of result.files) {
|
|
2357
|
+
const target = (0, import_node_path7.resolve)(outDir, file.path);
|
|
2358
|
+
await (0, import_promises2.mkdir)((0, import_node_path7.dirname)(target), { recursive: true });
|
|
2359
|
+
await (0, import_promises2.writeFile)(target, file.bytes);
|
|
2360
|
+
}
|
|
2361
|
+
}
|
|
2362
|
+
async function designUnpack(parsed, deps) {
|
|
2363
|
+
assertArgs(parsed, ["out", "json"], 4);
|
|
2364
|
+
const source = parsed.positionals[3];
|
|
2365
|
+
if (!source) throw new Error(USAGE);
|
|
2366
|
+
const outDir = (0, import_node_path7.resolve)(stringOpt(parsed.options.out) ?? "design");
|
|
2367
|
+
const result = unpackDesign(await readBundle(source, deps));
|
|
2368
|
+
await writeAll(result, outDir);
|
|
2369
|
+
const out = deps.stdout ?? console;
|
|
2370
|
+
if (parsed.options.json === true) {
|
|
2371
|
+
out.log(
|
|
2372
|
+
JSON.stringify({
|
|
2373
|
+
outDir,
|
|
2374
|
+
files: result.files.map((f) => f.path),
|
|
2375
|
+
failed: result.failed,
|
|
2376
|
+
digest: result.digest
|
|
2377
|
+
})
|
|
2378
|
+
);
|
|
2379
|
+
return;
|
|
2380
|
+
}
|
|
2381
|
+
for (const line of describeUnpack(result, outDir)) out.log(line);
|
|
2382
|
+
}
|
|
2383
|
+
async function brandCommand(parsed, deps) {
|
|
2384
|
+
const subject = parsed.positionals[1];
|
|
2385
|
+
const action2 = parsed.positionals[2];
|
|
2386
|
+
if (subject === "design" && action2 === "unpack") {
|
|
2387
|
+
await designUnpack(parsed, deps);
|
|
2388
|
+
return;
|
|
2389
|
+
}
|
|
2390
|
+
throw new Error(USAGE);
|
|
2391
|
+
}
|
|
2392
|
+
|
|
2246
2393
|
// src/calendar-errors.ts
|
|
2247
2394
|
var PLATFORM_NOT_READY_CODES = /* @__PURE__ */ new Set([
|
|
2248
2395
|
"calendar_google_oauth_not_configured",
|
|
@@ -2516,8 +2663,8 @@ function credential(value2) {
|
|
|
2516
2663
|
// src/calendar-poll.ts
|
|
2517
2664
|
async function waitForCalendarPoll(milliseconds, signal) {
|
|
2518
2665
|
if (signal?.aborted) throw signal.reason ?? new Error("calendar connection aborted");
|
|
2519
|
-
await new Promise((
|
|
2520
|
-
const timer = setTimeout(
|
|
2666
|
+
await new Promise((resolve13, reject) => {
|
|
2667
|
+
const timer = setTimeout(resolve13, milliseconds);
|
|
2521
2668
|
signal?.addEventListener("abort", () => {
|
|
2522
2669
|
clearTimeout(timer);
|
|
2523
2670
|
reject(signal.reason ?? new Error("calendar connection aborted"));
|
|
@@ -2771,7 +2918,7 @@ function printGroup(out, heading, items) {
|
|
|
2771
2918
|
|
|
2772
2919
|
// src/config-operation-command.ts
|
|
2773
2920
|
var import_apps6 = require("@odla-ai/apps");
|
|
2774
|
-
var
|
|
2921
|
+
var import_node_path8 = require("path");
|
|
2775
2922
|
|
|
2776
2923
|
// src/version.ts
|
|
2777
2924
|
var import_node_fs9 = require("fs");
|
|
@@ -3150,7 +3297,7 @@ async function configOperationWait(options) {
|
|
|
3150
3297
|
assertOperationId(options.operationId);
|
|
3151
3298
|
const cfg = await loadProjectConfig(options.configPath);
|
|
3152
3299
|
const client = await operationClient(cfg, options, "wait");
|
|
3153
|
-
const wait2 = options.pollWait ?? ((ms) => new Promise((
|
|
3300
|
+
const wait2 = options.pollWait ?? ((ms) => new Promise((resolve13) => setTimeout(resolve13, ms)));
|
|
3154
3301
|
const now = () => (options.now?.() ?? /* @__PURE__ */ new Date()).getTime();
|
|
3155
3302
|
const deadline = now() + (options.timeoutSeconds ?? DEFAULT_WAIT_SECONDS) * 1e3;
|
|
3156
3303
|
const interval = (options.intervalSeconds ?? DEFAULT_INTERVAL_SECONDS) * 1e3;
|
|
@@ -3181,7 +3328,7 @@ async function operationClient(cfg, options, purpose) {
|
|
|
3181
3328
|
platform: cfg.platformUrl,
|
|
3182
3329
|
scope: "app:config:write",
|
|
3183
3330
|
token: options.token,
|
|
3184
|
-
tokenFile: (0,
|
|
3331
|
+
tokenFile: (0, import_node_path8.join)(cfg.rootDir, ".odla", "admin-token.local.json"),
|
|
3185
3332
|
rootDir: cfg.rootDir,
|
|
3186
3333
|
email: options.email,
|
|
3187
3334
|
open: options.open,
|
|
@@ -3236,7 +3383,7 @@ function record3(value2) {
|
|
|
3236
3383
|
|
|
3237
3384
|
// src/config-reconcile-command.ts
|
|
3238
3385
|
var import_apps8 = require("@odla-ai/apps");
|
|
3239
|
-
var
|
|
3386
|
+
var import_node_path9 = require("path");
|
|
3240
3387
|
|
|
3241
3388
|
// src/config-reconcile.ts
|
|
3242
3389
|
var import_apps7 = require("@odla-ai/apps");
|
|
@@ -3532,7 +3679,7 @@ async function inspectConfig(options) {
|
|
|
3532
3679
|
platform: cfg.platformUrl,
|
|
3533
3680
|
scope: "app:config:read",
|
|
3534
3681
|
token: options.token,
|
|
3535
|
-
tokenFile: (0,
|
|
3682
|
+
tokenFile: (0, import_node_path9.join)(cfg.rootDir, ".odla", "admin-token.local.json"),
|
|
3536
3683
|
rootDir: cfg.rootDir,
|
|
3537
3684
|
email: options.email,
|
|
3538
3685
|
open: options.open,
|
|
@@ -3665,12 +3812,12 @@ function quoteArg2(value2) {
|
|
|
3665
3812
|
// src/doctor-checks.ts
|
|
3666
3813
|
var import_node_child_process3 = require("child_process");
|
|
3667
3814
|
var import_node_fs12 = require("fs");
|
|
3668
|
-
var
|
|
3815
|
+
var import_node_path11 = require("path");
|
|
3669
3816
|
|
|
3670
3817
|
// src/wrangler.ts
|
|
3671
3818
|
var import_node_child_process2 = require("child_process");
|
|
3672
3819
|
var import_node_fs11 = require("fs");
|
|
3673
|
-
var
|
|
3820
|
+
var import_node_path10 = require("path");
|
|
3674
3821
|
var defaultRunner = (cmd, args, opts) => new Promise((resolvePromise, reject) => {
|
|
3675
3822
|
const child = (0, import_node_child_process2.spawn)(cmd, args, { cwd: opts?.cwd, stdio: ["pipe", "pipe", "pipe"] });
|
|
3676
3823
|
let stdout = "";
|
|
@@ -3684,7 +3831,7 @@ var defaultRunner = (cmd, args, opts) => new Promise((resolvePromise, reject) =>
|
|
|
3684
3831
|
var WRANGLER_CONFIG_FILES = ["wrangler.jsonc", "wrangler.json", "wrangler.toml"];
|
|
3685
3832
|
function findWranglerConfig(rootDir) {
|
|
3686
3833
|
for (const name of WRANGLER_CONFIG_FILES) {
|
|
3687
|
-
const path = (0,
|
|
3834
|
+
const path = (0, import_node_path10.join)(rootDir, name);
|
|
3688
3835
|
if ((0, import_node_fs11.existsSync)(path)) return path;
|
|
3689
3836
|
}
|
|
3690
3837
|
return null;
|
|
@@ -3797,10 +3944,10 @@ function wranglerWarnings(rootDir) {
|
|
|
3797
3944
|
for (const { label, block } of blocks) {
|
|
3798
3945
|
const assets = block.assets;
|
|
3799
3946
|
if (assets?.directory) {
|
|
3800
|
-
const dir = (0,
|
|
3801
|
-
if (dir === (0,
|
|
3947
|
+
const dir = (0, import_node_path11.resolve)(rootDir, assets.directory);
|
|
3948
|
+
if (dir === (0, import_node_path11.resolve)(rootDir)) {
|
|
3802
3949
|
warnings.push(`${label}assets.directory is the project root \u2014 point it at a dedicated build dir (wrangler dev fails with "spawn EBADF")`);
|
|
3803
|
-
} else if ((0, import_node_fs12.existsSync)((0,
|
|
3950
|
+
} else if ((0, import_node_fs12.existsSync)((0, import_node_path11.join)(dir, "node_modules"))) {
|
|
3804
3951
|
warnings.push(`${label}assets.directory contains node_modules \u2014 wrangler dev's watcher will exhaust file descriptors`);
|
|
3805
3952
|
}
|
|
3806
3953
|
}
|
|
@@ -3835,7 +3982,7 @@ function o11yProjectWarnings(rootDir) {
|
|
|
3835
3982
|
warnings.push("cannot verify o11y Worker instrumentation \u2014 add a parseable wrangler.jsonc/json config");
|
|
3836
3983
|
return warnings;
|
|
3837
3984
|
}
|
|
3838
|
-
const main = typeof config.main === "string" ? (0,
|
|
3985
|
+
const main = typeof config.main === "string" ? (0, import_node_path11.resolve)(rootDir, config.main) : null;
|
|
3839
3986
|
if (!main || !(0, import_node_fs12.existsSync)(main)) {
|
|
3840
3987
|
warnings.push("cannot verify o11y Worker instrumentation \u2014 wrangler main is missing or unreadable");
|
|
3841
3988
|
} else {
|
|
@@ -3865,7 +4012,7 @@ function calendarProjectWarnings(rootDir) {
|
|
|
3865
4012
|
}
|
|
3866
4013
|
function readPackageJson(rootDir) {
|
|
3867
4014
|
try {
|
|
3868
|
-
return JSON.parse((0, import_node_fs12.readFileSync)((0,
|
|
4015
|
+
return JSON.parse((0, import_node_fs12.readFileSync)((0, import_node_path11.join)(rootDir, "package.json"), "utf8"));
|
|
3869
4016
|
} catch {
|
|
3870
4017
|
return null;
|
|
3871
4018
|
}
|
|
@@ -4093,12 +4240,12 @@ function harnessOption(value2, flag) {
|
|
|
4093
4240
|
|
|
4094
4241
|
// src/init.ts
|
|
4095
4242
|
var import_node_fs13 = require("fs");
|
|
4096
|
-
var
|
|
4243
|
+
var import_node_path12 = require("path");
|
|
4097
4244
|
var import_apps9 = require("@odla-ai/apps");
|
|
4098
4245
|
function initProject(options) {
|
|
4099
4246
|
const out = options.stdout ?? console;
|
|
4100
|
-
const rootDir = (0,
|
|
4101
|
-
const configPath = (0,
|
|
4247
|
+
const rootDir = (0, import_node_path12.resolve)(options.rootDir ?? process.cwd());
|
|
4248
|
+
const configPath = (0, import_node_path12.resolve)(rootDir, options.configPath ?? "odla.config.mjs");
|
|
4102
4249
|
if ((0, import_node_fs13.existsSync)(configPath) && !options.force) {
|
|
4103
4250
|
throw new Error(`${configPath} already exists. Pass --force to overwrite.`);
|
|
4104
4251
|
}
|
|
@@ -4115,12 +4262,12 @@ function initProject(options) {
|
|
|
4115
4262
|
}
|
|
4116
4263
|
}
|
|
4117
4264
|
const aiProvider = options.aiProvider ?? "anthropic";
|
|
4118
|
-
(0, import_node_fs13.mkdirSync)((0,
|
|
4119
|
-
(0, import_node_fs13.mkdirSync)((0,
|
|
4120
|
-
(0, import_node_fs13.mkdirSync)((0,
|
|
4265
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path12.dirname)(configPath), { recursive: true });
|
|
4266
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path12.resolve)(rootDir, "src/odla"), { recursive: true });
|
|
4267
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path12.resolve)(rootDir, ".odla"), { recursive: true });
|
|
4121
4268
|
(0, import_node_fs13.writeFileSync)(configPath, configTemplate({ appId: options.appId, name: options.name, envs, services, aiProvider }));
|
|
4122
|
-
writeIfMissing((0,
|
|
4123
|
-
writeIfMissing((0,
|
|
4269
|
+
writeIfMissing((0, import_node_path12.resolve)(rootDir, "src/odla/schema.mjs"), schemaTemplate());
|
|
4270
|
+
writeIfMissing((0, import_node_path12.resolve)(rootDir, "src/odla/rules.mjs"), rulesTemplate());
|
|
4124
4271
|
ensureGitignore(rootDir);
|
|
4125
4272
|
out.log(`created ${relativeDisplay(configPath, rootDir)}`);
|
|
4126
4273
|
out.log("created src/odla/schema.mjs and src/odla/rules.mjs");
|
|
@@ -4361,7 +4508,7 @@ async function resolveVaultWrite(options) {
|
|
|
4361
4508
|
// src/skill.ts
|
|
4362
4509
|
var import_node_fs14 = require("fs");
|
|
4363
4510
|
var import_node_os2 = require("os");
|
|
4364
|
-
var
|
|
4511
|
+
var import_node_path13 = require("path");
|
|
4365
4512
|
var import_node_url2 = require("url");
|
|
4366
4513
|
|
|
4367
4514
|
// src/skill-adapters.ts
|
|
@@ -4440,8 +4587,8 @@ function installSkill(options = {}) {
|
|
|
4440
4587
|
const files = listFiles(sourceDir);
|
|
4441
4588
|
if (files.length === 0) throw new Error(`no bundled skills found at ${sourceDir}`);
|
|
4442
4589
|
const harnesses = normalizeHarnesses(options.harnesses, options.global === true);
|
|
4443
|
-
const root = (0,
|
|
4444
|
-
const home = (0,
|
|
4590
|
+
const root = (0, import_node_path13.resolve)(options.dir ?? process.cwd());
|
|
4591
|
+
const home = (0, import_node_path13.resolve)(options.homeDir ?? (0, import_node_os2.homedir)());
|
|
4445
4592
|
const plans = /* @__PURE__ */ new Map();
|
|
4446
4593
|
const targets = /* @__PURE__ */ new Map();
|
|
4447
4594
|
const rememberTarget = (harness, target) => {
|
|
@@ -4455,48 +4602,48 @@ function installSkill(options = {}) {
|
|
|
4455
4602
|
plans.set(target, { target, content: content2, boundary, managedMerge });
|
|
4456
4603
|
};
|
|
4457
4604
|
const planSkillTree = (targetDir2, boundary = root) => {
|
|
4458
|
-
for (const rel of files) plan((0,
|
|
4605
|
+
for (const rel of files) plan((0, import_node_path13.join)(targetDir2, rel), (0, import_node_fs14.readFileSync)((0, import_node_path13.join)(sourceDir, rel), "utf8"), false, boundary);
|
|
4459
4606
|
};
|
|
4460
4607
|
let targetDir;
|
|
4461
4608
|
if (options.global) {
|
|
4462
|
-
const claudeRoot = (0,
|
|
4463
|
-
const codexRoot = (0,
|
|
4609
|
+
const claudeRoot = (0, import_node_path13.join)(home, ".claude", "skills");
|
|
4610
|
+
const codexRoot = (0, import_node_path13.resolve)(options.codexHomeDir ?? process.env.CODEX_HOME ?? (0, import_node_path13.join)(home, ".codex"), "skills");
|
|
4464
4611
|
targetDir = harnesses[0] === "codex" ? codexRoot : claudeRoot;
|
|
4465
4612
|
for (const harness of harnesses) {
|
|
4466
4613
|
const skillRoot = harness === "claude" ? claudeRoot : codexRoot;
|
|
4467
|
-
planSkillTree(skillRoot, harness === "claude" ? home : (0,
|
|
4614
|
+
planSkillTree(skillRoot, harness === "claude" ? home : (0, import_node_path13.dirname)((0, import_node_path13.dirname)(codexRoot)));
|
|
4468
4615
|
rememberTarget(harness, skillRoot);
|
|
4469
4616
|
}
|
|
4470
4617
|
} else {
|
|
4471
|
-
const sharedRoot = (0,
|
|
4618
|
+
const sharedRoot = (0, import_node_path13.join)(root, ".agents", "skills");
|
|
4472
4619
|
planSkillTree(sharedRoot);
|
|
4473
|
-
const claudeRoot = (0,
|
|
4620
|
+
const claudeRoot = (0, import_node_path13.join)(root, ".claude", "skills");
|
|
4474
4621
|
targetDir = harnesses.includes("claude") ? claudeRoot : sharedRoot;
|
|
4475
4622
|
for (const harness of harnesses) rememberTarget(harness, sharedRoot);
|
|
4476
4623
|
if (harnesses.includes("claude")) {
|
|
4477
4624
|
for (const skill of skillNames(files)) {
|
|
4478
|
-
const canonical = (0, import_node_fs14.readFileSync)((0,
|
|
4479
|
-
plan((0,
|
|
4625
|
+
const canonical = (0, import_node_fs14.readFileSync)((0, import_node_path13.join)(sourceDir, skill, "SKILL.md"), "utf8");
|
|
4626
|
+
plan((0, import_node_path13.join)(claudeRoot, skill, "SKILL.md"), claudeAdapter(skill, canonical));
|
|
4480
4627
|
}
|
|
4481
4628
|
rememberTarget("claude", claudeRoot);
|
|
4482
4629
|
}
|
|
4483
4630
|
if (harnesses.includes("cursor")) {
|
|
4484
|
-
const cursorRule = (0,
|
|
4631
|
+
const cursorRule = (0, import_node_path13.join)(root, ".cursor", "rules", "odla.mdc");
|
|
4485
4632
|
plan(cursorRule, CURSOR_RULE);
|
|
4486
4633
|
rememberTarget("cursor", cursorRule);
|
|
4487
4634
|
}
|
|
4488
4635
|
if (harnesses.includes("agents")) {
|
|
4489
|
-
const agentsFile = (0,
|
|
4636
|
+
const agentsFile = (0, import_node_path13.join)(root, "AGENTS.md");
|
|
4490
4637
|
plan(agentsFile, managedFileContent(agentsFile, PROJECT_INSTRUCTIONS, options.force === true, root), true);
|
|
4491
4638
|
rememberTarget("agents", agentsFile);
|
|
4492
4639
|
}
|
|
4493
4640
|
if (harnesses.includes("copilot")) {
|
|
4494
|
-
const copilotFile = (0,
|
|
4641
|
+
const copilotFile = (0, import_node_path13.join)(root, ".github", "copilot-instructions.md");
|
|
4495
4642
|
plan(copilotFile, managedFileContent(copilotFile, PROJECT_INSTRUCTIONS, options.force === true, root), true);
|
|
4496
4643
|
rememberTarget("copilot", copilotFile);
|
|
4497
4644
|
}
|
|
4498
4645
|
if (harnesses.includes("gemini")) {
|
|
4499
|
-
const geminiFile = (0,
|
|
4646
|
+
const geminiFile = (0, import_node_path13.join)(root, "GEMINI.md");
|
|
4500
4647
|
plan(geminiFile, managedFileContent(geminiFile, PROJECT_INSTRUCTIONS, options.force === true, root), true);
|
|
4501
4648
|
rememberTarget("gemini", geminiFile);
|
|
4502
4649
|
}
|
|
@@ -4532,7 +4679,7 @@ ${conflicts.map((f) => ` - ${f}`).join("\n")}`
|
|
|
4532
4679
|
}
|
|
4533
4680
|
for (const file of plans.values()) {
|
|
4534
4681
|
if (!(0, import_node_fs14.existsSync)(file.target) || (0, import_node_fs14.readFileSync)(file.target, "utf8") !== file.content) {
|
|
4535
|
-
(0, import_node_fs14.mkdirSync)((0,
|
|
4682
|
+
(0, import_node_fs14.mkdirSync)((0, import_node_path13.dirname)(file.target), { recursive: true });
|
|
4536
4683
|
(0, import_node_fs14.writeFileSync)(file.target, file.content);
|
|
4537
4684
|
}
|
|
4538
4685
|
}
|
|
@@ -4552,7 +4699,7 @@ ${conflicts.map((f) => ` - ${f}`).join("\n")}`
|
|
|
4552
4699
|
};
|
|
4553
4700
|
}
|
|
4554
4701
|
function pathsUnder(root, paths) {
|
|
4555
|
-
return [...paths].map((path) => (0,
|
|
4702
|
+
return [...paths].map((path) => (0, import_node_path13.relative)(root, path)).filter((path) => path !== ".." && !path.startsWith(`..${import_node_path13.sep}`) && !(0, import_node_path13.isAbsolute)(path)).sort();
|
|
4556
4703
|
}
|
|
4557
4704
|
function normalizeHarnesses(values, global) {
|
|
4558
4705
|
const requested = values?.length ? values : ["claude"];
|
|
@@ -4597,13 +4744,13 @@ function managedFileContent(path, block, force, boundary) {
|
|
|
4597
4744
|
return `${current.slice(0, startAt)}${block}${current.slice(afterEnd)}`;
|
|
4598
4745
|
}
|
|
4599
4746
|
function symlinkedComponent(boundary, target) {
|
|
4600
|
-
const rel = (0,
|
|
4601
|
-
if (rel === ".." || rel.startsWith(`..${
|
|
4747
|
+
const rel = (0, import_node_path13.relative)(boundary, target);
|
|
4748
|
+
if (rel === ".." || rel.startsWith(`..${import_node_path13.sep}`) || (0, import_node_path13.isAbsolute)(rel)) {
|
|
4602
4749
|
throw new Error(`agent setup target escapes its install root: ${target}`);
|
|
4603
4750
|
}
|
|
4604
4751
|
let current = boundary;
|
|
4605
|
-
for (const part of rel.split(
|
|
4606
|
-
current = (0,
|
|
4752
|
+
for (const part of rel.split(import_node_path13.sep).filter(Boolean)) {
|
|
4753
|
+
current = (0, import_node_path13.join)(current, part);
|
|
4607
4754
|
try {
|
|
4608
4755
|
if ((0, import_node_fs14.lstatSync)(current).isSymbolicLink()) return current;
|
|
4609
4756
|
} catch (error) {
|
|
@@ -4620,9 +4767,9 @@ function listFiles(dir) {
|
|
|
4620
4767
|
const results = [];
|
|
4621
4768
|
const walk = (current) => {
|
|
4622
4769
|
for (const entry of (0, import_node_fs14.readdirSync)(current, { withFileTypes: true })) {
|
|
4623
|
-
const path = (0,
|
|
4770
|
+
const path = (0, import_node_path13.join)(current, entry.name);
|
|
4624
4771
|
if (entry.isDirectory()) walk(path);
|
|
4625
|
-
else results.push((0,
|
|
4772
|
+
else results.push((0, import_node_path13.relative)(dir, path));
|
|
4626
4773
|
}
|
|
4627
4774
|
};
|
|
4628
4775
|
walk(dir);
|
|
@@ -4934,7 +5081,7 @@ async function projectCommand(command, parsed, deps) {
|
|
|
4934
5081
|
// src/code-connect.ts
|
|
4935
5082
|
var import_node_fs15 = require("fs");
|
|
4936
5083
|
var import_node_os4 = require("os");
|
|
4937
|
-
var
|
|
5084
|
+
var import_node_path15 = require("path");
|
|
4938
5085
|
|
|
4939
5086
|
// ../harness/dist/chunk-QTUEF2HZ.js
|
|
4940
5087
|
var HARNESS_PROTOCOL_VERSION = 1;
|
|
@@ -5020,15 +5167,15 @@ function encodeAgentInput(message2) {
|
|
|
5020
5167
|
// ../harness/dist/chunk-PHXQH4YM.js
|
|
5021
5168
|
var import_child_process = require("child_process");
|
|
5022
5169
|
var import_fs = require("fs");
|
|
5023
|
-
var
|
|
5170
|
+
var import_promises3 = require("fs/promises");
|
|
5024
5171
|
var import_path = require("path");
|
|
5025
5172
|
var import_process = require("process");
|
|
5026
|
-
var
|
|
5173
|
+
var import_promises4 = require("fs/promises");
|
|
5027
5174
|
var import_os = require("os");
|
|
5028
5175
|
var import_path2 = require("path");
|
|
5029
5176
|
var import_child_process2 = require("child_process");
|
|
5030
5177
|
var import_path3 = require("path");
|
|
5031
|
-
var
|
|
5178
|
+
var import_promises5 = require("fs/promises");
|
|
5032
5179
|
var import_os2 = require("os");
|
|
5033
5180
|
var import_path4 = require("path");
|
|
5034
5181
|
var import_child_process3 = require("child_process");
|
|
@@ -5039,7 +5186,7 @@ function assertPinnedImage(image) {
|
|
|
5039
5186
|
async function commandAvailable(engine) {
|
|
5040
5187
|
for (const directory of (process.env.PATH ?? "").split(import_path.delimiter).filter(Boolean)) {
|
|
5041
5188
|
try {
|
|
5042
|
-
await (0,
|
|
5189
|
+
await (0, import_promises3.access)((0, import_path.join)(directory, engine), import_fs.constants.X_OK);
|
|
5043
5190
|
return true;
|
|
5044
5191
|
} catch {
|
|
5045
5192
|
}
|
|
@@ -5325,7 +5472,7 @@ async function gitBlobs(cwd, entries, maxBytes) {
|
|
|
5325
5472
|
}
|
|
5326
5473
|
async function materializeGitTree(source, commitSha, options = {}) {
|
|
5327
5474
|
if (!/^[0-9a-f]{40}$/.test(commitSha)) throw new TypeError("Git tree requires an exact commit SHA");
|
|
5328
|
-
const sourceDir = await (0,
|
|
5475
|
+
const sourceDir = await (0, import_promises4.realpath)((0, import_path2.resolve)(source));
|
|
5329
5476
|
const maxFiles = options.maxFiles ?? 2e4;
|
|
5330
5477
|
const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;
|
|
5331
5478
|
const inventory = (await gitOutput(sourceDir, ["ls-tree", "-rz", commitSha], 16 * 1024 * 1024)).toString("utf8").split("\0").filter(Boolean);
|
|
@@ -5334,9 +5481,9 @@ async function materializeGitTree(source, commitSha, options = {}) {
|
|
|
5334
5481
|
return match && allowedWorkspacePath(match[3]) ? [{ mode: match[1], hash: match[2], path: match[3] }] : [];
|
|
5335
5482
|
});
|
|
5336
5483
|
if (entries.length > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
|
|
5337
|
-
const root = await (0,
|
|
5484
|
+
const root = await (0, import_promises4.mkdtemp)((0, import_path2.join)(options.tempRoot ?? (0, import_os.tmpdir)(), "odla-git-tree-"));
|
|
5338
5485
|
const targetRoot = (0, import_path2.join)(root, "source");
|
|
5339
|
-
await (0,
|
|
5486
|
+
await (0, import_promises4.mkdir)(targetRoot);
|
|
5340
5487
|
let byteCount = 0;
|
|
5341
5488
|
try {
|
|
5342
5489
|
const blobs = await gitBlobs(sourceDir, entries, maxBytes);
|
|
@@ -5346,18 +5493,18 @@ async function materializeGitTree(source, commitSha, options = {}) {
|
|
|
5346
5493
|
if (byteCount > maxBytes) throw new Error(`workspace exceeds ${maxBytes} bytes`);
|
|
5347
5494
|
const target = (0, import_path2.resolve)(targetRoot, entry.path);
|
|
5348
5495
|
if (!target.startsWith(`${(0, import_path2.resolve)(targetRoot)}${import_path2.sep}`)) throw new TypeError("Git tree path escapes workspace");
|
|
5349
|
-
await (0,
|
|
5350
|
-
await (0,
|
|
5496
|
+
await (0, import_promises4.mkdir)((0, import_path2.resolve)(target, ".."), { recursive: true });
|
|
5497
|
+
await (0, import_promises4.writeFile)(target, content2, { flag: "wx", mode: entry.mode === "100755" ? 493 : 420 });
|
|
5351
5498
|
}
|
|
5352
5499
|
return {
|
|
5353
5500
|
root,
|
|
5354
5501
|
sourceDir: targetRoot,
|
|
5355
5502
|
fileCount: entries.length,
|
|
5356
5503
|
byteCount,
|
|
5357
|
-
cleanup: () => (0,
|
|
5504
|
+
cleanup: () => (0, import_promises4.rm)(root, { recursive: true, force: true })
|
|
5358
5505
|
};
|
|
5359
5506
|
} catch (error) {
|
|
5360
|
-
await (0,
|
|
5507
|
+
await (0, import_promises4.rm)(root, { recursive: true, force: true });
|
|
5361
5508
|
throw error;
|
|
5362
5509
|
}
|
|
5363
5510
|
}
|
|
@@ -5365,7 +5512,7 @@ async function sourceFiles(sourceDir, maxFiles, maxBytes) {
|
|
|
5365
5512
|
const files = [];
|
|
5366
5513
|
let bytes = 0;
|
|
5367
5514
|
const walk = async (dir) => {
|
|
5368
|
-
for (const entry of await (0,
|
|
5515
|
+
for (const entry of await (0, import_promises5.readdir)(dir, { withFileTypes: true })) {
|
|
5369
5516
|
if (entry.isDirectory() && SKIP_WORKSPACE_DIRS.has(entry.name)) continue;
|
|
5370
5517
|
if (!entry.isDirectory() && SECRET_WORKSPACE_FILE.test(entry.name)) continue;
|
|
5371
5518
|
const path = (0, import_path4.join)(dir, entry.name);
|
|
@@ -5375,7 +5522,7 @@ async function sourceFiles(sourceDir, maxFiles, maxBytes) {
|
|
|
5375
5522
|
continue;
|
|
5376
5523
|
}
|
|
5377
5524
|
if (!entry.isFile()) continue;
|
|
5378
|
-
const metadata2 = await (0,
|
|
5525
|
+
const metadata2 = await (0, import_promises5.stat)(path);
|
|
5379
5526
|
bytes += metadata2.size;
|
|
5380
5527
|
if (files.length + 1 > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
|
|
5381
5528
|
if (bytes > maxBytes) throw new Error(`workspace exceeds ${maxBytes} bytes`);
|
|
@@ -5424,7 +5571,7 @@ async function gitSourceFiles(sourceDir, maxFiles, maxBytes) {
|
|
|
5424
5571
|
if (!source.startsWith(`${root}${import_path4.sep}`)) throw new TypeError("git file path escapes workspace");
|
|
5425
5572
|
let metadata2;
|
|
5426
5573
|
try {
|
|
5427
|
-
metadata2 = await (0,
|
|
5574
|
+
metadata2 = await (0, import_promises5.lstat)(source);
|
|
5428
5575
|
} catch (error) {
|
|
5429
5576
|
if (error.code === "ENOENT") continue;
|
|
5430
5577
|
throw error;
|
|
@@ -5439,9 +5586,9 @@ async function gitSourceFiles(sourceDir, maxFiles, maxBytes) {
|
|
|
5439
5586
|
async function copyTree(files, destination) {
|
|
5440
5587
|
for (const file of files) {
|
|
5441
5588
|
const target = (0, import_path4.join)(destination, file.relativePath);
|
|
5442
|
-
await (0,
|
|
5443
|
-
await (0,
|
|
5444
|
-
await (0,
|
|
5589
|
+
await (0, import_promises5.mkdir)((0, import_path4.resolve)(target, ".."), { recursive: true });
|
|
5590
|
+
await (0, import_promises5.copyFile)(file.source, target);
|
|
5591
|
+
await (0, import_promises5.chmod)(target, file.mode);
|
|
5445
5592
|
}
|
|
5446
5593
|
}
|
|
5447
5594
|
async function captureGitDiff(root, maxBytes) {
|
|
@@ -5478,13 +5625,13 @@ async function captureGitDiff(root, maxBytes) {
|
|
|
5478
5625
|
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");
|
|
5479
5626
|
}
|
|
5480
5627
|
async function stageWorkspace(source, options = {}) {
|
|
5481
|
-
const sourceDir = await (0,
|
|
5482
|
-
const sourceStat = await (0,
|
|
5628
|
+
const sourceDir = await (0, import_promises5.realpath)((0, import_path4.resolve)(source));
|
|
5629
|
+
const sourceStat = await (0, import_promises5.stat)(sourceDir);
|
|
5483
5630
|
if (!sourceStat.isDirectory()) throw new TypeError("workspace source must be a directory");
|
|
5484
|
-
const root = await (0,
|
|
5631
|
+
const root = await (0, import_promises5.mkdtemp)((0, import_path4.join)(options.tempRoot ?? (0, import_os2.tmpdir)(), "odla-harness-"));
|
|
5485
5632
|
const baselineDir = (0, import_path4.join)(root, "baseline");
|
|
5486
5633
|
const workspaceDir = (0, import_path4.join)(root, "workspace");
|
|
5487
|
-
await Promise.all([(0,
|
|
5634
|
+
await Promise.all([(0, import_promises5.mkdir)(baselineDir), (0, import_promises5.mkdir)(workspaceDir)]);
|
|
5488
5635
|
try {
|
|
5489
5636
|
const maxFiles = options.maxFiles ?? 2e4;
|
|
5490
5637
|
const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;
|
|
@@ -5497,26 +5644,26 @@ async function stageWorkspace(source, options = {}) {
|
|
|
5497
5644
|
fileCount: files.length,
|
|
5498
5645
|
byteCount: files.reduce((sum, file) => sum + file.bytes, 0),
|
|
5499
5646
|
patch: (maxBytes2) => captureGitDiff(root, maxBytes2),
|
|
5500
|
-
cleanup: () => (0,
|
|
5647
|
+
cleanup: () => (0, import_promises5.rm)(root, { recursive: true, force: true })
|
|
5501
5648
|
};
|
|
5502
5649
|
} catch (error) {
|
|
5503
|
-
await (0,
|
|
5650
|
+
await (0, import_promises5.rm)(root, { recursive: true, force: true });
|
|
5504
5651
|
throw error;
|
|
5505
5652
|
}
|
|
5506
5653
|
}
|
|
5507
5654
|
async function stageWorkspacePair(baselineSource, workspaceSource, options = {}) {
|
|
5508
|
-
const baselineDirSource = await (0,
|
|
5509
|
-
const workspaceDirSource = await (0,
|
|
5655
|
+
const baselineDirSource = await (0, import_promises5.realpath)((0, import_path4.resolve)(baselineSource));
|
|
5656
|
+
const workspaceDirSource = await (0, import_promises5.realpath)((0, import_path4.resolve)(workspaceSource));
|
|
5510
5657
|
const maxFiles = options.maxFiles ?? 2e4;
|
|
5511
5658
|
const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;
|
|
5512
5659
|
const [baselineFiles, workspaceFiles] = await Promise.all([
|
|
5513
5660
|
sourceFiles(baselineDirSource, maxFiles, maxBytes),
|
|
5514
5661
|
sourceFiles(workspaceDirSource, maxFiles, maxBytes)
|
|
5515
5662
|
]);
|
|
5516
|
-
const root = await (0,
|
|
5663
|
+
const root = await (0, import_promises5.mkdtemp)((0, import_path4.join)(options.tempRoot ?? (0, import_os2.tmpdir)(), "odla-harness-"));
|
|
5517
5664
|
const baselineDir = (0, import_path4.join)(root, "baseline");
|
|
5518
5665
|
const workspaceDir = (0, import_path4.join)(root, "workspace");
|
|
5519
|
-
await Promise.all([(0,
|
|
5666
|
+
await Promise.all([(0, import_promises5.mkdir)(baselineDir), (0, import_promises5.mkdir)(workspaceDir)]);
|
|
5520
5667
|
try {
|
|
5521
5668
|
await Promise.all([copyTree(baselineFiles, baselineDir), copyTree(workspaceFiles, workspaceDir)]);
|
|
5522
5669
|
return {
|
|
@@ -5526,17 +5673,17 @@ async function stageWorkspacePair(baselineSource, workspaceSource, options = {})
|
|
|
5526
5673
|
fileCount: workspaceFiles.length,
|
|
5527
5674
|
byteCount: workspaceFiles.reduce((sum, file) => sum + file.bytes, 0),
|
|
5528
5675
|
patch: (maxPatchBytes) => captureGitDiff(root, maxPatchBytes),
|
|
5529
|
-
cleanup: () => (0,
|
|
5676
|
+
cleanup: () => (0, import_promises5.rm)(root, { recursive: true, force: true })
|
|
5530
5677
|
};
|
|
5531
5678
|
} catch (error) {
|
|
5532
|
-
await (0,
|
|
5679
|
+
await (0, import_promises5.rm)(root, { recursive: true, force: true });
|
|
5533
5680
|
throw error;
|
|
5534
5681
|
}
|
|
5535
5682
|
}
|
|
5536
5683
|
|
|
5537
5684
|
// ../harness/dist/chunk-GMVZ4LZH.js
|
|
5538
5685
|
var import_crypto = require("crypto");
|
|
5539
|
-
var
|
|
5686
|
+
var import_promises6 = require("fs/promises");
|
|
5540
5687
|
var import_path5 = require("path");
|
|
5541
5688
|
|
|
5542
5689
|
// ../camel/dist/chunk-7FHPOQVP.js
|
|
@@ -5873,19 +6020,19 @@ function validateSnapshot(snapshot, limits) {
|
|
|
5873
6020
|
|
|
5874
6021
|
// ../harness/dist/chunk-GMVZ4LZH.js
|
|
5875
6022
|
var import_child_process4 = require("child_process");
|
|
5876
|
-
var
|
|
6023
|
+
var import_promises7 = require("fs/promises");
|
|
5877
6024
|
var import_path6 = require("path");
|
|
5878
6025
|
var import_child_process5 = require("child_process");
|
|
5879
6026
|
var import_process2 = require("process");
|
|
5880
6027
|
var import_crypto2 = require("crypto");
|
|
5881
6028
|
var import_crypto3 = require("crypto");
|
|
5882
6029
|
var import_fs2 = require("fs");
|
|
5883
|
-
var import_promises7 = require("fs/promises");
|
|
5884
|
-
var import_path7 = require("path");
|
|
5885
6030
|
var import_promises8 = require("fs/promises");
|
|
6031
|
+
var import_path7 = require("path");
|
|
6032
|
+
var import_promises9 = require("fs/promises");
|
|
5886
6033
|
var import_os3 = require("os");
|
|
5887
6034
|
var import_path8 = require("path");
|
|
5888
|
-
var
|
|
6035
|
+
var import_promises10 = require("fs/promises");
|
|
5889
6036
|
var import_path9 = require("path");
|
|
5890
6037
|
|
|
5891
6038
|
// ../camel/dist/chunk-LAXU2AVK.js
|
|
@@ -6169,7 +6316,7 @@ var import_crypto4 = require("crypto");
|
|
|
6169
6316
|
async function digestStagedWorkspace(root, limits) {
|
|
6170
6317
|
const files = [];
|
|
6171
6318
|
const walk = async (directory) => {
|
|
6172
|
-
const entries = await (0,
|
|
6319
|
+
const entries = await (0, import_promises6.readdir)(directory, { withFileTypes: true });
|
|
6173
6320
|
for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
6174
6321
|
if (entry.isSymbolicLink()) throw new TypeError("workspace digest refuses symbolic links");
|
|
6175
6322
|
const target = (0, import_path5.resolve)(directory, entry.name);
|
|
@@ -6184,7 +6331,7 @@ async function digestStagedWorkspace(root, limits) {
|
|
|
6184
6331
|
const hash = (0, import_crypto.createHash)("sha256");
|
|
6185
6332
|
let bytes = 0;
|
|
6186
6333
|
for (const file of files.sort((left, right) => left.path.localeCompare(right.path))) {
|
|
6187
|
-
const content2 = await (0,
|
|
6334
|
+
const content2 = await (0, import_promises6.readFile)(file.target);
|
|
6188
6335
|
bytes += Buffer.byteLength(file.path) + content2.byteLength;
|
|
6189
6336
|
if (bytes > limits.maxBytes) throw new TypeError("workspace digest exceeds its byte bound");
|
|
6190
6337
|
hash.update(`${Buffer.byteLength(file.path)}:${file.path}:${content2.byteLength}:`);
|
|
@@ -6510,7 +6657,7 @@ async function applyCodePatch(workspaceDir, patch2, paths) {
|
|
|
6510
6657
|
await gitApply(workspaceDir, patch2, false);
|
|
6511
6658
|
for (const path of paths) {
|
|
6512
6659
|
try {
|
|
6513
|
-
const info = await (0,
|
|
6660
|
+
const info = await (0, import_promises7.lstat)(resolveCodePath(workspaceDir, path));
|
|
6514
6661
|
if (info.isSymbolicLink() || !info.isFile() && !info.isDirectory()) {
|
|
6515
6662
|
throw new TypeError("patch created a non-regular workspace entry");
|
|
6516
6663
|
}
|
|
@@ -6801,7 +6948,7 @@ async function inspectArtifacts(workspaceDir, recipe2) {
|
|
|
6801
6948
|
for (const artifact of recipe2.expectedArtifacts ?? []) {
|
|
6802
6949
|
try {
|
|
6803
6950
|
const path = (0, import_path7.join)(workspaceDir, artifact.path);
|
|
6804
|
-
const info = await (0,
|
|
6951
|
+
const info = await (0, import_promises8.lstat)(path);
|
|
6805
6952
|
if (!info.isFile() || info.isSymbolicLink()) {
|
|
6806
6953
|
receipts.push({ artifactId: artifact.id, status: "invalid", bytes: null, digest: null });
|
|
6807
6954
|
} else if (info.size > artifact.maximumBytes) {
|
|
@@ -6982,9 +7129,9 @@ var RESERVED2 = /* @__PURE__ */ new Set([".git", ".odla", ".wrangler", "node_mod
|
|
|
6982
7129
|
var SECRET2 = /^(?:\.env(?:\..+)?|\.dev\.vars|credentials(?:\..+)?\.json|dev-token(?:\..+)?\.json)$/i;
|
|
6983
7130
|
async function materializeCodeRuntimeSource(snapshot, tempRoot = (0, import_os3.tmpdir)()) {
|
|
6984
7131
|
if (!snapshot.files.length || snapshot.files.length > 1e4) throw new TypeError("Code source file count is invalid");
|
|
6985
|
-
const root = await (0,
|
|
7132
|
+
const root = await (0, import_promises9.mkdtemp)((0, import_path8.join)(tempRoot, "odla-code-source-"));
|
|
6986
7133
|
const sourceDir = (0, import_path8.join)(root, "source");
|
|
6987
|
-
await (0,
|
|
7134
|
+
await (0, import_promises9.mkdir)(sourceDir);
|
|
6988
7135
|
const seen = /* @__PURE__ */ new Set();
|
|
6989
7136
|
let bytes = 0;
|
|
6990
7137
|
try {
|
|
@@ -6996,8 +7143,8 @@ async function materializeCodeRuntimeSource(snapshot, tempRoot = (0, import_os3.
|
|
|
6996
7143
|
if (bytes > 16 * 1024 * 1024) throw new TypeError("Code source exceeds its byte bound");
|
|
6997
7144
|
const target = (0, import_path8.resolve)(sourceDir, file.path);
|
|
6998
7145
|
if (!target.startsWith(`${(0, import_path8.resolve)(sourceDir)}${import_path8.sep}`)) throw new TypeError("Code source path escapes its root");
|
|
6999
|
-
await (0,
|
|
7000
|
-
await (0,
|
|
7146
|
+
await (0, import_promises9.mkdir)((0, import_path8.dirname)(target), { recursive: true });
|
|
7147
|
+
await (0, import_promises9.writeFile)(target, file.content, { flag: "wx", mode: 420 });
|
|
7001
7148
|
}
|
|
7002
7149
|
for (const reference of snapshot.references ?? []) {
|
|
7003
7150
|
validateAlias(reference.alias);
|
|
@@ -7011,13 +7158,13 @@ async function materializeCodeRuntimeSource(snapshot, tempRoot = (0, import_os3.
|
|
|
7011
7158
|
if (bytes > 80 * 1024 * 1024) throw new TypeError("Code source set exceeds its byte bound");
|
|
7012
7159
|
const target = (0, import_path8.resolve)(sourceDir, path);
|
|
7013
7160
|
if (!target.startsWith(`${(0, import_path8.resolve)(sourceDir)}${import_path8.sep}`)) throw new TypeError("Code reference path escapes its root");
|
|
7014
|
-
await (0,
|
|
7015
|
-
await (0,
|
|
7161
|
+
await (0, import_promises9.mkdir)((0, import_path8.dirname)(target), { recursive: true });
|
|
7162
|
+
await (0, import_promises9.writeFile)(target, file.content, { flag: "wx", mode: 292 });
|
|
7016
7163
|
}
|
|
7017
7164
|
}
|
|
7018
|
-
return { sourceDir, cleanup: () => (0,
|
|
7165
|
+
return { sourceDir, cleanup: () => (0, import_promises9.rm)(root, { recursive: true, force: true }) };
|
|
7019
7166
|
} catch (cause) {
|
|
7020
|
-
await (0,
|
|
7167
|
+
await (0, import_promises9.rm)(root, { recursive: true, force: true });
|
|
7021
7168
|
throw cause;
|
|
7022
7169
|
}
|
|
7023
7170
|
}
|
|
@@ -7038,8 +7185,8 @@ async function attachCodeRuntimeReferences(workspace, references) {
|
|
|
7038
7185
|
for (const root of [workspace.baselineDir, workspace.workspaceDir]) {
|
|
7039
7186
|
const target = (0, import_path8.resolve)(root, path);
|
|
7040
7187
|
if (!target.startsWith(`${(0, import_path8.resolve)(root)}${import_path8.sep}`)) throw new TypeError("Code reference path escapes its root");
|
|
7041
|
-
await (0,
|
|
7042
|
-
await (0,
|
|
7188
|
+
await (0, import_promises9.mkdir)((0, import_path8.dirname)(target), { recursive: true });
|
|
7189
|
+
await (0, import_promises9.writeFile)(target, file.content, { flag: "wx", mode: 292 });
|
|
7043
7190
|
}
|
|
7044
7191
|
}
|
|
7045
7192
|
}
|
|
@@ -7225,11 +7372,11 @@ async function read(context, request2, options, policy) {
|
|
|
7225
7372
|
const allowed = await policy.read(policyContext(context, request2, options, { paths, path, startLine, endLine }));
|
|
7226
7373
|
if (!allowed) return response(request2, false, "tool denied by CaMeL policy");
|
|
7227
7374
|
const target = resolveCodePath(context.workspaceDir, path);
|
|
7228
|
-
const info = await (0,
|
|
7375
|
+
const info = await (0, import_promises10.stat)(target);
|
|
7229
7376
|
if (!info.isFile() || info.size > Math.max(options.maxReadBytes ?? 128 * 1024, 2 * 1024 * 1024)) {
|
|
7230
7377
|
throw new TypeError("file is not a bounded regular source file");
|
|
7231
7378
|
}
|
|
7232
|
-
const source = await (0,
|
|
7379
|
+
const source = await (0, import_promises10.readFile)(target);
|
|
7233
7380
|
if (source.includes(0)) throw new TypeError("binary files are not readable through this tool");
|
|
7234
7381
|
const lines = source.toString("utf8").split("\n");
|
|
7235
7382
|
const content2 = lines.slice(startLine - 1, endLine).join("\n");
|
|
@@ -7306,7 +7453,7 @@ function policyContext(context, request2, options, extra) {
|
|
|
7306
7453
|
async function registeredFiles(root, limit) {
|
|
7307
7454
|
const paths = [];
|
|
7308
7455
|
const walk = async (directory) => {
|
|
7309
|
-
for (const entry of await (0,
|
|
7456
|
+
for (const entry of await (0, import_promises10.readdir)(directory, { withFileTypes: true })) {
|
|
7310
7457
|
if (entry.isSymbolicLink()) throw new TypeError("workspace contains a symbolic link");
|
|
7311
7458
|
const target = (0, import_path9.resolve)(directory, entry.name);
|
|
7312
7459
|
if (entry.isDirectory()) await walk(target);
|
|
@@ -7905,8 +8052,8 @@ function hostedPollTimeout(value2 = 10 * 6e4) {
|
|
|
7905
8052
|
}
|
|
7906
8053
|
async function waitForHostedPoll(milliseconds, signal) {
|
|
7907
8054
|
if (signal?.aborted) throw signal.reason ?? new DOMException("aborted", "AbortError");
|
|
7908
|
-
await new Promise((
|
|
7909
|
-
const timer = setTimeout(
|
|
8055
|
+
await new Promise((resolve13, reject) => {
|
|
8056
|
+
const timer = setTimeout(resolve13, milliseconds);
|
|
7910
8057
|
signal?.addEventListener("abort", () => {
|
|
7911
8058
|
clearTimeout(timer);
|
|
7912
8059
|
reject(signal.reason ?? new DOMException("aborted", "AbortError"));
|
|
@@ -8091,9 +8238,9 @@ function digestText(value2) {
|
|
|
8091
8238
|
// src/code-images.ts
|
|
8092
8239
|
var import_node_child_process6 = require("child_process");
|
|
8093
8240
|
var import_node_crypto3 = require("crypto");
|
|
8094
|
-
var
|
|
8241
|
+
var import_promises11 = require("fs/promises");
|
|
8095
8242
|
var import_node_os3 = require("os");
|
|
8096
|
-
var
|
|
8243
|
+
var import_node_path14 = require("path");
|
|
8097
8244
|
var import_node_url3 = require("url");
|
|
8098
8245
|
|
|
8099
8246
|
// src/code-runtime-config.ts
|
|
@@ -8173,16 +8320,16 @@ function embeddedPiAssetPath() {
|
|
|
8173
8320
|
return (0, import_node_url3.fileURLToPath)(new URL("./runtime/pi-agent.js", importMetaUrl));
|
|
8174
8321
|
}
|
|
8175
8322
|
async function embeddedPiImageName() {
|
|
8176
|
-
const bundle = await (0,
|
|
8323
|
+
const bundle = await (0, import_promises11.readFile)(embeddedPiAssetPath()).catch(() => {
|
|
8177
8324
|
throw new Error("CLI-embedded Pi runtime is missing; reinstall this exact @odla-ai/cli version");
|
|
8178
8325
|
});
|
|
8179
8326
|
return `odla-ai/pi-agent:embedded-sha256-${(0, import_node_crypto3.createHash)("sha256").update(bundle).digest("hex")}`;
|
|
8180
8327
|
}
|
|
8181
8328
|
async function buildEmbeddedPiImage(engine, image, run) {
|
|
8182
|
-
const context = await (0,
|
|
8329
|
+
const context = await (0, import_promises11.mkdtemp)((0, import_node_path14.join)((0, import_node_os3.tmpdir)(), "odla-code-pi-"));
|
|
8183
8330
|
try {
|
|
8184
|
-
await (0,
|
|
8185
|
-
await (0,
|
|
8331
|
+
await (0, import_promises11.copyFile)(embeddedPiAssetPath(), (0, import_node_path14.join)(context, "pi-agent.js"));
|
|
8332
|
+
await (0, import_promises11.writeFile)((0, import_node_path14.join)(context, "Dockerfile"), [
|
|
8186
8333
|
`FROM ${CODE_NODE_IMAGE}`,
|
|
8187
8334
|
"COPY pi-agent.js /opt/odla/pi-agent.js",
|
|
8188
8335
|
"WORKDIR /workspace",
|
|
@@ -8191,14 +8338,14 @@ async function buildEmbeddedPiImage(engine, image, run) {
|
|
|
8191
8338
|
].join("\n"), { mode: 384 });
|
|
8192
8339
|
await run(engine, ["build", "--tag", image, context], "inherit");
|
|
8193
8340
|
} finally {
|
|
8194
|
-
await (0,
|
|
8341
|
+
await (0, import_promises11.rm)(context, { recursive: true, force: true });
|
|
8195
8342
|
}
|
|
8196
8343
|
}
|
|
8197
8344
|
|
|
8198
8345
|
// src/code-connect.ts
|
|
8199
8346
|
async function codeConnect(options) {
|
|
8200
8347
|
const cwd = options.cwd ?? process.cwd();
|
|
8201
|
-
const configPath = (0,
|
|
8348
|
+
const configPath = (0, import_node_path15.resolve)(cwd, options.configPath);
|
|
8202
8349
|
const cfg = (0, import_node_fs15.existsSync)(configPath) ? await loadProjectConfig(configPath) : null;
|
|
8203
8350
|
const requestedAppId = options.appId?.trim();
|
|
8204
8351
|
if (requestedAppId && !/^[a-z0-9][a-z0-9-]{1,62}$/.test(requestedAppId)) {
|
|
@@ -8567,10 +8714,8 @@ function requireName(parsed) {
|
|
|
8567
8714
|
return name;
|
|
8568
8715
|
}
|
|
8569
8716
|
|
|
8570
|
-
// src/help.ts
|
|
8571
|
-
|
|
8572
|
-
output.log(`odla-ai
|
|
8573
|
-
|
|
8717
|
+
// src/help-usage.ts
|
|
8718
|
+
var USAGE_SECTION = `
|
|
8574
8719
|
Start here:
|
|
8575
8720
|
odla-ai runbook ask "<question>" The current procedure, from odla's own
|
|
8576
8721
|
runbooks. Ask BEFORE searching the web or
|
|
@@ -8604,6 +8749,7 @@ Usage:
|
|
|
8604
8749
|
odla-ai app owners list [--config odla.config.mjs] [--email <odla-account>] [--json]
|
|
8605
8750
|
odla-ai app owners add <email> [--email <odla-account>] [--json]
|
|
8606
8751
|
odla-ai app owners remove <email> [--email <odla-account>] [--json]
|
|
8752
|
+
odla-ai brand design unpack <bundle.html|-> [--out <dir>] [--json]
|
|
8607
8753
|
odla-ai pm goal list [--app <id>] [--status <s>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
|
|
8608
8754
|
odla-ai pm task list [--app <id>] [--column <c>] [--goal <id>] [--assignee <id>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
|
|
8609
8755
|
odla-ai pm decision list [--app <id>] [--status <s>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
|
|
@@ -8683,8 +8829,12 @@ Usage:
|
|
|
8683
8829
|
odla-ai secrets push --env <env> [--config odla.config.mjs] [--dry-run] [--yes]
|
|
8684
8830
|
odla-ai secrets set <name> --env <env> (--from-env <NAME>|--stdin) [--email <odla-account>] [--config odla.config.mjs] [--yes]
|
|
8685
8831
|
odla-ai secrets set-clerk-key --env <env> (--from-env <NAME>|--stdin) [--email <odla-account>] [--config odla.config.mjs] [--yes]
|
|
8686
|
-
odla-ai version
|
|
8832
|
+
odla-ai version`;
|
|
8687
8833
|
|
|
8834
|
+
// src/help.ts
|
|
8835
|
+
function printHelp(output = console) {
|
|
8836
|
+
output.log(`odla-ai
|
|
8837
|
+
${USAGE_SECTION}
|
|
8688
8838
|
Commands:
|
|
8689
8839
|
agent Inspect durable agent wakeups and explicitly requeue a
|
|
8690
8840
|
dead-lettered job; JSON output is stable for remote operators.
|
|
@@ -9133,7 +9283,7 @@ function jsonl(ctx, parsed, value2) {
|
|
|
9133
9283
|
}
|
|
9134
9284
|
async function discussWatch(ctx, topicId, parsed) {
|
|
9135
9285
|
if (ctx.json && parsed.options.jsonl === true) throw new Error("--json and --jsonl cannot be combined");
|
|
9136
|
-
const sleep = ctx.sleep ?? ((ms) => new Promise((
|
|
9286
|
+
const sleep = ctx.sleep ?? ((ms) => new Promise((resolve13) => setTimeout(resolve13, ms)));
|
|
9137
9287
|
const now = ctx.now ?? Date.now;
|
|
9138
9288
|
const intervalMs = (numberOpt2(parsed, "interval", DEFAULT_INTERVAL_MS / 1e3) ?? DEFAULT_INTERVAL_MS / 1e3) * 1e3;
|
|
9139
9289
|
const timeoutSeconds = numberOpt2(parsed, "timeout");
|
|
@@ -10605,6 +10755,7 @@ var COMMAND_SURFACE = {
|
|
|
10605
10755
|
promote: {},
|
|
10606
10756
|
owners: { list: {}, add: {}, remove: {} }
|
|
10607
10757
|
},
|
|
10758
|
+
brand: { design: { unpack: {} } },
|
|
10608
10759
|
calendar: { status: {}, calendars: {}, connect: {}, disconnect: {} },
|
|
10609
10760
|
capabilities: {},
|
|
10610
10761
|
code: { connect: {} },
|
|
@@ -10910,7 +11061,7 @@ async function runbookRemove(ctx, slug) {
|
|
|
10910
11061
|
|
|
10911
11062
|
// src/runbook-import.ts
|
|
10912
11063
|
var import_node_fs18 = require("fs");
|
|
10913
|
-
var
|
|
11064
|
+
var import_node_path16 = require("path");
|
|
10914
11065
|
function parseRunbook(text2, slug) {
|
|
10915
11066
|
let rest = text2;
|
|
10916
11067
|
const meta = {};
|
|
@@ -10939,8 +11090,8 @@ function readRunbookDir(dir) {
|
|
|
10939
11090
|
const files = (0, import_node_fs18.readdirSync)(dir).filter((f) => f.endsWith(".md")).sort();
|
|
10940
11091
|
if (!files.length) throw new Error(`no .md files in ${dir}`);
|
|
10941
11092
|
return files.map((file) => {
|
|
10942
|
-
const slug = (0,
|
|
10943
|
-
const parsed = parseRunbook((0, import_node_fs18.readFileSync)((0,
|
|
11093
|
+
const slug = (0, import_node_path16.basename)(file, ".md");
|
|
11094
|
+
const parsed = parseRunbook((0, import_node_fs18.readFileSync)((0, import_node_path16.join)(dir, file), "utf8"), slug);
|
|
10944
11095
|
return { file, slug, ...parsed, words: parsed.body.split(/\s+/).filter(Boolean).length };
|
|
10945
11096
|
});
|
|
10946
11097
|
}
|
|
@@ -11014,7 +11165,7 @@ async function upsert(ctx, r, visibility) {
|
|
|
11014
11165
|
// src/runbook-impact.ts
|
|
11015
11166
|
var import_node_child_process7 = require("child_process");
|
|
11016
11167
|
var import_node_fs19 = require("fs");
|
|
11017
|
-
var
|
|
11168
|
+
var import_node_path17 = require("path");
|
|
11018
11169
|
|
|
11019
11170
|
// src/runbook-impact-scan.ts
|
|
11020
11171
|
var DECL = /^[+-]\s*export\s+(?:declare\s+)?(?:default\s+)?(?:abstract\s+)?(?:async\s+)?(?:const|let|var|function|class|interface|type|enum)\s+([A-Za-z_$][\w$]*)/;
|
|
@@ -11183,7 +11334,7 @@ ${body.split("\n").map((line) => `+${line}`).join("\n")}
|
|
|
11183
11334
|
}
|
|
11184
11335
|
function manifestLabeller(root) {
|
|
11185
11336
|
return (workspace) => {
|
|
11186
|
-
const manifest = (0,
|
|
11337
|
+
const manifest = (0, import_node_path17.join)(root, workspace, "package.json");
|
|
11187
11338
|
if (!(0, import_node_fs19.existsSync)(manifest)) return void 0;
|
|
11188
11339
|
try {
|
|
11189
11340
|
const name = JSON.parse((0, import_node_fs19.readFileSync)(manifest, "utf8")).name;
|
|
@@ -11253,7 +11404,7 @@ function report3(ctx, impacts) {
|
|
|
11253
11404
|
async function runbookImpact(ctx, options, deps = {}) {
|
|
11254
11405
|
const cwd = deps.cwd ?? process.cwd();
|
|
11255
11406
|
const runGit = deps.runGit ?? gitRunner(cwd);
|
|
11256
|
-
const read3 = deps.readRepoFile ?? ((path) => (0, import_node_fs19.readFileSync)((0,
|
|
11407
|
+
const read3 = deps.readRepoFile ?? ((path) => (0, import_node_fs19.readFileSync)((0, import_node_path17.join)(cwd, path), "utf8"));
|
|
11257
11408
|
const surfaces = changedSurfaces(collectDiff(runGit, options.base, read3), manifestLabeller(cwd));
|
|
11258
11409
|
if (!surfaces.length) {
|
|
11259
11410
|
return ctx.out.log(
|
|
@@ -11388,7 +11539,7 @@ async function runbookComment(ctx, slug, body) {
|
|
|
11388
11539
|
var import_node_child_process8 = require("child_process");
|
|
11389
11540
|
var import_node_fs20 = require("fs");
|
|
11390
11541
|
var import_node_os5 = require("os");
|
|
11391
|
-
var
|
|
11542
|
+
var import_node_path18 = require("path");
|
|
11392
11543
|
var import_node_process12 = __toESM(require("process"), 1);
|
|
11393
11544
|
var EDITOR_ENV = ["ODLA_EDITOR", "VISUAL", "EDITOR"];
|
|
11394
11545
|
function resolveEditor(env = import_node_process12.default.env) {
|
|
@@ -11414,8 +11565,8 @@ function editText(initial, slug, deps = {}) {
|
|
|
11414
11565
|
);
|
|
11415
11566
|
if (!interactive())
|
|
11416
11567
|
throw new Error(`cannot open an editor without a terminal \u2014 pass --file <path> or --body "\u2026" instead`);
|
|
11417
|
-
const dir = (0, import_node_fs20.mkdtempSync)((0,
|
|
11418
|
-
const file = (0,
|
|
11568
|
+
const dir = (0, import_node_fs20.mkdtempSync)((0, import_node_path18.join)((0, import_node_os5.tmpdir)(), "odla-runbook-"));
|
|
11569
|
+
const file = (0, import_node_path18.join)(dir, `${slug}.md`);
|
|
11419
11570
|
try {
|
|
11420
11571
|
(0, import_node_fs20.writeFileSync)(file, initial, { mode: 384 });
|
|
11421
11572
|
const code = defaultRunOrInjected(deps)(editor, file);
|
|
@@ -11757,7 +11908,7 @@ async function runbookCommand(parsed, deps = {}) {
|
|
|
11757
11908
|
}
|
|
11758
11909
|
|
|
11759
11910
|
// src/security-command-context.ts
|
|
11760
|
-
var
|
|
11911
|
+
var import_promises12 = require("readline/promises");
|
|
11761
11912
|
async function hostedSecurityContext(parsed, dependencies) {
|
|
11762
11913
|
const configPath = stringOpt(parsed.options.config) ?? "odla.config.mjs";
|
|
11763
11914
|
const cfg = await loadProjectConfig(configPath);
|
|
@@ -11783,7 +11934,7 @@ async function hostedSecurityContext(parsed, dependencies) {
|
|
|
11783
11934
|
async function interactiveConfirmation(message2, dependencies) {
|
|
11784
11935
|
if (dependencies.confirm) return dependencies.confirm(message2);
|
|
11785
11936
|
if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
|
|
11786
|
-
const prompt = (0,
|
|
11937
|
+
const prompt = (0, import_promises12.createInterface)({ input: process.stdin, output: process.stdout });
|
|
11787
11938
|
try {
|
|
11788
11939
|
const answer = await prompt.question(`${message2} [y/N] `);
|
|
11789
11940
|
return /^y(?:es)?$/i.test(answer.trim());
|
|
@@ -11910,7 +12061,7 @@ function hostedSeverity(value2, flag) {
|
|
|
11910
12061
|
var import_security2 = require("@odla-ai/security");
|
|
11911
12062
|
|
|
11912
12063
|
// src/security.ts
|
|
11913
|
-
var
|
|
12064
|
+
var import_node_path19 = require("path");
|
|
11914
12065
|
var import_security = require("@odla-ai/security");
|
|
11915
12066
|
var import_node3 = require("@odla-ai/security/node");
|
|
11916
12067
|
async function runHostedSecurity(options) {
|
|
@@ -11922,9 +12073,9 @@ async function runHostedSecurity(options) {
|
|
|
11922
12073
|
const appId = selfAudit ? "odla-ai" : cfg.app.id;
|
|
11923
12074
|
const env = selfAudit ? "prod" : selectEnv(options.env, cfg.envs, cfg.configPath, cfg.rootDir);
|
|
11924
12075
|
const platform = options.platform ?? cfg?.platformUrl ?? "https://odla.ai";
|
|
11925
|
-
const target = (0,
|
|
11926
|
-
const output = (0,
|
|
11927
|
-
const outputRelative = (0,
|
|
12076
|
+
const target = (0, import_node_path19.resolve)(options.target ?? cfg?.rootDir ?? ".");
|
|
12077
|
+
const output = (0, import_node_path19.resolve)(options.out ?? (0, import_node_path19.resolve)(target, ".odla/security/hosted"));
|
|
12078
|
+
const outputRelative = (0, import_node_path19.relative)(target, output).split(import_node_path19.sep).join("/");
|
|
11928
12079
|
if (!outputRelative) throw new Error("Hosted security output cannot be the repository root");
|
|
11929
12080
|
const profile = profileFor(options.profile ?? "odla", options.maxHuntTasks ?? 12);
|
|
11930
12081
|
const tokenRequest = {
|
|
@@ -11936,7 +12087,7 @@ async function runHostedSecurity(options) {
|
|
|
11936
12087
|
};
|
|
11937
12088
|
const token = await injectedToken(options, tokenRequest);
|
|
11938
12089
|
const snapshot = await (0, import_node3.snapshotDirectory)(target, {
|
|
11939
|
-
exclude: !outputRelative.startsWith("../") && !(0,
|
|
12090
|
+
exclude: !outputRelative.startsWith("../") && !(0, import_node_path19.isAbsolute)(outputRelative) ? [outputRelative] : []
|
|
11940
12091
|
});
|
|
11941
12092
|
const hosted = await (0, import_security.createPlatformSecurityReasoners)({
|
|
11942
12093
|
platform,
|
|
@@ -11954,7 +12105,7 @@ async function runHostedSecurity(options) {
|
|
|
11954
12105
|
});
|
|
11955
12106
|
const harness = (0, import_security.createSecurityHarness)({
|
|
11956
12107
|
profile,
|
|
11957
|
-
store: new import_node3.FileRunStore((0,
|
|
12108
|
+
store: new import_node3.FileRunStore((0, import_node_path19.resolve)(output, "state")),
|
|
11958
12109
|
discoveryReasoner: hosted.discoveryReasoner,
|
|
11959
12110
|
validationReasoner: hosted.validationReasoner,
|
|
11960
12111
|
policy: {
|
|
@@ -11978,7 +12129,7 @@ async function runHostedSecurity(options) {
|
|
|
11978
12129
|
function selectEnv(requested, declared, configPath, rootDir) {
|
|
11979
12130
|
const env = requested ?? (declared.includes("dev") ? "dev" : declared[0]);
|
|
11980
12131
|
if (!env || !declared.includes(env)) {
|
|
11981
|
-
const shown = (0,
|
|
12132
|
+
const shown = (0, import_node_path19.relative)(rootDir, configPath) || configPath;
|
|
11982
12133
|
throw new Error(`env "${env ?? ""}" is not declared in ${shown}`);
|
|
11983
12134
|
}
|
|
11984
12135
|
return env;
|
|
@@ -12007,7 +12158,7 @@ function printSummary(out, appId, env, run, report4, output) {
|
|
|
12007
12158
|
out.log(` coverage: ${report4.coverageStatus} ${complete}/${report4.coverage.length} blocked=${report4.metrics.blockedCells} shallow=${report4.metrics.shallowCells} unscheduled=${report4.metrics.unscheduledCells} budget_exhausted=${report4.metrics.budgetExhaustedCells}`);
|
|
12008
12159
|
if (report4.callBudget) out.log(` calls: discovery=${formatBudget(report4.callBudget.discovery)} validation=${formatBudget(report4.callBudget.validation)}`);
|
|
12009
12160
|
out.log(` findings: confirmed=${report4.metrics.confirmed} needs_reproduction=${report4.metrics.needsReproduction} candidates=${report4.metrics.candidates}`);
|
|
12010
|
-
out.log(` report: ${(0,
|
|
12161
|
+
out.log(` report: ${(0, import_node_path19.resolve)(output, "REPORT.md")}`);
|
|
12011
12162
|
}
|
|
12012
12163
|
function formatBudget(usage) {
|
|
12013
12164
|
return usage ? `${usage.usedCalls}/${usage.maxCalls} skipped=${usage.skippedCalls}` : "caller-managed";
|
|
@@ -12519,6 +12670,10 @@ async function runCli(argv = process.argv.slice(2), dependencies = {}) {
|
|
|
12519
12670
|
await securityCommand(parsed, runtime);
|
|
12520
12671
|
return;
|
|
12521
12672
|
}
|
|
12673
|
+
if (command === "brand") {
|
|
12674
|
+
await brandCommand(parsed, runtime);
|
|
12675
|
+
return;
|
|
12676
|
+
}
|
|
12522
12677
|
if (command === "pm") {
|
|
12523
12678
|
await pmCommand(parsed, runtime);
|
|
12524
12679
|
return;
|