@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/bin.cjs
CHANGED
|
@@ -246,7 +246,7 @@ var import_node_process2 = __toESM(require("process"), 1);
|
|
|
246
246
|
async function openUrl(url, options = {}) {
|
|
247
247
|
const command = openerFor(options.platform ?? import_node_process2.default.platform);
|
|
248
248
|
const doSpawn = options.spawnImpl ?? import_node_child_process.spawn;
|
|
249
|
-
await new Promise((
|
|
249
|
+
await new Promise((resolve13, reject) => {
|
|
250
250
|
const child = doSpawn(command.cmd, [...command.args, url], {
|
|
251
251
|
stdio: "ignore",
|
|
252
252
|
detached: true
|
|
@@ -254,7 +254,7 @@ async function openUrl(url, options = {}) {
|
|
|
254
254
|
child.once("error", reject);
|
|
255
255
|
child.once("spawn", () => {
|
|
256
256
|
child.unref();
|
|
257
|
-
|
|
257
|
+
resolve13();
|
|
258
258
|
});
|
|
259
259
|
});
|
|
260
260
|
}
|
|
@@ -2175,6 +2175,153 @@ async function appCommand(parsed, dependencies = {}) {
|
|
|
2175
2175
|
else await appRestore(options);
|
|
2176
2176
|
}
|
|
2177
2177
|
|
|
2178
|
+
// src/brand-command.ts
|
|
2179
|
+
var import_promises2 = require("fs/promises");
|
|
2180
|
+
var import_node_path7 = require("path");
|
|
2181
|
+
|
|
2182
|
+
// src/brand-design-unpack.ts
|
|
2183
|
+
var import_node_zlib = require("zlib");
|
|
2184
|
+
var import_brand = require("@odla-ai/brand");
|
|
2185
|
+
var EXTENSIONS = {
|
|
2186
|
+
"image/png": "png",
|
|
2187
|
+
"image/jpeg": "jpg",
|
|
2188
|
+
"image/gif": "gif",
|
|
2189
|
+
"image/webp": "webp",
|
|
2190
|
+
"image/svg+xml": "svg",
|
|
2191
|
+
"image/avif": "avif",
|
|
2192
|
+
"font/woff2": "woff2",
|
|
2193
|
+
"font/woff": "woff",
|
|
2194
|
+
"font/ttf": "ttf",
|
|
2195
|
+
"font/otf": "otf",
|
|
2196
|
+
"text/javascript": "js",
|
|
2197
|
+
"application/javascript": "js",
|
|
2198
|
+
"text/css": "css",
|
|
2199
|
+
"text/html": "html",
|
|
2200
|
+
"application/json": "json"
|
|
2201
|
+
};
|
|
2202
|
+
var encode = (text2) => new TextEncoder().encode(text2);
|
|
2203
|
+
function assetFileName(uuid, mime) {
|
|
2204
|
+
const ext = EXTENSIONS[mime.split(";")[0].trim().toLowerCase()] ?? "bin";
|
|
2205
|
+
return `${uuid.replace(/[^a-zA-Z0-9._-]/g, "_")}.${ext}`;
|
|
2206
|
+
}
|
|
2207
|
+
function decodePayload(data, compressed) {
|
|
2208
|
+
const raw = Buffer.from(data, "base64");
|
|
2209
|
+
return new Uint8Array(compressed ? (0, import_node_zlib.gunzipSync)(raw) : raw);
|
|
2210
|
+
}
|
|
2211
|
+
function rewriteReferences(template, assetPaths, pagePaths) {
|
|
2212
|
+
let out = template;
|
|
2213
|
+
for (const [uuid, path] of pagePaths) {
|
|
2214
|
+
out = out.split(`about:blank#${uuid}`).join(path);
|
|
2215
|
+
}
|
|
2216
|
+
for (const [uuid, path] of assetPaths) {
|
|
2217
|
+
out = out.split(uuid).join(path);
|
|
2218
|
+
}
|
|
2219
|
+
return out;
|
|
2220
|
+
}
|
|
2221
|
+
function tokensCss(digest) {
|
|
2222
|
+
if (Object.keys(digest.tokens.light).length === 0) return null;
|
|
2223
|
+
return (0, import_brand.renderTokensCss)(digest.tokens.light, { dark: digest.tokens.dark });
|
|
2224
|
+
}
|
|
2225
|
+
function unpackDesign(html) {
|
|
2226
|
+
const bundle = (0, import_brand.parseDesignBundle)(html);
|
|
2227
|
+
const manifest = (0, import_brand.readDesignManifest)(html);
|
|
2228
|
+
const digest = (0, import_brand.digestDesignBundle)(bundle);
|
|
2229
|
+
const pageUuids = new Set(bundle.pageOrder);
|
|
2230
|
+
const files = [];
|
|
2231
|
+
const failed = [];
|
|
2232
|
+
const assetPaths = /* @__PURE__ */ new Map();
|
|
2233
|
+
const pagePaths = /* @__PURE__ */ new Map();
|
|
2234
|
+
for (const [uuid, entry] of Object.entries(manifest)) {
|
|
2235
|
+
let bytes;
|
|
2236
|
+
try {
|
|
2237
|
+
bytes = decodePayload(entry.data, entry.compressed);
|
|
2238
|
+
} catch {
|
|
2239
|
+
failed.push(uuid);
|
|
2240
|
+
continue;
|
|
2241
|
+
}
|
|
2242
|
+
if (pageUuids.has(uuid)) {
|
|
2243
|
+
const path2 = `pages/${assetFileName(uuid, "text/html")}`;
|
|
2244
|
+
pagePaths.set(uuid, `./${path2}`);
|
|
2245
|
+
files.push({ path: path2, bytes });
|
|
2246
|
+
continue;
|
|
2247
|
+
}
|
|
2248
|
+
const path = `assets/${assetFileName(uuid, entry.mime)}`;
|
|
2249
|
+
assetPaths.set(uuid, `./${path}`);
|
|
2250
|
+
files.push({ path, bytes });
|
|
2251
|
+
}
|
|
2252
|
+
files.push({
|
|
2253
|
+
path: "index.html",
|
|
2254
|
+
bytes: encode(rewriteReferences(bundle.template, assetPaths, pagePaths))
|
|
2255
|
+
});
|
|
2256
|
+
files.push({ path: "digest.json", bytes: encode(`${JSON.stringify(digest, null, 2)}
|
|
2257
|
+
`) });
|
|
2258
|
+
const css = tokensCss(digest);
|
|
2259
|
+
if (css !== null) files.push({ path: "tokens.css", bytes: encode(css) });
|
|
2260
|
+
if (bundle.thumbnailSvg) files.push({ path: "thumbnail.svg", bytes: encode(bundle.thumbnailSvg) });
|
|
2261
|
+
return { files, digest, failed };
|
|
2262
|
+
}
|
|
2263
|
+
function describeUnpack(result, outDir) {
|
|
2264
|
+
const { digest } = result;
|
|
2265
|
+
const lines = [
|
|
2266
|
+
`Unpacked ${digest.title ? `"${digest.title}"` : "design"} into ${outDir}`,
|
|
2267
|
+
` index.html the design, offline-runnable (${digest.templateBytes} bytes)`,
|
|
2268
|
+
` assets/ ${digest.assetCount} embedded files (${digest.assetBytes} bytes)`,
|
|
2269
|
+
` digest.json ${Object.keys(digest.tokens.light).length} --ui-* tokens, ${digest.props.length} props, ${digest.outline.length} headings`
|
|
2270
|
+
];
|
|
2271
|
+
if (result.files.some((f) => f.path === "tokens.css"))
|
|
2272
|
+
lines.push(" tokens.css the design's tokens as an @odla-ai/ui theme sheet");
|
|
2273
|
+
if (digest.fonts.length > 0) lines.push(`Typefaces: ${digest.fonts.join(", ")}`);
|
|
2274
|
+
if (result.failed.length > 0)
|
|
2275
|
+
lines.push(`WARNING: ${result.failed.length} embedded asset(s) could not be decoded.`);
|
|
2276
|
+
return lines;
|
|
2277
|
+
}
|
|
2278
|
+
|
|
2279
|
+
// src/brand-command.ts
|
|
2280
|
+
var USAGE = "usage: odla-ai brand design unpack <bundle.html|-> [--out <dir>] [--json]";
|
|
2281
|
+
async function readBundle(source, deps) {
|
|
2282
|
+
if (source !== "-") return (0, import_promises2.readFile)((0, import_node_path7.resolve)(source), "utf8");
|
|
2283
|
+
const readStdin = deps.readStdin;
|
|
2284
|
+
if (!readStdin) throw new Error("reading a bundle from stdin is not supported here");
|
|
2285
|
+
return readStdin();
|
|
2286
|
+
}
|
|
2287
|
+
async function writeAll(result, outDir) {
|
|
2288
|
+
for (const file of result.files) {
|
|
2289
|
+
const target = (0, import_node_path7.resolve)(outDir, file.path);
|
|
2290
|
+
await (0, import_promises2.mkdir)((0, import_node_path7.dirname)(target), { recursive: true });
|
|
2291
|
+
await (0, import_promises2.writeFile)(target, file.bytes);
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
async function designUnpack(parsed, deps) {
|
|
2295
|
+
assertArgs(parsed, ["out", "json"], 4);
|
|
2296
|
+
const source = parsed.positionals[3];
|
|
2297
|
+
if (!source) throw new Error(USAGE);
|
|
2298
|
+
const outDir = (0, import_node_path7.resolve)(stringOpt(parsed.options.out) ?? "design");
|
|
2299
|
+
const result = unpackDesign(await readBundle(source, deps));
|
|
2300
|
+
await writeAll(result, outDir);
|
|
2301
|
+
const out = deps.stdout ?? console;
|
|
2302
|
+
if (parsed.options.json === true) {
|
|
2303
|
+
out.log(
|
|
2304
|
+
JSON.stringify({
|
|
2305
|
+
outDir,
|
|
2306
|
+
files: result.files.map((f) => f.path),
|
|
2307
|
+
failed: result.failed,
|
|
2308
|
+
digest: result.digest
|
|
2309
|
+
})
|
|
2310
|
+
);
|
|
2311
|
+
return;
|
|
2312
|
+
}
|
|
2313
|
+
for (const line of describeUnpack(result, outDir)) out.log(line);
|
|
2314
|
+
}
|
|
2315
|
+
async function brandCommand(parsed, deps) {
|
|
2316
|
+
const subject = parsed.positionals[1];
|
|
2317
|
+
const action2 = parsed.positionals[2];
|
|
2318
|
+
if (subject === "design" && action2 === "unpack") {
|
|
2319
|
+
await designUnpack(parsed, deps);
|
|
2320
|
+
return;
|
|
2321
|
+
}
|
|
2322
|
+
throw new Error(USAGE);
|
|
2323
|
+
}
|
|
2324
|
+
|
|
2178
2325
|
// src/calendar-errors.ts
|
|
2179
2326
|
var PLATFORM_NOT_READY_CODES = /* @__PURE__ */ new Set([
|
|
2180
2327
|
"calendar_google_oauth_not_configured",
|
|
@@ -2448,8 +2595,8 @@ function credential(value2) {
|
|
|
2448
2595
|
// src/calendar-poll.ts
|
|
2449
2596
|
async function waitForCalendarPoll(milliseconds, signal) {
|
|
2450
2597
|
if (signal?.aborted) throw signal.reason ?? new Error("calendar connection aborted");
|
|
2451
|
-
await new Promise((
|
|
2452
|
-
const timer = setTimeout(
|
|
2598
|
+
await new Promise((resolve13, reject) => {
|
|
2599
|
+
const timer = setTimeout(resolve13, milliseconds);
|
|
2453
2600
|
signal?.addEventListener("abort", () => {
|
|
2454
2601
|
clearTimeout(timer);
|
|
2455
2602
|
reject(signal.reason ?? new Error("calendar connection aborted"));
|
|
@@ -2703,7 +2850,7 @@ function printGroup(out, heading, items) {
|
|
|
2703
2850
|
|
|
2704
2851
|
// src/config-operation-command.ts
|
|
2705
2852
|
var import_apps6 = require("@odla-ai/apps");
|
|
2706
|
-
var
|
|
2853
|
+
var import_node_path8 = require("path");
|
|
2707
2854
|
|
|
2708
2855
|
// src/version.ts
|
|
2709
2856
|
var import_node_fs9 = require("fs");
|
|
@@ -3082,7 +3229,7 @@ async function configOperationWait(options) {
|
|
|
3082
3229
|
assertOperationId(options.operationId);
|
|
3083
3230
|
const cfg = await loadProjectConfig(options.configPath);
|
|
3084
3231
|
const client = await operationClient(cfg, options, "wait");
|
|
3085
|
-
const wait2 = options.pollWait ?? ((ms) => new Promise((
|
|
3232
|
+
const wait2 = options.pollWait ?? ((ms) => new Promise((resolve13) => setTimeout(resolve13, ms)));
|
|
3086
3233
|
const now = () => (options.now?.() ?? /* @__PURE__ */ new Date()).getTime();
|
|
3087
3234
|
const deadline = now() + (options.timeoutSeconds ?? DEFAULT_WAIT_SECONDS) * 1e3;
|
|
3088
3235
|
const interval = (options.intervalSeconds ?? DEFAULT_INTERVAL_SECONDS) * 1e3;
|
|
@@ -3113,7 +3260,7 @@ async function operationClient(cfg, options, purpose) {
|
|
|
3113
3260
|
platform: cfg.platformUrl,
|
|
3114
3261
|
scope: "app:config:write",
|
|
3115
3262
|
token: options.token,
|
|
3116
|
-
tokenFile: (0,
|
|
3263
|
+
tokenFile: (0, import_node_path8.join)(cfg.rootDir, ".odla", "admin-token.local.json"),
|
|
3117
3264
|
rootDir: cfg.rootDir,
|
|
3118
3265
|
email: options.email,
|
|
3119
3266
|
open: options.open,
|
|
@@ -3168,7 +3315,7 @@ function record3(value2) {
|
|
|
3168
3315
|
|
|
3169
3316
|
// src/config-reconcile-command.ts
|
|
3170
3317
|
var import_apps8 = require("@odla-ai/apps");
|
|
3171
|
-
var
|
|
3318
|
+
var import_node_path9 = require("path");
|
|
3172
3319
|
|
|
3173
3320
|
// src/config-reconcile.ts
|
|
3174
3321
|
var import_apps7 = require("@odla-ai/apps");
|
|
@@ -3464,7 +3611,7 @@ async function inspectConfig(options) {
|
|
|
3464
3611
|
platform: cfg.platformUrl,
|
|
3465
3612
|
scope: "app:config:read",
|
|
3466
3613
|
token: options.token,
|
|
3467
|
-
tokenFile: (0,
|
|
3614
|
+
tokenFile: (0, import_node_path9.join)(cfg.rootDir, ".odla", "admin-token.local.json"),
|
|
3468
3615
|
rootDir: cfg.rootDir,
|
|
3469
3616
|
email: options.email,
|
|
3470
3617
|
open: options.open,
|
|
@@ -3597,12 +3744,12 @@ function quoteArg2(value2) {
|
|
|
3597
3744
|
// src/doctor-checks.ts
|
|
3598
3745
|
var import_node_child_process3 = require("child_process");
|
|
3599
3746
|
var import_node_fs12 = require("fs");
|
|
3600
|
-
var
|
|
3747
|
+
var import_node_path11 = require("path");
|
|
3601
3748
|
|
|
3602
3749
|
// src/wrangler.ts
|
|
3603
3750
|
var import_node_child_process2 = require("child_process");
|
|
3604
3751
|
var import_node_fs11 = require("fs");
|
|
3605
|
-
var
|
|
3752
|
+
var import_node_path10 = require("path");
|
|
3606
3753
|
var defaultRunner = (cmd, args, opts) => new Promise((resolvePromise, reject) => {
|
|
3607
3754
|
const child = (0, import_node_child_process2.spawn)(cmd, args, { cwd: opts?.cwd, stdio: ["pipe", "pipe", "pipe"] });
|
|
3608
3755
|
let stdout = "";
|
|
@@ -3616,7 +3763,7 @@ var defaultRunner = (cmd, args, opts) => new Promise((resolvePromise, reject) =>
|
|
|
3616
3763
|
var WRANGLER_CONFIG_FILES = ["wrangler.jsonc", "wrangler.json", "wrangler.toml"];
|
|
3617
3764
|
function findWranglerConfig(rootDir) {
|
|
3618
3765
|
for (const name of WRANGLER_CONFIG_FILES) {
|
|
3619
|
-
const path = (0,
|
|
3766
|
+
const path = (0, import_node_path10.join)(rootDir, name);
|
|
3620
3767
|
if ((0, import_node_fs11.existsSync)(path)) return path;
|
|
3621
3768
|
}
|
|
3622
3769
|
return null;
|
|
@@ -3729,10 +3876,10 @@ function wranglerWarnings(rootDir) {
|
|
|
3729
3876
|
for (const { label, block } of blocks) {
|
|
3730
3877
|
const assets = block.assets;
|
|
3731
3878
|
if (assets?.directory) {
|
|
3732
|
-
const dir = (0,
|
|
3733
|
-
if (dir === (0,
|
|
3879
|
+
const dir = (0, import_node_path11.resolve)(rootDir, assets.directory);
|
|
3880
|
+
if (dir === (0, import_node_path11.resolve)(rootDir)) {
|
|
3734
3881
|
warnings.push(`${label}assets.directory is the project root \u2014 point it at a dedicated build dir (wrangler dev fails with "spawn EBADF")`);
|
|
3735
|
-
} else if ((0, import_node_fs12.existsSync)((0,
|
|
3882
|
+
} else if ((0, import_node_fs12.existsSync)((0, import_node_path11.join)(dir, "node_modules"))) {
|
|
3736
3883
|
warnings.push(`${label}assets.directory contains node_modules \u2014 wrangler dev's watcher will exhaust file descriptors`);
|
|
3737
3884
|
}
|
|
3738
3885
|
}
|
|
@@ -3767,7 +3914,7 @@ function o11yProjectWarnings(rootDir) {
|
|
|
3767
3914
|
warnings.push("cannot verify o11y Worker instrumentation \u2014 add a parseable wrangler.jsonc/json config");
|
|
3768
3915
|
return warnings;
|
|
3769
3916
|
}
|
|
3770
|
-
const main = typeof config.main === "string" ? (0,
|
|
3917
|
+
const main = typeof config.main === "string" ? (0, import_node_path11.resolve)(rootDir, config.main) : null;
|
|
3771
3918
|
if (!main || !(0, import_node_fs12.existsSync)(main)) {
|
|
3772
3919
|
warnings.push("cannot verify o11y Worker instrumentation \u2014 wrangler main is missing or unreadable");
|
|
3773
3920
|
} else {
|
|
@@ -3797,7 +3944,7 @@ function calendarProjectWarnings(rootDir) {
|
|
|
3797
3944
|
}
|
|
3798
3945
|
function readPackageJson(rootDir) {
|
|
3799
3946
|
try {
|
|
3800
|
-
return JSON.parse((0, import_node_fs12.readFileSync)((0,
|
|
3947
|
+
return JSON.parse((0, import_node_fs12.readFileSync)((0, import_node_path11.join)(rootDir, "package.json"), "utf8"));
|
|
3801
3948
|
} catch {
|
|
3802
3949
|
return null;
|
|
3803
3950
|
}
|
|
@@ -4025,12 +4172,12 @@ function harnessOption(value2, flag) {
|
|
|
4025
4172
|
|
|
4026
4173
|
// src/init.ts
|
|
4027
4174
|
var import_node_fs13 = require("fs");
|
|
4028
|
-
var
|
|
4175
|
+
var import_node_path12 = require("path");
|
|
4029
4176
|
var import_apps9 = require("@odla-ai/apps");
|
|
4030
4177
|
function initProject(options) {
|
|
4031
4178
|
const out = options.stdout ?? console;
|
|
4032
|
-
const rootDir = (0,
|
|
4033
|
-
const configPath = (0,
|
|
4179
|
+
const rootDir = (0, import_node_path12.resolve)(options.rootDir ?? process.cwd());
|
|
4180
|
+
const configPath = (0, import_node_path12.resolve)(rootDir, options.configPath ?? "odla.config.mjs");
|
|
4034
4181
|
if ((0, import_node_fs13.existsSync)(configPath) && !options.force) {
|
|
4035
4182
|
throw new Error(`${configPath} already exists. Pass --force to overwrite.`);
|
|
4036
4183
|
}
|
|
@@ -4047,12 +4194,12 @@ function initProject(options) {
|
|
|
4047
4194
|
}
|
|
4048
4195
|
}
|
|
4049
4196
|
const aiProvider = options.aiProvider ?? "anthropic";
|
|
4050
|
-
(0, import_node_fs13.mkdirSync)((0,
|
|
4051
|
-
(0, import_node_fs13.mkdirSync)((0,
|
|
4052
|
-
(0, import_node_fs13.mkdirSync)((0,
|
|
4197
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path12.dirname)(configPath), { recursive: true });
|
|
4198
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path12.resolve)(rootDir, "src/odla"), { recursive: true });
|
|
4199
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path12.resolve)(rootDir, ".odla"), { recursive: true });
|
|
4053
4200
|
(0, import_node_fs13.writeFileSync)(configPath, configTemplate({ appId: options.appId, name: options.name, envs, services, aiProvider }));
|
|
4054
|
-
writeIfMissing((0,
|
|
4055
|
-
writeIfMissing((0,
|
|
4201
|
+
writeIfMissing((0, import_node_path12.resolve)(rootDir, "src/odla/schema.mjs"), schemaTemplate());
|
|
4202
|
+
writeIfMissing((0, import_node_path12.resolve)(rootDir, "src/odla/rules.mjs"), rulesTemplate());
|
|
4056
4203
|
ensureGitignore(rootDir);
|
|
4057
4204
|
out.log(`created ${relativeDisplay(configPath, rootDir)}`);
|
|
4058
4205
|
out.log("created src/odla/schema.mjs and src/odla/rules.mjs");
|
|
@@ -4293,7 +4440,7 @@ async function resolveVaultWrite(options) {
|
|
|
4293
4440
|
// src/skill.ts
|
|
4294
4441
|
var import_node_fs14 = require("fs");
|
|
4295
4442
|
var import_node_os2 = require("os");
|
|
4296
|
-
var
|
|
4443
|
+
var import_node_path13 = require("path");
|
|
4297
4444
|
var import_node_url2 = require("url");
|
|
4298
4445
|
|
|
4299
4446
|
// src/skill-adapters.ts
|
|
@@ -4372,8 +4519,8 @@ function installSkill(options = {}) {
|
|
|
4372
4519
|
const files = listFiles(sourceDir);
|
|
4373
4520
|
if (files.length === 0) throw new Error(`no bundled skills found at ${sourceDir}`);
|
|
4374
4521
|
const harnesses = normalizeHarnesses(options.harnesses, options.global === true);
|
|
4375
|
-
const root = (0,
|
|
4376
|
-
const home = (0,
|
|
4522
|
+
const root = (0, import_node_path13.resolve)(options.dir ?? process.cwd());
|
|
4523
|
+
const home = (0, import_node_path13.resolve)(options.homeDir ?? (0, import_node_os2.homedir)());
|
|
4377
4524
|
const plans = /* @__PURE__ */ new Map();
|
|
4378
4525
|
const targets = /* @__PURE__ */ new Map();
|
|
4379
4526
|
const rememberTarget = (harness, target) => {
|
|
@@ -4387,48 +4534,48 @@ function installSkill(options = {}) {
|
|
|
4387
4534
|
plans.set(target, { target, content: content2, boundary, managedMerge });
|
|
4388
4535
|
};
|
|
4389
4536
|
const planSkillTree = (targetDir2, boundary = root) => {
|
|
4390
|
-
for (const rel of files) plan((0,
|
|
4537
|
+
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);
|
|
4391
4538
|
};
|
|
4392
4539
|
let targetDir;
|
|
4393
4540
|
if (options.global) {
|
|
4394
|
-
const claudeRoot = (0,
|
|
4395
|
-
const codexRoot = (0,
|
|
4541
|
+
const claudeRoot = (0, import_node_path13.join)(home, ".claude", "skills");
|
|
4542
|
+
const codexRoot = (0, import_node_path13.resolve)(options.codexHomeDir ?? process.env.CODEX_HOME ?? (0, import_node_path13.join)(home, ".codex"), "skills");
|
|
4396
4543
|
targetDir = harnesses[0] === "codex" ? codexRoot : claudeRoot;
|
|
4397
4544
|
for (const harness of harnesses) {
|
|
4398
4545
|
const skillRoot = harness === "claude" ? claudeRoot : codexRoot;
|
|
4399
|
-
planSkillTree(skillRoot, harness === "claude" ? home : (0,
|
|
4546
|
+
planSkillTree(skillRoot, harness === "claude" ? home : (0, import_node_path13.dirname)((0, import_node_path13.dirname)(codexRoot)));
|
|
4400
4547
|
rememberTarget(harness, skillRoot);
|
|
4401
4548
|
}
|
|
4402
4549
|
} else {
|
|
4403
|
-
const sharedRoot = (0,
|
|
4550
|
+
const sharedRoot = (0, import_node_path13.join)(root, ".agents", "skills");
|
|
4404
4551
|
planSkillTree(sharedRoot);
|
|
4405
|
-
const claudeRoot = (0,
|
|
4552
|
+
const claudeRoot = (0, import_node_path13.join)(root, ".claude", "skills");
|
|
4406
4553
|
targetDir = harnesses.includes("claude") ? claudeRoot : sharedRoot;
|
|
4407
4554
|
for (const harness of harnesses) rememberTarget(harness, sharedRoot);
|
|
4408
4555
|
if (harnesses.includes("claude")) {
|
|
4409
4556
|
for (const skill of skillNames(files)) {
|
|
4410
|
-
const canonical = (0, import_node_fs14.readFileSync)((0,
|
|
4411
|
-
plan((0,
|
|
4557
|
+
const canonical = (0, import_node_fs14.readFileSync)((0, import_node_path13.join)(sourceDir, skill, "SKILL.md"), "utf8");
|
|
4558
|
+
plan((0, import_node_path13.join)(claudeRoot, skill, "SKILL.md"), claudeAdapter(skill, canonical));
|
|
4412
4559
|
}
|
|
4413
4560
|
rememberTarget("claude", claudeRoot);
|
|
4414
4561
|
}
|
|
4415
4562
|
if (harnesses.includes("cursor")) {
|
|
4416
|
-
const cursorRule = (0,
|
|
4563
|
+
const cursorRule = (0, import_node_path13.join)(root, ".cursor", "rules", "odla.mdc");
|
|
4417
4564
|
plan(cursorRule, CURSOR_RULE);
|
|
4418
4565
|
rememberTarget("cursor", cursorRule);
|
|
4419
4566
|
}
|
|
4420
4567
|
if (harnesses.includes("agents")) {
|
|
4421
|
-
const agentsFile = (0,
|
|
4568
|
+
const agentsFile = (0, import_node_path13.join)(root, "AGENTS.md");
|
|
4422
4569
|
plan(agentsFile, managedFileContent(agentsFile, PROJECT_INSTRUCTIONS, options.force === true, root), true);
|
|
4423
4570
|
rememberTarget("agents", agentsFile);
|
|
4424
4571
|
}
|
|
4425
4572
|
if (harnesses.includes("copilot")) {
|
|
4426
|
-
const copilotFile = (0,
|
|
4573
|
+
const copilotFile = (0, import_node_path13.join)(root, ".github", "copilot-instructions.md");
|
|
4427
4574
|
plan(copilotFile, managedFileContent(copilotFile, PROJECT_INSTRUCTIONS, options.force === true, root), true);
|
|
4428
4575
|
rememberTarget("copilot", copilotFile);
|
|
4429
4576
|
}
|
|
4430
4577
|
if (harnesses.includes("gemini")) {
|
|
4431
|
-
const geminiFile = (0,
|
|
4578
|
+
const geminiFile = (0, import_node_path13.join)(root, "GEMINI.md");
|
|
4432
4579
|
plan(geminiFile, managedFileContent(geminiFile, PROJECT_INSTRUCTIONS, options.force === true, root), true);
|
|
4433
4580
|
rememberTarget("gemini", geminiFile);
|
|
4434
4581
|
}
|
|
@@ -4464,7 +4611,7 @@ ${conflicts.map((f) => ` - ${f}`).join("\n")}`
|
|
|
4464
4611
|
}
|
|
4465
4612
|
for (const file of plans.values()) {
|
|
4466
4613
|
if (!(0, import_node_fs14.existsSync)(file.target) || (0, import_node_fs14.readFileSync)(file.target, "utf8") !== file.content) {
|
|
4467
|
-
(0, import_node_fs14.mkdirSync)((0,
|
|
4614
|
+
(0, import_node_fs14.mkdirSync)((0, import_node_path13.dirname)(file.target), { recursive: true });
|
|
4468
4615
|
(0, import_node_fs14.writeFileSync)(file.target, file.content);
|
|
4469
4616
|
}
|
|
4470
4617
|
}
|
|
@@ -4484,7 +4631,7 @@ ${conflicts.map((f) => ` - ${f}`).join("\n")}`
|
|
|
4484
4631
|
};
|
|
4485
4632
|
}
|
|
4486
4633
|
function pathsUnder(root, paths) {
|
|
4487
|
-
return [...paths].map((path) => (0,
|
|
4634
|
+
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();
|
|
4488
4635
|
}
|
|
4489
4636
|
function normalizeHarnesses(values, global) {
|
|
4490
4637
|
const requested = values?.length ? values : ["claude"];
|
|
@@ -4529,13 +4676,13 @@ function managedFileContent(path, block, force, boundary) {
|
|
|
4529
4676
|
return `${current.slice(0, startAt)}${block}${current.slice(afterEnd)}`;
|
|
4530
4677
|
}
|
|
4531
4678
|
function symlinkedComponent(boundary, target) {
|
|
4532
|
-
const rel = (0,
|
|
4533
|
-
if (rel === ".." || rel.startsWith(`..${
|
|
4679
|
+
const rel = (0, import_node_path13.relative)(boundary, target);
|
|
4680
|
+
if (rel === ".." || rel.startsWith(`..${import_node_path13.sep}`) || (0, import_node_path13.isAbsolute)(rel)) {
|
|
4534
4681
|
throw new Error(`agent setup target escapes its install root: ${target}`);
|
|
4535
4682
|
}
|
|
4536
4683
|
let current = boundary;
|
|
4537
|
-
for (const part of rel.split(
|
|
4538
|
-
current = (0,
|
|
4684
|
+
for (const part of rel.split(import_node_path13.sep).filter(Boolean)) {
|
|
4685
|
+
current = (0, import_node_path13.join)(current, part);
|
|
4539
4686
|
try {
|
|
4540
4687
|
if ((0, import_node_fs14.lstatSync)(current).isSymbolicLink()) return current;
|
|
4541
4688
|
} catch (error) {
|
|
@@ -4552,9 +4699,9 @@ function listFiles(dir) {
|
|
|
4552
4699
|
const results = [];
|
|
4553
4700
|
const walk = (current) => {
|
|
4554
4701
|
for (const entry of (0, import_node_fs14.readdirSync)(current, { withFileTypes: true })) {
|
|
4555
|
-
const path = (0,
|
|
4702
|
+
const path = (0, import_node_path13.join)(current, entry.name);
|
|
4556
4703
|
if (entry.isDirectory()) walk(path);
|
|
4557
|
-
else results.push((0,
|
|
4704
|
+
else results.push((0, import_node_path13.relative)(dir, path));
|
|
4558
4705
|
}
|
|
4559
4706
|
};
|
|
4560
4707
|
walk(dir);
|
|
@@ -4866,7 +5013,7 @@ async function projectCommand(command, parsed, deps) {
|
|
|
4866
5013
|
// src/code-connect.ts
|
|
4867
5014
|
var import_node_fs15 = require("fs");
|
|
4868
5015
|
var import_node_os4 = require("os");
|
|
4869
|
-
var
|
|
5016
|
+
var import_node_path15 = require("path");
|
|
4870
5017
|
|
|
4871
5018
|
// ../harness/dist/chunk-QTUEF2HZ.js
|
|
4872
5019
|
var HARNESS_PROTOCOL_VERSION = 1;
|
|
@@ -4952,15 +5099,15 @@ function encodeAgentInput(message2) {
|
|
|
4952
5099
|
// ../harness/dist/chunk-PHXQH4YM.js
|
|
4953
5100
|
var import_child_process = require("child_process");
|
|
4954
5101
|
var import_fs = require("fs");
|
|
4955
|
-
var
|
|
5102
|
+
var import_promises3 = require("fs/promises");
|
|
4956
5103
|
var import_path = require("path");
|
|
4957
5104
|
var import_process = require("process");
|
|
4958
|
-
var
|
|
5105
|
+
var import_promises4 = require("fs/promises");
|
|
4959
5106
|
var import_os = require("os");
|
|
4960
5107
|
var import_path2 = require("path");
|
|
4961
5108
|
var import_child_process2 = require("child_process");
|
|
4962
5109
|
var import_path3 = require("path");
|
|
4963
|
-
var
|
|
5110
|
+
var import_promises5 = require("fs/promises");
|
|
4964
5111
|
var import_os2 = require("os");
|
|
4965
5112
|
var import_path4 = require("path");
|
|
4966
5113
|
var import_child_process3 = require("child_process");
|
|
@@ -4971,7 +5118,7 @@ function assertPinnedImage(image) {
|
|
|
4971
5118
|
async function commandAvailable(engine) {
|
|
4972
5119
|
for (const directory of (process.env.PATH ?? "").split(import_path.delimiter).filter(Boolean)) {
|
|
4973
5120
|
try {
|
|
4974
|
-
await (0,
|
|
5121
|
+
await (0, import_promises3.access)((0, import_path.join)(directory, engine), import_fs.constants.X_OK);
|
|
4975
5122
|
return true;
|
|
4976
5123
|
} catch {
|
|
4977
5124
|
}
|
|
@@ -5257,7 +5404,7 @@ async function gitBlobs(cwd, entries, maxBytes) {
|
|
|
5257
5404
|
}
|
|
5258
5405
|
async function materializeGitTree(source, commitSha, options = {}) {
|
|
5259
5406
|
if (!/^[0-9a-f]{40}$/.test(commitSha)) throw new TypeError("Git tree requires an exact commit SHA");
|
|
5260
|
-
const sourceDir = await (0,
|
|
5407
|
+
const sourceDir = await (0, import_promises4.realpath)((0, import_path2.resolve)(source));
|
|
5261
5408
|
const maxFiles = options.maxFiles ?? 2e4;
|
|
5262
5409
|
const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;
|
|
5263
5410
|
const inventory = (await gitOutput(sourceDir, ["ls-tree", "-rz", commitSha], 16 * 1024 * 1024)).toString("utf8").split("\0").filter(Boolean);
|
|
@@ -5266,9 +5413,9 @@ async function materializeGitTree(source, commitSha, options = {}) {
|
|
|
5266
5413
|
return match && allowedWorkspacePath(match[3]) ? [{ mode: match[1], hash: match[2], path: match[3] }] : [];
|
|
5267
5414
|
});
|
|
5268
5415
|
if (entries.length > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
|
|
5269
|
-
const root = await (0,
|
|
5416
|
+
const root = await (0, import_promises4.mkdtemp)((0, import_path2.join)(options.tempRoot ?? (0, import_os.tmpdir)(), "odla-git-tree-"));
|
|
5270
5417
|
const targetRoot = (0, import_path2.join)(root, "source");
|
|
5271
|
-
await (0,
|
|
5418
|
+
await (0, import_promises4.mkdir)(targetRoot);
|
|
5272
5419
|
let byteCount = 0;
|
|
5273
5420
|
try {
|
|
5274
5421
|
const blobs = await gitBlobs(sourceDir, entries, maxBytes);
|
|
@@ -5278,18 +5425,18 @@ async function materializeGitTree(source, commitSha, options = {}) {
|
|
|
5278
5425
|
if (byteCount > maxBytes) throw new Error(`workspace exceeds ${maxBytes} bytes`);
|
|
5279
5426
|
const target = (0, import_path2.resolve)(targetRoot, entry.path);
|
|
5280
5427
|
if (!target.startsWith(`${(0, import_path2.resolve)(targetRoot)}${import_path2.sep}`)) throw new TypeError("Git tree path escapes workspace");
|
|
5281
|
-
await (0,
|
|
5282
|
-
await (0,
|
|
5428
|
+
await (0, import_promises4.mkdir)((0, import_path2.resolve)(target, ".."), { recursive: true });
|
|
5429
|
+
await (0, import_promises4.writeFile)(target, content2, { flag: "wx", mode: entry.mode === "100755" ? 493 : 420 });
|
|
5283
5430
|
}
|
|
5284
5431
|
return {
|
|
5285
5432
|
root,
|
|
5286
5433
|
sourceDir: targetRoot,
|
|
5287
5434
|
fileCount: entries.length,
|
|
5288
5435
|
byteCount,
|
|
5289
|
-
cleanup: () => (0,
|
|
5436
|
+
cleanup: () => (0, import_promises4.rm)(root, { recursive: true, force: true })
|
|
5290
5437
|
};
|
|
5291
5438
|
} catch (error) {
|
|
5292
|
-
await (0,
|
|
5439
|
+
await (0, import_promises4.rm)(root, { recursive: true, force: true });
|
|
5293
5440
|
throw error;
|
|
5294
5441
|
}
|
|
5295
5442
|
}
|
|
@@ -5297,7 +5444,7 @@ async function sourceFiles(sourceDir, maxFiles, maxBytes) {
|
|
|
5297
5444
|
const files = [];
|
|
5298
5445
|
let bytes = 0;
|
|
5299
5446
|
const walk = async (dir) => {
|
|
5300
|
-
for (const entry of await (0,
|
|
5447
|
+
for (const entry of await (0, import_promises5.readdir)(dir, { withFileTypes: true })) {
|
|
5301
5448
|
if (entry.isDirectory() && SKIP_WORKSPACE_DIRS.has(entry.name)) continue;
|
|
5302
5449
|
if (!entry.isDirectory() && SECRET_WORKSPACE_FILE.test(entry.name)) continue;
|
|
5303
5450
|
const path = (0, import_path4.join)(dir, entry.name);
|
|
@@ -5307,7 +5454,7 @@ async function sourceFiles(sourceDir, maxFiles, maxBytes) {
|
|
|
5307
5454
|
continue;
|
|
5308
5455
|
}
|
|
5309
5456
|
if (!entry.isFile()) continue;
|
|
5310
|
-
const metadata2 = await (0,
|
|
5457
|
+
const metadata2 = await (0, import_promises5.stat)(path);
|
|
5311
5458
|
bytes += metadata2.size;
|
|
5312
5459
|
if (files.length + 1 > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
|
|
5313
5460
|
if (bytes > maxBytes) throw new Error(`workspace exceeds ${maxBytes} bytes`);
|
|
@@ -5356,7 +5503,7 @@ async function gitSourceFiles(sourceDir, maxFiles, maxBytes) {
|
|
|
5356
5503
|
if (!source.startsWith(`${root}${import_path4.sep}`)) throw new TypeError("git file path escapes workspace");
|
|
5357
5504
|
let metadata2;
|
|
5358
5505
|
try {
|
|
5359
|
-
metadata2 = await (0,
|
|
5506
|
+
metadata2 = await (0, import_promises5.lstat)(source);
|
|
5360
5507
|
} catch (error) {
|
|
5361
5508
|
if (error.code === "ENOENT") continue;
|
|
5362
5509
|
throw error;
|
|
@@ -5371,9 +5518,9 @@ async function gitSourceFiles(sourceDir, maxFiles, maxBytes) {
|
|
|
5371
5518
|
async function copyTree(files, destination) {
|
|
5372
5519
|
for (const file of files) {
|
|
5373
5520
|
const target = (0, import_path4.join)(destination, file.relativePath);
|
|
5374
|
-
await (0,
|
|
5375
|
-
await (0,
|
|
5376
|
-
await (0,
|
|
5521
|
+
await (0, import_promises5.mkdir)((0, import_path4.resolve)(target, ".."), { recursive: true });
|
|
5522
|
+
await (0, import_promises5.copyFile)(file.source, target);
|
|
5523
|
+
await (0, import_promises5.chmod)(target, file.mode);
|
|
5377
5524
|
}
|
|
5378
5525
|
}
|
|
5379
5526
|
async function captureGitDiff(root, maxBytes) {
|
|
@@ -5410,13 +5557,13 @@ async function captureGitDiff(root, maxBytes) {
|
|
|
5410
5557
|
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");
|
|
5411
5558
|
}
|
|
5412
5559
|
async function stageWorkspace(source, options = {}) {
|
|
5413
|
-
const sourceDir = await (0,
|
|
5414
|
-
const sourceStat = await (0,
|
|
5560
|
+
const sourceDir = await (0, import_promises5.realpath)((0, import_path4.resolve)(source));
|
|
5561
|
+
const sourceStat = await (0, import_promises5.stat)(sourceDir);
|
|
5415
5562
|
if (!sourceStat.isDirectory()) throw new TypeError("workspace source must be a directory");
|
|
5416
|
-
const root = await (0,
|
|
5563
|
+
const root = await (0, import_promises5.mkdtemp)((0, import_path4.join)(options.tempRoot ?? (0, import_os2.tmpdir)(), "odla-harness-"));
|
|
5417
5564
|
const baselineDir = (0, import_path4.join)(root, "baseline");
|
|
5418
5565
|
const workspaceDir = (0, import_path4.join)(root, "workspace");
|
|
5419
|
-
await Promise.all([(0,
|
|
5566
|
+
await Promise.all([(0, import_promises5.mkdir)(baselineDir), (0, import_promises5.mkdir)(workspaceDir)]);
|
|
5420
5567
|
try {
|
|
5421
5568
|
const maxFiles = options.maxFiles ?? 2e4;
|
|
5422
5569
|
const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;
|
|
@@ -5429,26 +5576,26 @@ async function stageWorkspace(source, options = {}) {
|
|
|
5429
5576
|
fileCount: files.length,
|
|
5430
5577
|
byteCount: files.reduce((sum, file) => sum + file.bytes, 0),
|
|
5431
5578
|
patch: (maxBytes2) => captureGitDiff(root, maxBytes2),
|
|
5432
|
-
cleanup: () => (0,
|
|
5579
|
+
cleanup: () => (0, import_promises5.rm)(root, { recursive: true, force: true })
|
|
5433
5580
|
};
|
|
5434
5581
|
} catch (error) {
|
|
5435
|
-
await (0,
|
|
5582
|
+
await (0, import_promises5.rm)(root, { recursive: true, force: true });
|
|
5436
5583
|
throw error;
|
|
5437
5584
|
}
|
|
5438
5585
|
}
|
|
5439
5586
|
async function stageWorkspacePair(baselineSource, workspaceSource, options = {}) {
|
|
5440
|
-
const baselineDirSource = await (0,
|
|
5441
|
-
const workspaceDirSource = await (0,
|
|
5587
|
+
const baselineDirSource = await (0, import_promises5.realpath)((0, import_path4.resolve)(baselineSource));
|
|
5588
|
+
const workspaceDirSource = await (0, import_promises5.realpath)((0, import_path4.resolve)(workspaceSource));
|
|
5442
5589
|
const maxFiles = options.maxFiles ?? 2e4;
|
|
5443
5590
|
const maxBytes = options.maxBytes ?? 512 * 1024 * 1024;
|
|
5444
5591
|
const [baselineFiles, workspaceFiles] = await Promise.all([
|
|
5445
5592
|
sourceFiles(baselineDirSource, maxFiles, maxBytes),
|
|
5446
5593
|
sourceFiles(workspaceDirSource, maxFiles, maxBytes)
|
|
5447
5594
|
]);
|
|
5448
|
-
const root = await (0,
|
|
5595
|
+
const root = await (0, import_promises5.mkdtemp)((0, import_path4.join)(options.tempRoot ?? (0, import_os2.tmpdir)(), "odla-harness-"));
|
|
5449
5596
|
const baselineDir = (0, import_path4.join)(root, "baseline");
|
|
5450
5597
|
const workspaceDir = (0, import_path4.join)(root, "workspace");
|
|
5451
|
-
await Promise.all([(0,
|
|
5598
|
+
await Promise.all([(0, import_promises5.mkdir)(baselineDir), (0, import_promises5.mkdir)(workspaceDir)]);
|
|
5452
5599
|
try {
|
|
5453
5600
|
await Promise.all([copyTree(baselineFiles, baselineDir), copyTree(workspaceFiles, workspaceDir)]);
|
|
5454
5601
|
return {
|
|
@@ -5458,17 +5605,17 @@ async function stageWorkspacePair(baselineSource, workspaceSource, options = {})
|
|
|
5458
5605
|
fileCount: workspaceFiles.length,
|
|
5459
5606
|
byteCount: workspaceFiles.reduce((sum, file) => sum + file.bytes, 0),
|
|
5460
5607
|
patch: (maxPatchBytes) => captureGitDiff(root, maxPatchBytes),
|
|
5461
|
-
cleanup: () => (0,
|
|
5608
|
+
cleanup: () => (0, import_promises5.rm)(root, { recursive: true, force: true })
|
|
5462
5609
|
};
|
|
5463
5610
|
} catch (error) {
|
|
5464
|
-
await (0,
|
|
5611
|
+
await (0, import_promises5.rm)(root, { recursive: true, force: true });
|
|
5465
5612
|
throw error;
|
|
5466
5613
|
}
|
|
5467
5614
|
}
|
|
5468
5615
|
|
|
5469
5616
|
// ../harness/dist/chunk-GMVZ4LZH.js
|
|
5470
5617
|
var import_crypto = require("crypto");
|
|
5471
|
-
var
|
|
5618
|
+
var import_promises6 = require("fs/promises");
|
|
5472
5619
|
var import_path5 = require("path");
|
|
5473
5620
|
|
|
5474
5621
|
// ../camel/dist/chunk-7FHPOQVP.js
|
|
@@ -5805,19 +5952,19 @@ function validateSnapshot(snapshot, limits) {
|
|
|
5805
5952
|
|
|
5806
5953
|
// ../harness/dist/chunk-GMVZ4LZH.js
|
|
5807
5954
|
var import_child_process4 = require("child_process");
|
|
5808
|
-
var
|
|
5955
|
+
var import_promises7 = require("fs/promises");
|
|
5809
5956
|
var import_path6 = require("path");
|
|
5810
5957
|
var import_child_process5 = require("child_process");
|
|
5811
5958
|
var import_process2 = require("process");
|
|
5812
5959
|
var import_crypto2 = require("crypto");
|
|
5813
5960
|
var import_crypto3 = require("crypto");
|
|
5814
5961
|
var import_fs2 = require("fs");
|
|
5815
|
-
var import_promises7 = require("fs/promises");
|
|
5816
|
-
var import_path7 = require("path");
|
|
5817
5962
|
var import_promises8 = require("fs/promises");
|
|
5963
|
+
var import_path7 = require("path");
|
|
5964
|
+
var import_promises9 = require("fs/promises");
|
|
5818
5965
|
var import_os3 = require("os");
|
|
5819
5966
|
var import_path8 = require("path");
|
|
5820
|
-
var
|
|
5967
|
+
var import_promises10 = require("fs/promises");
|
|
5821
5968
|
var import_path9 = require("path");
|
|
5822
5969
|
|
|
5823
5970
|
// ../camel/dist/chunk-LAXU2AVK.js
|
|
@@ -6101,7 +6248,7 @@ var import_crypto4 = require("crypto");
|
|
|
6101
6248
|
async function digestStagedWorkspace(root, limits) {
|
|
6102
6249
|
const files = [];
|
|
6103
6250
|
const walk = async (directory) => {
|
|
6104
|
-
const entries = await (0,
|
|
6251
|
+
const entries = await (0, import_promises6.readdir)(directory, { withFileTypes: true });
|
|
6105
6252
|
for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
6106
6253
|
if (entry.isSymbolicLink()) throw new TypeError("workspace digest refuses symbolic links");
|
|
6107
6254
|
const target = (0, import_path5.resolve)(directory, entry.name);
|
|
@@ -6116,7 +6263,7 @@ async function digestStagedWorkspace(root, limits) {
|
|
|
6116
6263
|
const hash = (0, import_crypto.createHash)("sha256");
|
|
6117
6264
|
let bytes = 0;
|
|
6118
6265
|
for (const file of files.sort((left, right) => left.path.localeCompare(right.path))) {
|
|
6119
|
-
const content2 = await (0,
|
|
6266
|
+
const content2 = await (0, import_promises6.readFile)(file.target);
|
|
6120
6267
|
bytes += Buffer.byteLength(file.path) + content2.byteLength;
|
|
6121
6268
|
if (bytes > limits.maxBytes) throw new TypeError("workspace digest exceeds its byte bound");
|
|
6122
6269
|
hash.update(`${Buffer.byteLength(file.path)}:${file.path}:${content2.byteLength}:`);
|
|
@@ -6442,7 +6589,7 @@ async function applyCodePatch(workspaceDir, patch2, paths) {
|
|
|
6442
6589
|
await gitApply(workspaceDir, patch2, false);
|
|
6443
6590
|
for (const path of paths) {
|
|
6444
6591
|
try {
|
|
6445
|
-
const info = await (0,
|
|
6592
|
+
const info = await (0, import_promises7.lstat)(resolveCodePath(workspaceDir, path));
|
|
6446
6593
|
if (info.isSymbolicLink() || !info.isFile() && !info.isDirectory()) {
|
|
6447
6594
|
throw new TypeError("patch created a non-regular workspace entry");
|
|
6448
6595
|
}
|
|
@@ -6733,7 +6880,7 @@ async function inspectArtifacts(workspaceDir, recipe2) {
|
|
|
6733
6880
|
for (const artifact of recipe2.expectedArtifacts ?? []) {
|
|
6734
6881
|
try {
|
|
6735
6882
|
const path = (0, import_path7.join)(workspaceDir, artifact.path);
|
|
6736
|
-
const info = await (0,
|
|
6883
|
+
const info = await (0, import_promises8.lstat)(path);
|
|
6737
6884
|
if (!info.isFile() || info.isSymbolicLink()) {
|
|
6738
6885
|
receipts.push({ artifactId: artifact.id, status: "invalid", bytes: null, digest: null });
|
|
6739
6886
|
} else if (info.size > artifact.maximumBytes) {
|
|
@@ -6914,9 +7061,9 @@ var RESERVED2 = /* @__PURE__ */ new Set([".git", ".odla", ".wrangler", "node_mod
|
|
|
6914
7061
|
var SECRET2 = /^(?:\.env(?:\..+)?|\.dev\.vars|credentials(?:\..+)?\.json|dev-token(?:\..+)?\.json)$/i;
|
|
6915
7062
|
async function materializeCodeRuntimeSource(snapshot, tempRoot = (0, import_os3.tmpdir)()) {
|
|
6916
7063
|
if (!snapshot.files.length || snapshot.files.length > 1e4) throw new TypeError("Code source file count is invalid");
|
|
6917
|
-
const root = await (0,
|
|
7064
|
+
const root = await (0, import_promises9.mkdtemp)((0, import_path8.join)(tempRoot, "odla-code-source-"));
|
|
6918
7065
|
const sourceDir = (0, import_path8.join)(root, "source");
|
|
6919
|
-
await (0,
|
|
7066
|
+
await (0, import_promises9.mkdir)(sourceDir);
|
|
6920
7067
|
const seen = /* @__PURE__ */ new Set();
|
|
6921
7068
|
let bytes = 0;
|
|
6922
7069
|
try {
|
|
@@ -6928,8 +7075,8 @@ async function materializeCodeRuntimeSource(snapshot, tempRoot = (0, import_os3.
|
|
|
6928
7075
|
if (bytes > 16 * 1024 * 1024) throw new TypeError("Code source exceeds its byte bound");
|
|
6929
7076
|
const target = (0, import_path8.resolve)(sourceDir, file.path);
|
|
6930
7077
|
if (!target.startsWith(`${(0, import_path8.resolve)(sourceDir)}${import_path8.sep}`)) throw new TypeError("Code source path escapes its root");
|
|
6931
|
-
await (0,
|
|
6932
|
-
await (0,
|
|
7078
|
+
await (0, import_promises9.mkdir)((0, import_path8.dirname)(target), { recursive: true });
|
|
7079
|
+
await (0, import_promises9.writeFile)(target, file.content, { flag: "wx", mode: 420 });
|
|
6933
7080
|
}
|
|
6934
7081
|
for (const reference of snapshot.references ?? []) {
|
|
6935
7082
|
validateAlias(reference.alias);
|
|
@@ -6943,13 +7090,13 @@ async function materializeCodeRuntimeSource(snapshot, tempRoot = (0, import_os3.
|
|
|
6943
7090
|
if (bytes > 80 * 1024 * 1024) throw new TypeError("Code source set exceeds its byte bound");
|
|
6944
7091
|
const target = (0, import_path8.resolve)(sourceDir, path);
|
|
6945
7092
|
if (!target.startsWith(`${(0, import_path8.resolve)(sourceDir)}${import_path8.sep}`)) throw new TypeError("Code reference path escapes its root");
|
|
6946
|
-
await (0,
|
|
6947
|
-
await (0,
|
|
7093
|
+
await (0, import_promises9.mkdir)((0, import_path8.dirname)(target), { recursive: true });
|
|
7094
|
+
await (0, import_promises9.writeFile)(target, file.content, { flag: "wx", mode: 292 });
|
|
6948
7095
|
}
|
|
6949
7096
|
}
|
|
6950
|
-
return { sourceDir, cleanup: () => (0,
|
|
7097
|
+
return { sourceDir, cleanup: () => (0, import_promises9.rm)(root, { recursive: true, force: true }) };
|
|
6951
7098
|
} catch (cause) {
|
|
6952
|
-
await (0,
|
|
7099
|
+
await (0, import_promises9.rm)(root, { recursive: true, force: true });
|
|
6953
7100
|
throw cause;
|
|
6954
7101
|
}
|
|
6955
7102
|
}
|
|
@@ -6970,8 +7117,8 @@ async function attachCodeRuntimeReferences(workspace, references) {
|
|
|
6970
7117
|
for (const root of [workspace.baselineDir, workspace.workspaceDir]) {
|
|
6971
7118
|
const target = (0, import_path8.resolve)(root, path);
|
|
6972
7119
|
if (!target.startsWith(`${(0, import_path8.resolve)(root)}${import_path8.sep}`)) throw new TypeError("Code reference path escapes its root");
|
|
6973
|
-
await (0,
|
|
6974
|
-
await (0,
|
|
7120
|
+
await (0, import_promises9.mkdir)((0, import_path8.dirname)(target), { recursive: true });
|
|
7121
|
+
await (0, import_promises9.writeFile)(target, file.content, { flag: "wx", mode: 292 });
|
|
6975
7122
|
}
|
|
6976
7123
|
}
|
|
6977
7124
|
}
|
|
@@ -7157,11 +7304,11 @@ async function read(context, request2, options, policy) {
|
|
|
7157
7304
|
const allowed = await policy.read(policyContext(context, request2, options, { paths, path, startLine, endLine }));
|
|
7158
7305
|
if (!allowed) return response(request2, false, "tool denied by CaMeL policy");
|
|
7159
7306
|
const target = resolveCodePath(context.workspaceDir, path);
|
|
7160
|
-
const info = await (0,
|
|
7307
|
+
const info = await (0, import_promises10.stat)(target);
|
|
7161
7308
|
if (!info.isFile() || info.size > Math.max(options.maxReadBytes ?? 128 * 1024, 2 * 1024 * 1024)) {
|
|
7162
7309
|
throw new TypeError("file is not a bounded regular source file");
|
|
7163
7310
|
}
|
|
7164
|
-
const source = await (0,
|
|
7311
|
+
const source = await (0, import_promises10.readFile)(target);
|
|
7165
7312
|
if (source.includes(0)) throw new TypeError("binary files are not readable through this tool");
|
|
7166
7313
|
const lines = source.toString("utf8").split("\n");
|
|
7167
7314
|
const content2 = lines.slice(startLine - 1, endLine).join("\n");
|
|
@@ -7238,7 +7385,7 @@ function policyContext(context, request2, options, extra) {
|
|
|
7238
7385
|
async function registeredFiles(root, limit) {
|
|
7239
7386
|
const paths = [];
|
|
7240
7387
|
const walk = async (directory) => {
|
|
7241
|
-
for (const entry of await (0,
|
|
7388
|
+
for (const entry of await (0, import_promises10.readdir)(directory, { withFileTypes: true })) {
|
|
7242
7389
|
if (entry.isSymbolicLink()) throw new TypeError("workspace contains a symbolic link");
|
|
7243
7390
|
const target = (0, import_path9.resolve)(directory, entry.name);
|
|
7244
7391
|
if (entry.isDirectory()) await walk(target);
|
|
@@ -7837,8 +7984,8 @@ function hostedPollTimeout(value2 = 10 * 6e4) {
|
|
|
7837
7984
|
}
|
|
7838
7985
|
async function waitForHostedPoll(milliseconds, signal) {
|
|
7839
7986
|
if (signal?.aborted) throw signal.reason ?? new DOMException("aborted", "AbortError");
|
|
7840
|
-
await new Promise((
|
|
7841
|
-
const timer = setTimeout(
|
|
7987
|
+
await new Promise((resolve13, reject) => {
|
|
7988
|
+
const timer = setTimeout(resolve13, milliseconds);
|
|
7842
7989
|
signal?.addEventListener("abort", () => {
|
|
7843
7990
|
clearTimeout(timer);
|
|
7844
7991
|
reject(signal.reason ?? new DOMException("aborted", "AbortError"));
|
|
@@ -8023,9 +8170,9 @@ function digestText(value2) {
|
|
|
8023
8170
|
// src/code-images.ts
|
|
8024
8171
|
var import_node_child_process6 = require("child_process");
|
|
8025
8172
|
var import_node_crypto3 = require("crypto");
|
|
8026
|
-
var
|
|
8173
|
+
var import_promises11 = require("fs/promises");
|
|
8027
8174
|
var import_node_os3 = require("os");
|
|
8028
|
-
var
|
|
8175
|
+
var import_node_path14 = require("path");
|
|
8029
8176
|
var import_node_url3 = require("url");
|
|
8030
8177
|
|
|
8031
8178
|
// src/code-runtime-config.ts
|
|
@@ -8105,16 +8252,16 @@ function embeddedPiAssetPath() {
|
|
|
8105
8252
|
return (0, import_node_url3.fileURLToPath)(new URL("./runtime/pi-agent.js", importMetaUrl));
|
|
8106
8253
|
}
|
|
8107
8254
|
async function embeddedPiImageName() {
|
|
8108
|
-
const bundle = await (0,
|
|
8255
|
+
const bundle = await (0, import_promises11.readFile)(embeddedPiAssetPath()).catch(() => {
|
|
8109
8256
|
throw new Error("CLI-embedded Pi runtime is missing; reinstall this exact @odla-ai/cli version");
|
|
8110
8257
|
});
|
|
8111
8258
|
return `odla-ai/pi-agent:embedded-sha256-${(0, import_node_crypto3.createHash)("sha256").update(bundle).digest("hex")}`;
|
|
8112
8259
|
}
|
|
8113
8260
|
async function buildEmbeddedPiImage(engine, image, run) {
|
|
8114
|
-
const context = await (0,
|
|
8261
|
+
const context = await (0, import_promises11.mkdtemp)((0, import_node_path14.join)((0, import_node_os3.tmpdir)(), "odla-code-pi-"));
|
|
8115
8262
|
try {
|
|
8116
|
-
await (0,
|
|
8117
|
-
await (0,
|
|
8263
|
+
await (0, import_promises11.copyFile)(embeddedPiAssetPath(), (0, import_node_path14.join)(context, "pi-agent.js"));
|
|
8264
|
+
await (0, import_promises11.writeFile)((0, import_node_path14.join)(context, "Dockerfile"), [
|
|
8118
8265
|
`FROM ${CODE_NODE_IMAGE}`,
|
|
8119
8266
|
"COPY pi-agent.js /opt/odla/pi-agent.js",
|
|
8120
8267
|
"WORKDIR /workspace",
|
|
@@ -8123,14 +8270,14 @@ async function buildEmbeddedPiImage(engine, image, run) {
|
|
|
8123
8270
|
].join("\n"), { mode: 384 });
|
|
8124
8271
|
await run(engine, ["build", "--tag", image, context], "inherit");
|
|
8125
8272
|
} finally {
|
|
8126
|
-
await (0,
|
|
8273
|
+
await (0, import_promises11.rm)(context, { recursive: true, force: true });
|
|
8127
8274
|
}
|
|
8128
8275
|
}
|
|
8129
8276
|
|
|
8130
8277
|
// src/code-connect.ts
|
|
8131
8278
|
async function codeConnect(options) {
|
|
8132
8279
|
const cwd = options.cwd ?? process.cwd();
|
|
8133
|
-
const configPath = (0,
|
|
8280
|
+
const configPath = (0, import_node_path15.resolve)(cwd, options.configPath);
|
|
8134
8281
|
const cfg = (0, import_node_fs15.existsSync)(configPath) ? await loadProjectConfig(configPath) : null;
|
|
8135
8282
|
const requestedAppId = options.appId?.trim();
|
|
8136
8283
|
if (requestedAppId && !/^[a-z0-9][a-z0-9-]{1,62}$/.test(requestedAppId)) {
|
|
@@ -8499,10 +8646,8 @@ function requireName(parsed) {
|
|
|
8499
8646
|
return name;
|
|
8500
8647
|
}
|
|
8501
8648
|
|
|
8502
|
-
// src/help.ts
|
|
8503
|
-
|
|
8504
|
-
output.log(`odla-ai
|
|
8505
|
-
|
|
8649
|
+
// src/help-usage.ts
|
|
8650
|
+
var USAGE_SECTION = `
|
|
8506
8651
|
Start here:
|
|
8507
8652
|
odla-ai runbook ask "<question>" The current procedure, from odla's own
|
|
8508
8653
|
runbooks. Ask BEFORE searching the web or
|
|
@@ -8536,6 +8681,7 @@ Usage:
|
|
|
8536
8681
|
odla-ai app owners list [--config odla.config.mjs] [--email <odla-account>] [--json]
|
|
8537
8682
|
odla-ai app owners add <email> [--email <odla-account>] [--json]
|
|
8538
8683
|
odla-ai app owners remove <email> [--email <odla-account>] [--json]
|
|
8684
|
+
odla-ai brand design unpack <bundle.html|-> [--out <dir>] [--json]
|
|
8539
8685
|
odla-ai pm goal list [--app <id>] [--status <s>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
|
|
8540
8686
|
odla-ai pm task list [--app <id>] [--column <c>] [--goal <id>] [--assignee <id>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
|
|
8541
8687
|
odla-ai pm decision list [--app <id>] [--status <s>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
|
|
@@ -8615,8 +8761,12 @@ Usage:
|
|
|
8615
8761
|
odla-ai secrets push --env <env> [--config odla.config.mjs] [--dry-run] [--yes]
|
|
8616
8762
|
odla-ai secrets set <name> --env <env> (--from-env <NAME>|--stdin) [--email <odla-account>] [--config odla.config.mjs] [--yes]
|
|
8617
8763
|
odla-ai secrets set-clerk-key --env <env> (--from-env <NAME>|--stdin) [--email <odla-account>] [--config odla.config.mjs] [--yes]
|
|
8618
|
-
odla-ai version
|
|
8764
|
+
odla-ai version`;
|
|
8619
8765
|
|
|
8766
|
+
// src/help.ts
|
|
8767
|
+
function printHelp(output = console) {
|
|
8768
|
+
output.log(`odla-ai
|
|
8769
|
+
${USAGE_SECTION}
|
|
8620
8770
|
Commands:
|
|
8621
8771
|
agent Inspect durable agent wakeups and explicitly requeue a
|
|
8622
8772
|
dead-lettered job; JSON output is stable for remote operators.
|
|
@@ -9065,7 +9215,7 @@ function jsonl(ctx, parsed, value2) {
|
|
|
9065
9215
|
}
|
|
9066
9216
|
async function discussWatch(ctx, topicId, parsed) {
|
|
9067
9217
|
if (ctx.json && parsed.options.jsonl === true) throw new Error("--json and --jsonl cannot be combined");
|
|
9068
|
-
const sleep = ctx.sleep ?? ((ms) => new Promise((
|
|
9218
|
+
const sleep = ctx.sleep ?? ((ms) => new Promise((resolve13) => setTimeout(resolve13, ms)));
|
|
9069
9219
|
const now = ctx.now ?? Date.now;
|
|
9070
9220
|
const intervalMs = (numberOpt2(parsed, "interval", DEFAULT_INTERVAL_MS / 1e3) ?? DEFAULT_INTERVAL_MS / 1e3) * 1e3;
|
|
9071
9221
|
const timeoutSeconds = numberOpt2(parsed, "timeout");
|
|
@@ -10537,6 +10687,7 @@ var COMMAND_SURFACE = {
|
|
|
10537
10687
|
promote: {},
|
|
10538
10688
|
owners: { list: {}, add: {}, remove: {} }
|
|
10539
10689
|
},
|
|
10690
|
+
brand: { design: { unpack: {} } },
|
|
10540
10691
|
calendar: { status: {}, calendars: {}, connect: {}, disconnect: {} },
|
|
10541
10692
|
capabilities: {},
|
|
10542
10693
|
code: { connect: {} },
|
|
@@ -10833,7 +10984,7 @@ async function runbookRemove(ctx, slug) {
|
|
|
10833
10984
|
|
|
10834
10985
|
// src/runbook-import.ts
|
|
10835
10986
|
var import_node_fs18 = require("fs");
|
|
10836
|
-
var
|
|
10987
|
+
var import_node_path16 = require("path");
|
|
10837
10988
|
function parseRunbook(text2, slug) {
|
|
10838
10989
|
let rest = text2;
|
|
10839
10990
|
const meta = {};
|
|
@@ -10862,8 +11013,8 @@ function readRunbookDir(dir) {
|
|
|
10862
11013
|
const files = (0, import_node_fs18.readdirSync)(dir).filter((f) => f.endsWith(".md")).sort();
|
|
10863
11014
|
if (!files.length) throw new Error(`no .md files in ${dir}`);
|
|
10864
11015
|
return files.map((file) => {
|
|
10865
|
-
const slug = (0,
|
|
10866
|
-
const parsed = parseRunbook((0, import_node_fs18.readFileSync)((0,
|
|
11016
|
+
const slug = (0, import_node_path16.basename)(file, ".md");
|
|
11017
|
+
const parsed = parseRunbook((0, import_node_fs18.readFileSync)((0, import_node_path16.join)(dir, file), "utf8"), slug);
|
|
10867
11018
|
return { file, slug, ...parsed, words: parsed.body.split(/\s+/).filter(Boolean).length };
|
|
10868
11019
|
});
|
|
10869
11020
|
}
|
|
@@ -10937,7 +11088,7 @@ async function upsert(ctx, r, visibility) {
|
|
|
10937
11088
|
// src/runbook-impact.ts
|
|
10938
11089
|
var import_node_child_process7 = require("child_process");
|
|
10939
11090
|
var import_node_fs19 = require("fs");
|
|
10940
|
-
var
|
|
11091
|
+
var import_node_path17 = require("path");
|
|
10941
11092
|
|
|
10942
11093
|
// src/runbook-impact-scan.ts
|
|
10943
11094
|
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$]*)/;
|
|
@@ -11106,7 +11257,7 @@ ${body.split("\n").map((line) => `+${line}`).join("\n")}
|
|
|
11106
11257
|
}
|
|
11107
11258
|
function manifestLabeller(root) {
|
|
11108
11259
|
return (workspace) => {
|
|
11109
|
-
const manifest = (0,
|
|
11260
|
+
const manifest = (0, import_node_path17.join)(root, workspace, "package.json");
|
|
11110
11261
|
if (!(0, import_node_fs19.existsSync)(manifest)) return void 0;
|
|
11111
11262
|
try {
|
|
11112
11263
|
const name = JSON.parse((0, import_node_fs19.readFileSync)(manifest, "utf8")).name;
|
|
@@ -11176,7 +11327,7 @@ function report3(ctx, impacts) {
|
|
|
11176
11327
|
async function runbookImpact(ctx, options, deps = {}) {
|
|
11177
11328
|
const cwd = deps.cwd ?? process.cwd();
|
|
11178
11329
|
const runGit = deps.runGit ?? gitRunner(cwd);
|
|
11179
|
-
const read3 = deps.readRepoFile ?? ((path) => (0, import_node_fs19.readFileSync)((0,
|
|
11330
|
+
const read3 = deps.readRepoFile ?? ((path) => (0, import_node_fs19.readFileSync)((0, import_node_path17.join)(cwd, path), "utf8"));
|
|
11180
11331
|
const surfaces = changedSurfaces(collectDiff(runGit, options.base, read3), manifestLabeller(cwd));
|
|
11181
11332
|
if (!surfaces.length) {
|
|
11182
11333
|
return ctx.out.log(
|
|
@@ -11311,7 +11462,7 @@ async function runbookComment(ctx, slug, body) {
|
|
|
11311
11462
|
var import_node_child_process8 = require("child_process");
|
|
11312
11463
|
var import_node_fs20 = require("fs");
|
|
11313
11464
|
var import_node_os5 = require("os");
|
|
11314
|
-
var
|
|
11465
|
+
var import_node_path18 = require("path");
|
|
11315
11466
|
var import_node_process12 = __toESM(require("process"), 1);
|
|
11316
11467
|
var EDITOR_ENV = ["ODLA_EDITOR", "VISUAL", "EDITOR"];
|
|
11317
11468
|
function resolveEditor(env = import_node_process12.default.env) {
|
|
@@ -11337,8 +11488,8 @@ function editText(initial, slug, deps = {}) {
|
|
|
11337
11488
|
);
|
|
11338
11489
|
if (!interactive())
|
|
11339
11490
|
throw new Error(`cannot open an editor without a terminal \u2014 pass --file <path> or --body "\u2026" instead`);
|
|
11340
|
-
const dir = (0, import_node_fs20.mkdtempSync)((0,
|
|
11341
|
-
const file = (0,
|
|
11491
|
+
const dir = (0, import_node_fs20.mkdtempSync)((0, import_node_path18.join)((0, import_node_os5.tmpdir)(), "odla-runbook-"));
|
|
11492
|
+
const file = (0, import_node_path18.join)(dir, `${slug}.md`);
|
|
11342
11493
|
try {
|
|
11343
11494
|
(0, import_node_fs20.writeFileSync)(file, initial, { mode: 384 });
|
|
11344
11495
|
const code = defaultRunOrInjected(deps)(editor, file);
|
|
@@ -11680,7 +11831,7 @@ async function runbookCommand(parsed, deps = {}) {
|
|
|
11680
11831
|
}
|
|
11681
11832
|
|
|
11682
11833
|
// src/security-command-context.ts
|
|
11683
|
-
var
|
|
11834
|
+
var import_promises12 = require("readline/promises");
|
|
11684
11835
|
async function hostedSecurityContext(parsed, dependencies) {
|
|
11685
11836
|
const configPath = stringOpt(parsed.options.config) ?? "odla.config.mjs";
|
|
11686
11837
|
const cfg = await loadProjectConfig(configPath);
|
|
@@ -11706,7 +11857,7 @@ async function hostedSecurityContext(parsed, dependencies) {
|
|
|
11706
11857
|
async function interactiveConfirmation(message2, dependencies) {
|
|
11707
11858
|
if (dependencies.confirm) return dependencies.confirm(message2);
|
|
11708
11859
|
if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
|
|
11709
|
-
const prompt = (0,
|
|
11860
|
+
const prompt = (0, import_promises12.createInterface)({ input: process.stdin, output: process.stdout });
|
|
11710
11861
|
try {
|
|
11711
11862
|
const answer = await prompt.question(`${message2} [y/N] `);
|
|
11712
11863
|
return /^y(?:es)?$/i.test(answer.trim());
|
|
@@ -11833,7 +11984,7 @@ function hostedSeverity(value2, flag) {
|
|
|
11833
11984
|
var import_security2 = require("@odla-ai/security");
|
|
11834
11985
|
|
|
11835
11986
|
// src/security.ts
|
|
11836
|
-
var
|
|
11987
|
+
var import_node_path19 = require("path");
|
|
11837
11988
|
var import_security = require("@odla-ai/security");
|
|
11838
11989
|
var import_node3 = require("@odla-ai/security/node");
|
|
11839
11990
|
async function runHostedSecurity(options) {
|
|
@@ -11845,9 +11996,9 @@ async function runHostedSecurity(options) {
|
|
|
11845
11996
|
const appId = selfAudit ? "odla-ai" : cfg.app.id;
|
|
11846
11997
|
const env = selfAudit ? "prod" : selectEnv(options.env, cfg.envs, cfg.configPath, cfg.rootDir);
|
|
11847
11998
|
const platform = options.platform ?? cfg?.platformUrl ?? "https://odla.ai";
|
|
11848
|
-
const target = (0,
|
|
11849
|
-
const output = (0,
|
|
11850
|
-
const outputRelative = (0,
|
|
11999
|
+
const target = (0, import_node_path19.resolve)(options.target ?? cfg?.rootDir ?? ".");
|
|
12000
|
+
const output = (0, import_node_path19.resolve)(options.out ?? (0, import_node_path19.resolve)(target, ".odla/security/hosted"));
|
|
12001
|
+
const outputRelative = (0, import_node_path19.relative)(target, output).split(import_node_path19.sep).join("/");
|
|
11851
12002
|
if (!outputRelative) throw new Error("Hosted security output cannot be the repository root");
|
|
11852
12003
|
const profile = profileFor(options.profile ?? "odla", options.maxHuntTasks ?? 12);
|
|
11853
12004
|
const tokenRequest = {
|
|
@@ -11859,7 +12010,7 @@ async function runHostedSecurity(options) {
|
|
|
11859
12010
|
};
|
|
11860
12011
|
const token = await injectedToken(options, tokenRequest);
|
|
11861
12012
|
const snapshot = await (0, import_node3.snapshotDirectory)(target, {
|
|
11862
|
-
exclude: !outputRelative.startsWith("../") && !(0,
|
|
12013
|
+
exclude: !outputRelative.startsWith("../") && !(0, import_node_path19.isAbsolute)(outputRelative) ? [outputRelative] : []
|
|
11863
12014
|
});
|
|
11864
12015
|
const hosted = await (0, import_security.createPlatformSecurityReasoners)({
|
|
11865
12016
|
platform,
|
|
@@ -11877,7 +12028,7 @@ async function runHostedSecurity(options) {
|
|
|
11877
12028
|
});
|
|
11878
12029
|
const harness = (0, import_security.createSecurityHarness)({
|
|
11879
12030
|
profile,
|
|
11880
|
-
store: new import_node3.FileRunStore((0,
|
|
12031
|
+
store: new import_node3.FileRunStore((0, import_node_path19.resolve)(output, "state")),
|
|
11881
12032
|
discoveryReasoner: hosted.discoveryReasoner,
|
|
11882
12033
|
validationReasoner: hosted.validationReasoner,
|
|
11883
12034
|
policy: {
|
|
@@ -11901,7 +12052,7 @@ async function runHostedSecurity(options) {
|
|
|
11901
12052
|
function selectEnv(requested, declared, configPath, rootDir) {
|
|
11902
12053
|
const env = requested ?? (declared.includes("dev") ? "dev" : declared[0]);
|
|
11903
12054
|
if (!env || !declared.includes(env)) {
|
|
11904
|
-
const shown = (0,
|
|
12055
|
+
const shown = (0, import_node_path19.relative)(rootDir, configPath) || configPath;
|
|
11905
12056
|
throw new Error(`env "${env ?? ""}" is not declared in ${shown}`);
|
|
11906
12057
|
}
|
|
11907
12058
|
return env;
|
|
@@ -11930,7 +12081,7 @@ function printSummary(out, appId, env, run, report4, output) {
|
|
|
11930
12081
|
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}`);
|
|
11931
12082
|
if (report4.callBudget) out.log(` calls: discovery=${formatBudget(report4.callBudget.discovery)} validation=${formatBudget(report4.callBudget.validation)}`);
|
|
11932
12083
|
out.log(` findings: confirmed=${report4.metrics.confirmed} needs_reproduction=${report4.metrics.needsReproduction} candidates=${report4.metrics.candidates}`);
|
|
11933
|
-
out.log(` report: ${(0,
|
|
12084
|
+
out.log(` report: ${(0, import_node_path19.resolve)(output, "REPORT.md")}`);
|
|
11934
12085
|
}
|
|
11935
12086
|
function formatBudget(usage) {
|
|
11936
12087
|
return usage ? `${usage.usedCalls}/${usage.maxCalls} skipped=${usage.skippedCalls}` : "caller-managed";
|
|
@@ -12431,6 +12582,10 @@ async function runCli(argv = process.argv.slice(2), dependencies = {}) {
|
|
|
12431
12582
|
await securityCommand(parsed, runtime);
|
|
12432
12583
|
return;
|
|
12433
12584
|
}
|
|
12585
|
+
if (command === "brand") {
|
|
12586
|
+
await brandCommand(parsed, runtime);
|
|
12587
|
+
return;
|
|
12588
|
+
}
|
|
12434
12589
|
if (command === "pm") {
|
|
12435
12590
|
await pmCommand(parsed, runtime);
|
|
12436
12591
|
return;
|