@odla-ai/cli 0.35.0 → 0.35.3
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 +187 -95
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-EG23MPUC.js → chunk-PYR73XBD.js} +82 -7
- package/dist/chunk-PYR73XBD.js.map +1 -0
- package/dist/{cli-Z5NSTS75.js → cli-ZBNA7J4T.js} +2 -2
- package/dist/index.cjs +155 -80
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-EG23MPUC.js.map +0 -1
- /package/dist/{cli-Z5NSTS75.js.map → cli-ZBNA7J4T.js.map} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
runCli
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-PYR73XBD.js";
|
|
5
5
|
import {
|
|
6
6
|
exitCodeFor
|
|
7
7
|
} from "./chunk-UKLSRQ5J.js";
|
|
@@ -9,4 +9,4 @@ export {
|
|
|
9
9
|
exitCodeFor,
|
|
10
10
|
runCli
|
|
11
11
|
};
|
|
12
|
-
//# sourceMappingURL=cli-
|
|
12
|
+
//# sourceMappingURL=cli-ZBNA7J4T.js.map
|
package/dist/index.cjs
CHANGED
|
@@ -236,13 +236,36 @@ function handshakeWaitMs(waitSeconds, interactive = import_node_process3.default
|
|
|
236
236
|
return interactive ? void 0 : 9e4;
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
-
// src/
|
|
239
|
+
// src/cached-credential.ts
|
|
240
240
|
var import_node_fs2 = require("fs");
|
|
241
|
+
var noted = null;
|
|
242
|
+
function noteCachedCredential(tokenFile) {
|
|
243
|
+
noted = tokenFile;
|
|
244
|
+
}
|
|
245
|
+
function isCredentialRejection(error) {
|
|
246
|
+
const message2 = error instanceof Error ? error.message : String(error ?? "");
|
|
247
|
+
return /\((401|403)\)\s*$/.test(message2.trim());
|
|
248
|
+
}
|
|
249
|
+
function explainRejectedCredential(error) {
|
|
250
|
+
const tokenFile = noted;
|
|
251
|
+
if (!tokenFile || !isCredentialRejection(error)) return null;
|
|
252
|
+
noted = null;
|
|
253
|
+
(0, import_node_fs2.rmSync)(tokenFile, { force: true });
|
|
254
|
+
return [
|
|
255
|
+
"auth: the cached credential was rejected by odla, so it was revoked before its cached expiry.",
|
|
256
|
+
" The usual cause is a newer sign-in for this project: collecting a handshake retires the",
|
|
257
|
+
" principal's other credentials, so a second terminal or worktree supersedes this one.",
|
|
258
|
+
` Discarded ${tokenFile}; re-run this command to request a fresh approval.`
|
|
259
|
+
].join("\n");
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// src/local.ts
|
|
263
|
+
var import_node_fs3 = require("fs");
|
|
241
264
|
var import_node_path2 = require("path");
|
|
242
265
|
var GITIGNORE_LINES = [".odla/*.local.json", ".odla/dev-token.json", ".dev.vars"];
|
|
243
266
|
function readJsonFile(path) {
|
|
244
267
|
try {
|
|
245
|
-
return JSON.parse((0,
|
|
268
|
+
return JSON.parse((0, import_node_fs3.readFileSync)(path, "utf8"));
|
|
246
269
|
} catch {
|
|
247
270
|
return null;
|
|
248
271
|
}
|
|
@@ -252,10 +275,10 @@ function writePrivateJson(path, value2) {
|
|
|
252
275
|
`);
|
|
253
276
|
}
|
|
254
277
|
function readCredentials(path) {
|
|
255
|
-
if (!(0,
|
|
278
|
+
if (!(0, import_node_fs3.existsSync)(path)) return null;
|
|
256
279
|
let value2;
|
|
257
280
|
try {
|
|
258
|
-
value2 = JSON.parse((0,
|
|
281
|
+
value2 = JSON.parse((0, import_node_fs3.readFileSync)(path, "utf8"));
|
|
259
282
|
} catch {
|
|
260
283
|
throw new Error(`credentials file ${path} is not valid JSON; fix or remove it before provisioning`);
|
|
261
284
|
}
|
|
@@ -286,13 +309,13 @@ function mergeCredential(current, update) {
|
|
|
286
309
|
}
|
|
287
310
|
function ensureGitignore(rootDir, localPaths = []) {
|
|
288
311
|
const path = (0, import_node_path2.resolve)(rootDir, ".gitignore");
|
|
289
|
-
const existing = (0,
|
|
312
|
+
const existing = (0, import_node_fs3.existsSync)(path) ? (0, import_node_fs3.readFileSync)(path, "utf8") : "";
|
|
290
313
|
const configured = localPaths.map((localPath) => gitignoreEntry(rootDir, localPath)).filter((line2) => !!line2);
|
|
291
314
|
const wanted = [.../* @__PURE__ */ new Set([...GITIGNORE_LINES, ...configured])];
|
|
292
315
|
const missing = wanted.filter((line2) => !existing.split(/\r?\n/).includes(line2));
|
|
293
316
|
if (missing.length === 0) return;
|
|
294
317
|
const prefix = existing && !existing.endsWith("\n") ? "\n" : "";
|
|
295
|
-
(0,
|
|
318
|
+
(0, import_node_fs3.writeFileSync)(path, `${existing}${prefix}${missing.join("\n")}
|
|
296
319
|
`);
|
|
297
320
|
}
|
|
298
321
|
function o11yDevVars(cfg) {
|
|
@@ -320,7 +343,7 @@ function writeDevVars(path, credentials, env, o11y) {
|
|
|
320
343
|
if (o11y.version) lines.push(`ODLA_O11Y_VERSION="${o11y.version}"`);
|
|
321
344
|
if (entry.o11yToken) lines.push(`ODLA_O11Y_TOKEN="${entry.o11yToken}"`);
|
|
322
345
|
}
|
|
323
|
-
const existing = (0,
|
|
346
|
+
const existing = (0, import_node_fs3.existsSync)(path) ? (0, import_node_fs3.readFileSync)(path, "utf8") : "";
|
|
324
347
|
const retained = existing.split(/\r?\n/).filter((line2) => !isManagedDevVar(line2));
|
|
325
348
|
while (retained.at(-1) === "") retained.pop();
|
|
326
349
|
const prefix = retained.length ? `${retained.join("\n")}
|
|
@@ -346,11 +369,11 @@ function isManagedDevVar(line2) {
|
|
|
346
369
|
return !!match?.[1] && MANAGED_DEV_VARS.has(match[1]);
|
|
347
370
|
}
|
|
348
371
|
function writePrivateText(path, text3) {
|
|
349
|
-
(0,
|
|
372
|
+
(0, import_node_fs3.mkdirSync)((0, import_node_path2.dirname)(path), { recursive: true });
|
|
350
373
|
const temporary = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
351
|
-
(0,
|
|
352
|
-
(0,
|
|
353
|
-
(0,
|
|
374
|
+
(0, import_node_fs3.writeFileSync)(temporary, text3, { mode: 384 });
|
|
375
|
+
(0, import_node_fs3.chmodSync)(temporary, 384);
|
|
376
|
+
(0, import_node_fs3.renameSync)(temporary, path);
|
|
354
377
|
}
|
|
355
378
|
function gitignoreEntry(rootDir, path) {
|
|
356
379
|
const rel = (0, import_node_path2.relative)((0, import_node_path2.resolve)(rootDir), (0, import_node_path2.resolve)(path));
|
|
@@ -381,6 +404,7 @@ async function getDeveloperToken(cfg, options, doFetch, out, grantRequest = {})
|
|
|
381
404
|
}
|
|
382
405
|
if (cached?.token && cached.platform === audience && (cached.expiresAt ?? 0) > Date.now() + 6e4 && cachedGrantCovers(cached, grantIntent)) {
|
|
383
406
|
out.error(`auth: using cached developer token (${displayPath(cfg.local.tokenFile, cfg.rootDir)})`);
|
|
407
|
+
noteCachedCredential(cfg.local.tokenFile);
|
|
384
408
|
return cached.token;
|
|
385
409
|
}
|
|
386
410
|
} else {
|
|
@@ -535,7 +559,7 @@ async function readSecretStream(kind, stream = import_node_process5.default.stdi
|
|
|
535
559
|
}
|
|
536
560
|
|
|
537
561
|
// src/admin-ai-auth.ts
|
|
538
|
-
var
|
|
562
|
+
var import_node_fs4 = require("fs");
|
|
539
563
|
var import_node_path3 = require("path");
|
|
540
564
|
var import_node_process6 = __toESM(require("process"), 1);
|
|
541
565
|
var import_db2 = require("@odla-ai/db");
|
|
@@ -610,7 +634,7 @@ async function scopedToken(platform, scope, options, doFetch, out) {
|
|
|
610
634
|
if (options.cache !== false) {
|
|
611
635
|
const tokens = cache2?.platform === audience ? { ...cache2.tokens ?? {} } : {};
|
|
612
636
|
tokens[scope] = { token, expiresAt };
|
|
613
|
-
if ((0,
|
|
637
|
+
if ((0, import_node_fs4.existsSync)((0, import_node_path3.join)(rootDir, ".git"))) ensureGitignore(rootDir, [tokenFile]);
|
|
614
638
|
writePrivateJson(tokenFile, { platform: audience, email, tokens });
|
|
615
639
|
out.error(`auth: cached ${scope} grant (${tokenFile}; mode 0600)`);
|
|
616
640
|
} else {
|
|
@@ -1042,12 +1066,12 @@ function addOption(options, name, value2) {
|
|
|
1042
1066
|
}
|
|
1043
1067
|
|
|
1044
1068
|
// src/operator-context.ts
|
|
1045
|
-
var
|
|
1069
|
+
var import_node_fs7 = require("fs");
|
|
1046
1070
|
var import_node_path6 = require("path");
|
|
1047
1071
|
var import_node_process9 = __toESM(require("process"), 1);
|
|
1048
1072
|
|
|
1049
1073
|
// src/config.ts
|
|
1050
|
-
var
|
|
1074
|
+
var import_node_fs5 = require("fs");
|
|
1051
1075
|
var import_node_path4 = require("path");
|
|
1052
1076
|
var import_node_url = require("url");
|
|
1053
1077
|
var import_apps = require("@odla-ai/apps");
|
|
@@ -1454,7 +1478,7 @@ var configImportSerial = 0;
|
|
|
1454
1478
|
var GOOGLE_CALENDAR_EVENTS_SCOPE = "https://www.googleapis.com/auth/calendar.events";
|
|
1455
1479
|
async function loadProjectConfig(configPath = "odla.config.mjs", options = {}) {
|
|
1456
1480
|
const resolved = (0, import_node_path4.resolve)(configPath);
|
|
1457
|
-
if (!(0,
|
|
1481
|
+
if (!(0, import_node_fs5.existsSync)(resolved)) {
|
|
1458
1482
|
throw new Error(`config not found: ${configPath}. Run "odla-ai init" first or pass --config.`);
|
|
1459
1483
|
}
|
|
1460
1484
|
const raw = await loadConfigModule(resolved);
|
|
@@ -1489,7 +1513,7 @@ async function resolveDataExport(cfg, value2, names) {
|
|
|
1489
1513
|
if (typeof value2 !== "string") return value2;
|
|
1490
1514
|
const target = (0, import_node_path4.isAbsolute)(value2) ? value2 : (0, import_node_path4.resolve)(cfg.rootDir, value2);
|
|
1491
1515
|
if (target.endsWith(".json")) {
|
|
1492
|
-
return JSON.parse((0,
|
|
1516
|
+
return JSON.parse((0, import_node_fs5.readFileSync)(target, "utf8"));
|
|
1493
1517
|
}
|
|
1494
1518
|
const mod = await import((0, import_node_url.pathToFileURL)(target).href);
|
|
1495
1519
|
for (const name of names) {
|
|
@@ -1565,7 +1589,7 @@ function validId2(value2) {
|
|
|
1565
1589
|
return typeof value2 === "string" && /^[a-z0-9][a-z0-9-]*$/.test(value2);
|
|
1566
1590
|
}
|
|
1567
1591
|
async function loadConfigModule(path) {
|
|
1568
|
-
if (path.endsWith(".json")) return JSON.parse((0,
|
|
1592
|
+
if (path.endsWith(".json")) return JSON.parse((0, import_node_fs5.readFileSync)(path, "utf8"));
|
|
1569
1593
|
const nonce = `${Date.now()}-${configImportSerial++}`;
|
|
1570
1594
|
const mod = await import(`${(0, import_node_url.pathToFileURL)(path).href}?reload=${nonce}`);
|
|
1571
1595
|
const value2 = mod.default ?? mod.config;
|
|
@@ -1580,7 +1604,7 @@ function unique3(values) {
|
|
|
1580
1604
|
}
|
|
1581
1605
|
|
|
1582
1606
|
// src/operator-profiles.ts
|
|
1583
|
-
var
|
|
1607
|
+
var import_node_fs6 = require("fs");
|
|
1584
1608
|
var import_node_os = require("os");
|
|
1585
1609
|
var import_node_path5 = require("path");
|
|
1586
1610
|
var import_node_process8 = __toESM(require("process"), 1);
|
|
@@ -1645,10 +1669,10 @@ function assertOperatorName(value2, label) {
|
|
|
1645
1669
|
}
|
|
1646
1670
|
}
|
|
1647
1671
|
function readOperatorProfiles(file) {
|
|
1648
|
-
if (!(0,
|
|
1672
|
+
if (!(0, import_node_fs6.existsSync)(file)) return emptyProfiles();
|
|
1649
1673
|
let raw;
|
|
1650
1674
|
try {
|
|
1651
|
-
raw = JSON.parse((0,
|
|
1675
|
+
raw = JSON.parse((0, import_node_fs6.readFileSync)(file, "utf8"));
|
|
1652
1676
|
} catch {
|
|
1653
1677
|
throw new Error(`operator context file ${file} is not valid JSON`);
|
|
1654
1678
|
}
|
|
@@ -1714,7 +1738,7 @@ async function resolveOperatorContext(parsed, options = {}) {
|
|
|
1714
1738
|
const configArgument = stringOpt(parsed.options.config) ?? "odla.config.mjs";
|
|
1715
1739
|
const configPath = (0, import_node_path6.resolve)(configArgument);
|
|
1716
1740
|
const explicitConfig = parsed.options.config !== void 0;
|
|
1717
|
-
const hasConfig = (0,
|
|
1741
|
+
const hasConfig = (0, import_node_fs7.existsSync)(configPath);
|
|
1718
1742
|
if (!hasConfig && (!options.allowMissingConfig || explicitConfig)) {
|
|
1719
1743
|
await loadProjectConfig(configArgument);
|
|
1720
1744
|
}
|
|
@@ -2180,7 +2204,7 @@ async function appExport(options) {
|
|
|
2180
2204
|
}
|
|
2181
2205
|
|
|
2182
2206
|
// src/app-import.ts
|
|
2183
|
-
var
|
|
2207
|
+
var import_node_fs8 = require("fs");
|
|
2184
2208
|
var import_import = require("@odla-ai/db/import");
|
|
2185
2209
|
function chooseIdMode(options, rows) {
|
|
2186
2210
|
const chosen = [options.idField && "field", options.key && "key", options.generateIds && "generate"].filter(Boolean);
|
|
@@ -2198,7 +2222,7 @@ async function appImport(options) {
|
|
|
2198
2222
|
const out = options.stdout ?? console;
|
|
2199
2223
|
const say = options.json ? (line2) => out.error(line2) : (line2) => out.log(line2);
|
|
2200
2224
|
const { tenant } = resolveTenant(cfg, options.env);
|
|
2201
|
-
const text3 = options.file === "-" ? (options.readStdin ?? (() => (0,
|
|
2225
|
+
const text3 = options.file === "-" ? (options.readStdin ?? (() => (0, import_node_fs8.readFileSync)(0, "utf8")))() : (0, import_node_fs8.readFileSync)(options.file, "utf8");
|
|
2202
2226
|
const { format, sources } = (0, import_import.parseImport)(text3, options.ns);
|
|
2203
2227
|
if (format === "namespace-map" && options.ns) {
|
|
2204
2228
|
throw new Error("--ns cannot be combined with a {namespace: rows} file \u2014 the file already names each namespace");
|
|
@@ -3114,9 +3138,9 @@ var import_apps6 = require("@odla-ai/apps");
|
|
|
3114
3138
|
var import_node_path8 = require("path");
|
|
3115
3139
|
|
|
3116
3140
|
// src/version.ts
|
|
3117
|
-
var
|
|
3141
|
+
var import_node_fs9 = require("fs");
|
|
3118
3142
|
function cliVersion() {
|
|
3119
|
-
const pkg = JSON.parse((0,
|
|
3143
|
+
const pkg = JSON.parse((0, import_node_fs9.readFileSync)(new URL("../package.json", importMetaUrl), "utf8"));
|
|
3120
3144
|
return pkg.version ?? "unknown";
|
|
3121
3145
|
}
|
|
3122
3146
|
|
|
@@ -3132,7 +3156,7 @@ var ConfigOperationCommandError = class extends Error {
|
|
|
3132
3156
|
|
|
3133
3157
|
// src/config-operation-validate.ts
|
|
3134
3158
|
var import_apps3 = require("@odla-ai/apps");
|
|
3135
|
-
var
|
|
3159
|
+
var import_node_fs10 = require("fs");
|
|
3136
3160
|
|
|
3137
3161
|
// src/config-reconcile-digest.ts
|
|
3138
3162
|
var import_node_crypto2 = require("crypto");
|
|
@@ -3168,7 +3192,7 @@ var SERVICE = /^[a-z][a-z0-9-]{0,39}$/;
|
|
|
3168
3192
|
function readPlan(path) {
|
|
3169
3193
|
let value2;
|
|
3170
3194
|
try {
|
|
3171
|
-
const raw = (0,
|
|
3195
|
+
const raw = (0, import_node_fs10.readFileSync)(path, "utf8");
|
|
3172
3196
|
if (Buffer.byteLength(raw) > 128 * 1024) throw new Error("plan exceeds 128 KiB");
|
|
3173
3197
|
value2 = JSON.parse(raw);
|
|
3174
3198
|
} catch (error) {
|
|
@@ -4024,12 +4048,12 @@ function quoteArg2(value2) {
|
|
|
4024
4048
|
|
|
4025
4049
|
// src/doctor-checks.ts
|
|
4026
4050
|
var import_node_child_process3 = require("child_process");
|
|
4027
|
-
var
|
|
4051
|
+
var import_node_fs12 = require("fs");
|
|
4028
4052
|
var import_node_path11 = require("path");
|
|
4029
4053
|
|
|
4030
4054
|
// src/wrangler.ts
|
|
4031
4055
|
var import_node_child_process2 = require("child_process");
|
|
4032
|
-
var
|
|
4056
|
+
var import_node_fs11 = require("fs");
|
|
4033
4057
|
var import_node_path10 = require("path");
|
|
4034
4058
|
var defaultRunner = (cmd, args, opts) => new Promise((resolvePromise, reject) => {
|
|
4035
4059
|
const child = (0, import_node_child_process2.spawn)(cmd, args, { cwd: opts?.cwd, stdio: ["pipe", "pipe", "pipe"] });
|
|
@@ -4045,14 +4069,14 @@ var WRANGLER_CONFIG_FILES = ["wrangler.jsonc", "wrangler.json", "wrangler.toml"]
|
|
|
4045
4069
|
function findWranglerConfig(rootDir) {
|
|
4046
4070
|
for (const name of WRANGLER_CONFIG_FILES) {
|
|
4047
4071
|
const path = (0, import_node_path10.join)(rootDir, name);
|
|
4048
|
-
if ((0,
|
|
4072
|
+
if ((0, import_node_fs11.existsSync)(path)) return path;
|
|
4049
4073
|
}
|
|
4050
4074
|
return null;
|
|
4051
4075
|
}
|
|
4052
4076
|
function readWranglerConfig(path) {
|
|
4053
4077
|
if (path.endsWith(".toml")) return null;
|
|
4054
4078
|
try {
|
|
4055
|
-
return JSON.parse(stripJsonComments((0,
|
|
4079
|
+
return JSON.parse(stripJsonComments((0, import_node_fs11.readFileSync)(path, "utf8")));
|
|
4056
4080
|
} catch {
|
|
4057
4081
|
return null;
|
|
4058
4082
|
}
|
|
@@ -4205,7 +4229,7 @@ function wranglerWarnings(rootDir) {
|
|
|
4205
4229
|
const dir = (0, import_node_path11.resolve)(rootDir, assets.directory);
|
|
4206
4230
|
if (dir === (0, import_node_path11.resolve)(rootDir)) {
|
|
4207
4231
|
warnings.push(`${label}assets.directory is the project root \u2014 point it at a dedicated build dir (wrangler dev fails with "spawn EBADF")`);
|
|
4208
|
-
} else if ((0,
|
|
4232
|
+
} else if ((0, import_node_fs12.existsSync)((0, import_node_path11.join)(dir, "node_modules"))) {
|
|
4209
4233
|
warnings.push(`${label}assets.directory contains node_modules \u2014 wrangler dev's watcher will exhaust file descriptors`);
|
|
4210
4234
|
}
|
|
4211
4235
|
}
|
|
@@ -4241,12 +4265,12 @@ function o11yProjectWarnings(rootDir) {
|
|
|
4241
4265
|
return warnings;
|
|
4242
4266
|
}
|
|
4243
4267
|
const main = typeof config.main === "string" ? (0, import_node_path11.resolve)(rootDir, config.main) : null;
|
|
4244
|
-
if (!main || !(0,
|
|
4268
|
+
if (!main || !(0, import_node_fs12.existsSync)(main)) {
|
|
4245
4269
|
warnings.push("cannot verify o11y Worker instrumentation \u2014 wrangler main is missing or unreadable");
|
|
4246
4270
|
} else {
|
|
4247
4271
|
let source = "";
|
|
4248
4272
|
try {
|
|
4249
|
-
source = (0,
|
|
4273
|
+
source = (0, import_node_fs12.readFileSync)(main, "utf8");
|
|
4250
4274
|
} catch {
|
|
4251
4275
|
}
|
|
4252
4276
|
if (!/\bwithObservability\b/.test(source)) {
|
|
@@ -4270,7 +4294,7 @@ function calendarProjectWarnings(rootDir) {
|
|
|
4270
4294
|
}
|
|
4271
4295
|
function readPackageJson(rootDir) {
|
|
4272
4296
|
try {
|
|
4273
|
-
return JSON.parse((0,
|
|
4297
|
+
return JSON.parse((0, import_node_fs12.readFileSync)((0, import_node_path11.join)(rootDir, "package.json"), "utf8"));
|
|
4274
4298
|
} catch {
|
|
4275
4299
|
return null;
|
|
4276
4300
|
}
|
|
@@ -4564,14 +4588,14 @@ function harnessOption(value2, flag) {
|
|
|
4564
4588
|
}
|
|
4565
4589
|
|
|
4566
4590
|
// src/init.ts
|
|
4567
|
-
var
|
|
4591
|
+
var import_node_fs13 = require("fs");
|
|
4568
4592
|
var import_node_path12 = require("path");
|
|
4569
4593
|
var import_apps9 = require("@odla-ai/apps");
|
|
4570
4594
|
function initProject(options) {
|
|
4571
4595
|
const out = options.stdout ?? console;
|
|
4572
4596
|
const rootDir = (0, import_node_path12.resolve)(options.rootDir ?? process.cwd());
|
|
4573
4597
|
const configPath = (0, import_node_path12.resolve)(rootDir, options.configPath ?? "odla.config.mjs");
|
|
4574
|
-
if ((0,
|
|
4598
|
+
if ((0, import_node_fs13.existsSync)(configPath) && !options.force) {
|
|
4575
4599
|
throw new Error(`${configPath} already exists. Pass --force to overwrite.`);
|
|
4576
4600
|
}
|
|
4577
4601
|
if (!/^[a-z0-9][a-z0-9-]*$/.test(options.appId)) {
|
|
@@ -4587,10 +4611,10 @@ function initProject(options) {
|
|
|
4587
4611
|
}
|
|
4588
4612
|
}
|
|
4589
4613
|
const aiProvider = options.aiProvider;
|
|
4590
|
-
(0,
|
|
4591
|
-
(0,
|
|
4592
|
-
(0,
|
|
4593
|
-
(0,
|
|
4614
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path12.dirname)(configPath), { recursive: true });
|
|
4615
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path12.resolve)(rootDir, "src/odla"), { recursive: true });
|
|
4616
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path12.resolve)(rootDir, ".odla"), { recursive: true });
|
|
4617
|
+
(0, import_node_fs13.writeFileSync)(configPath, configTemplate({ appId: options.appId, name: options.name, envs, services, aiProvider }));
|
|
4594
4618
|
writeIfMissing((0, import_node_path12.resolve)(rootDir, "src/odla/schema.mjs"), schemaTemplate());
|
|
4595
4619
|
writeIfMissing((0, import_node_path12.resolve)(rootDir, "src/odla/rules.mjs"), rulesTemplate());
|
|
4596
4620
|
ensureGitignore(rootDir);
|
|
@@ -4599,8 +4623,8 @@ function initProject(options) {
|
|
|
4599
4623
|
out.log("updated .gitignore for local odla credentials");
|
|
4600
4624
|
}
|
|
4601
4625
|
function writeIfMissing(path, text3) {
|
|
4602
|
-
if ((0,
|
|
4603
|
-
(0,
|
|
4626
|
+
if ((0, import_node_fs13.existsSync)(path)) return;
|
|
4627
|
+
(0, import_node_fs13.writeFileSync)(path, text3);
|
|
4604
4628
|
}
|
|
4605
4629
|
function configTemplate(input) {
|
|
4606
4630
|
const calendar = input.services.includes("calendar") ? ` calendar: {
|
|
@@ -4896,7 +4920,7 @@ function printReport(report5, out) {
|
|
|
4896
4920
|
}
|
|
4897
4921
|
|
|
4898
4922
|
// src/skill.ts
|
|
4899
|
-
var
|
|
4923
|
+
var import_node_fs14 = require("fs");
|
|
4900
4924
|
var import_node_os2 = require("os");
|
|
4901
4925
|
var import_node_path13 = require("path");
|
|
4902
4926
|
var import_node_url2 = require("url");
|
|
@@ -5012,7 +5036,7 @@ function installSkill(options = {}) {
|
|
|
5012
5036
|
plans.set(target, { target, content: content2, boundary, managedMerge });
|
|
5013
5037
|
};
|
|
5014
5038
|
const planSkillTree = (targetDir2, boundary = root) => {
|
|
5015
|
-
for (const rel of files) plan((0, import_node_path13.join)(targetDir2, rel), (0,
|
|
5039
|
+
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);
|
|
5016
5040
|
};
|
|
5017
5041
|
let targetDir;
|
|
5018
5042
|
if (options.global) {
|
|
@@ -5032,7 +5056,7 @@ function installSkill(options = {}) {
|
|
|
5032
5056
|
for (const harness of harnesses) rememberTarget(harness, sharedRoot);
|
|
5033
5057
|
if (harnesses.includes("claude")) {
|
|
5034
5058
|
for (const skill of skillNames(files)) {
|
|
5035
|
-
const canonical2 = (0,
|
|
5059
|
+
const canonical2 = (0, import_node_fs14.readFileSync)((0, import_node_path13.join)(sourceDir, skill, "SKILL.md"), "utf8");
|
|
5036
5060
|
plan((0, import_node_path13.join)(claudeRoot, skill, "SKILL.md"), claudeAdapter(skill, canonical2));
|
|
5037
5061
|
}
|
|
5038
5062
|
rememberTarget("claude", claudeRoot);
|
|
@@ -5067,11 +5091,11 @@ function installSkill(options = {}) {
|
|
|
5067
5091
|
conflicts.push(`${file.target} (redirected by symbolic link ${symlink})`);
|
|
5068
5092
|
continue;
|
|
5069
5093
|
}
|
|
5070
|
-
if (!(0,
|
|
5094
|
+
if (!(0, import_node_fs14.existsSync)(file.target)) {
|
|
5071
5095
|
writtenPaths.add(file.target);
|
|
5072
5096
|
continue;
|
|
5073
5097
|
}
|
|
5074
|
-
const current = (0,
|
|
5098
|
+
const current = (0, import_node_fs14.readFileSync)(file.target, "utf8");
|
|
5075
5099
|
if (current === file.content) {
|
|
5076
5100
|
unchangedPaths.add(file.target);
|
|
5077
5101
|
} else if (file.managedMerge || options.force) {
|
|
@@ -5088,9 +5112,9 @@ ${conflicts.map((f) => ` - ${f}`).join("\n")}`
|
|
|
5088
5112
|
);
|
|
5089
5113
|
}
|
|
5090
5114
|
for (const file of plans.values()) {
|
|
5091
|
-
if (!(0,
|
|
5092
|
-
(0,
|
|
5093
|
-
(0,
|
|
5115
|
+
if (!(0, import_node_fs14.existsSync)(file.target) || (0, import_node_fs14.readFileSync)(file.target, "utf8") !== file.content) {
|
|
5116
|
+
(0, import_node_fs14.mkdirSync)((0, import_node_path13.dirname)(file.target), { recursive: true });
|
|
5117
|
+
(0, import_node_fs14.writeFileSync)(file.target, file.content);
|
|
5094
5118
|
}
|
|
5095
5119
|
}
|
|
5096
5120
|
const skills = skillNames(files);
|
|
@@ -5131,9 +5155,9 @@ function normalizeHarnesses(values, global) {
|
|
|
5131
5155
|
function managedFileContent(path, block, force, boundary) {
|
|
5132
5156
|
const symlink = symlinkedComponent(boundary, path);
|
|
5133
5157
|
if (symlink) throw new Error(`refusing to manage ${path}: symbolic link component ${symlink}`);
|
|
5134
|
-
if (!(0,
|
|
5158
|
+
if (!(0, import_node_fs14.existsSync)(path)) return `${block}
|
|
5135
5159
|
`;
|
|
5136
|
-
const current = (0,
|
|
5160
|
+
const current = (0, import_node_fs14.readFileSync)(path, "utf8");
|
|
5137
5161
|
const start = "<!-- odla-ai agent setup:start -->";
|
|
5138
5162
|
const end = "<!-- odla-ai agent setup:end -->";
|
|
5139
5163
|
const startAt = current.indexOf(start);
|
|
@@ -5162,7 +5186,7 @@ function symlinkedComponent(boundary, target) {
|
|
|
5162
5186
|
for (const part of rel.split(import_node_path13.sep).filter(Boolean)) {
|
|
5163
5187
|
current = (0, import_node_path13.join)(current, part);
|
|
5164
5188
|
try {
|
|
5165
|
-
if ((0,
|
|
5189
|
+
if ((0, import_node_fs14.lstatSync)(current).isSymbolicLink()) return current;
|
|
5166
5190
|
} catch (error) {
|
|
5167
5191
|
if (error.code !== "ENOENT") throw error;
|
|
5168
5192
|
}
|
|
@@ -5173,10 +5197,10 @@ function skillNames(files) {
|
|
|
5173
5197
|
return [...new Set(files.filter((file) => /(^|[\\/])SKILL\.md$/.test(file)).map((file) => file.split(/[\\/]/)[0]))].sort();
|
|
5174
5198
|
}
|
|
5175
5199
|
function listFiles(dir) {
|
|
5176
|
-
if (!(0,
|
|
5200
|
+
if (!(0, import_node_fs14.existsSync)(dir)) return [];
|
|
5177
5201
|
const results = [];
|
|
5178
5202
|
const walk = (current) => {
|
|
5179
|
-
for (const entry of (0,
|
|
5203
|
+
for (const entry of (0, import_node_fs14.readdirSync)(current, { withFileTypes: true })) {
|
|
5180
5204
|
const path = (0, import_node_path13.join)(current, entry.name);
|
|
5181
5205
|
if (entry.isDirectory()) walk(path);
|
|
5182
5206
|
else results.push((0, import_node_path13.relative)(dir, path));
|
|
@@ -5534,7 +5558,7 @@ async function projectCommand(command, parsed, deps) {
|
|
|
5534
5558
|
}
|
|
5535
5559
|
|
|
5536
5560
|
// src/code-connect.ts
|
|
5537
|
-
var
|
|
5561
|
+
var import_node_fs15 = require("fs");
|
|
5538
5562
|
var import_node_os3 = require("os");
|
|
5539
5563
|
var import_node_path14 = require("path");
|
|
5540
5564
|
|
|
@@ -9584,7 +9608,7 @@ var CODE_BUILD_RECIPES = Object.freeze([{
|
|
|
9584
9608
|
async function codeConnect(options) {
|
|
9585
9609
|
const cwd = options.cwd ?? process.cwd();
|
|
9586
9610
|
const configPath = (0, import_node_path14.resolve)(cwd, options.configPath);
|
|
9587
|
-
const cfg = (0,
|
|
9611
|
+
const cfg = (0, import_node_fs15.existsSync)(configPath) ? await loadProjectConfig(configPath) : null;
|
|
9588
9612
|
const requestedAppId = options.appId?.trim();
|
|
9589
9613
|
if (requestedAppId && !/^[a-z0-9][a-z0-9-]{1,62}$/.test(requestedAppId)) {
|
|
9590
9614
|
throw new Error("--app-id must be a valid odla app id");
|
|
@@ -13210,7 +13234,7 @@ async function provision(options) {
|
|
|
13210
13234
|
}
|
|
13211
13235
|
|
|
13212
13236
|
// src/record.ts
|
|
13213
|
-
var
|
|
13237
|
+
var import_node_fs16 = require("fs");
|
|
13214
13238
|
var import_node_process13 = __toESM(require("process"), 1);
|
|
13215
13239
|
|
|
13216
13240
|
// src/surface.ts
|
|
@@ -13400,14 +13424,37 @@ function recordInvocation(parsed) {
|
|
|
13400
13424
|
options: Object.entries(parsed.options).map(([name, value2]) => value2 === false ? `no-${name}` : name).sort()
|
|
13401
13425
|
};
|
|
13402
13426
|
if (!entry.path.length) return;
|
|
13403
|
-
(0,
|
|
13427
|
+
(0, import_node_fs16.appendFileSync)(file, `${JSON.stringify(entry)}
|
|
13404
13428
|
`);
|
|
13405
13429
|
} catch {
|
|
13406
13430
|
}
|
|
13407
13431
|
}
|
|
13408
13432
|
|
|
13433
|
+
// src/advisory-output.ts
|
|
13434
|
+
var import_apps14 = require("@odla-ai/apps");
|
|
13435
|
+
function advisoryCollectingFetch(inner, sink) {
|
|
13436
|
+
return (async (input, init) => {
|
|
13437
|
+
const response2 = await inner(input, init);
|
|
13438
|
+
try {
|
|
13439
|
+
sink.push(...(0, import_apps14.parseAdvisories)(response2));
|
|
13440
|
+
} catch {
|
|
13441
|
+
}
|
|
13442
|
+
return response2;
|
|
13443
|
+
});
|
|
13444
|
+
}
|
|
13445
|
+
function renderAdvisories(out, advisories, env = process.env) {
|
|
13446
|
+
if (env.ODLA_NO_ADVISORIES) return;
|
|
13447
|
+
const seen = /* @__PURE__ */ new Set();
|
|
13448
|
+
for (const advisory of advisories) {
|
|
13449
|
+
const key = `${advisory.code}:${advisory.message}`;
|
|
13450
|
+
if (seen.has(key)) continue;
|
|
13451
|
+
seen.add(key);
|
|
13452
|
+
out.error((0, import_apps14.formatAdvisory)(advisory));
|
|
13453
|
+
}
|
|
13454
|
+
}
|
|
13455
|
+
|
|
13409
13456
|
// src/runbook-actions.ts
|
|
13410
|
-
var
|
|
13457
|
+
var import_node_fs17 = require("fs");
|
|
13411
13458
|
|
|
13412
13459
|
// src/runbook-requires.ts
|
|
13413
13460
|
var SPEC = /^(@?[\w./-]+?)@(\d+\.\d+\.\d+(?:[\w.-]*)?)$/;
|
|
@@ -13485,14 +13532,25 @@ async function bySlug(ctx, slug) {
|
|
|
13485
13532
|
"GET",
|
|
13486
13533
|
`/runbook?app=${encodeURIComponent(ctx.appId)}&slug=${encodeURIComponent(slug)}&limit=1`
|
|
13487
13534
|
);
|
|
13488
|
-
const
|
|
13489
|
-
if (
|
|
13490
|
-
|
|
13535
|
+
const filtered = page2.records.find((record11) => record11.slug === slug);
|
|
13536
|
+
if (filtered) return filtered;
|
|
13537
|
+
const limit = 100;
|
|
13538
|
+
for (let offset = 0; ; offset += limit) {
|
|
13539
|
+
const fallback = await call(
|
|
13540
|
+
ctx,
|
|
13541
|
+
"GET",
|
|
13542
|
+
`/runbook?app=${encodeURIComponent(ctx.appId)}&limit=${limit}&offset=${offset}`
|
|
13543
|
+
);
|
|
13544
|
+
const found = fallback.records.find((record11) => record11.slug === slug);
|
|
13545
|
+
if (found) return found;
|
|
13546
|
+
if (!fallback.records.length || offset + fallback.records.length >= fallback.total) break;
|
|
13547
|
+
}
|
|
13548
|
+
throw new Error(`no runbook "${slug}" in ${ctx.appId}`);
|
|
13491
13549
|
}
|
|
13492
13550
|
function readBody(file, inline) {
|
|
13493
13551
|
if (inline !== void 0) return inline;
|
|
13494
13552
|
if (file === void 0) throw new Error("supply the new text with --file <path>, --file - (stdin), or --body");
|
|
13495
|
-
return (0,
|
|
13553
|
+
return (0, import_node_fs17.readFileSync)(file === "-" ? 0 : file, "utf8");
|
|
13496
13554
|
}
|
|
13497
13555
|
var stamp = (ms) => ms ? new Date(ms).toISOString().slice(0, 16).replace("T", " ") : "";
|
|
13498
13556
|
async function runbookList(ctx, all, query) {
|
|
@@ -13572,7 +13630,7 @@ async function runbookRevert(ctx, slug, version) {
|
|
|
13572
13630
|
ctx,
|
|
13573
13631
|
"POST",
|
|
13574
13632
|
`/runbook/${encodeURIComponent(runbook.id)}/revert`,
|
|
13575
|
-
{ version }
|
|
13633
|
+
{ version, expectedVersion: runbook.version }
|
|
13576
13634
|
);
|
|
13577
13635
|
if (ctx.json) return ctx.out.log(JSON.stringify(result, null, 2));
|
|
13578
13636
|
ctx.out.log(`${slug} reverted to v${version}, now v${result.record?.version ?? runbook.version + 1}`);
|
|
@@ -13584,7 +13642,7 @@ async function runbookRemove(ctx, slug) {
|
|
|
13584
13642
|
}
|
|
13585
13643
|
|
|
13586
13644
|
// src/runbook-import.ts
|
|
13587
|
-
var
|
|
13645
|
+
var import_node_fs18 = require("fs");
|
|
13588
13646
|
var import_node_path16 = require("path");
|
|
13589
13647
|
function parseRunbook(text3, slug) {
|
|
13590
13648
|
let rest = text3;
|
|
@@ -13610,12 +13668,12 @@ function parseRunbook(text3, slug) {
|
|
|
13610
13668
|
};
|
|
13611
13669
|
}
|
|
13612
13670
|
function readRunbookDir(dir) {
|
|
13613
|
-
if (!(0,
|
|
13614
|
-
const files = (0,
|
|
13671
|
+
if (!(0, import_node_fs18.statSync)(dir, { throwIfNoEntry: false })?.isDirectory()) throw new Error(`not a directory: ${dir}`);
|
|
13672
|
+
const files = (0, import_node_fs18.readdirSync)(dir).filter((f) => f.endsWith(".md")).sort();
|
|
13615
13673
|
if (!files.length) throw new Error(`no .md files in ${dir}`);
|
|
13616
13674
|
return files.map((file) => {
|
|
13617
13675
|
const slug = (0, import_node_path16.basename)(file, ".md");
|
|
13618
|
-
const parsed = parseRunbook((0,
|
|
13676
|
+
const parsed = parseRunbook((0, import_node_fs18.readFileSync)((0, import_node_path16.join)(dir, file), "utf8"), slug);
|
|
13619
13677
|
return { file, slug, ...parsed, words: parsed.body.split(/\s+/).filter(Boolean).length };
|
|
13620
13678
|
});
|
|
13621
13679
|
}
|
|
@@ -13688,7 +13746,7 @@ async function upsert(ctx, r, visibility) {
|
|
|
13688
13746
|
|
|
13689
13747
|
// src/runbook-impact.ts
|
|
13690
13748
|
var import_node_child_process6 = require("child_process");
|
|
13691
|
-
var
|
|
13749
|
+
var import_node_fs19 = require("fs");
|
|
13692
13750
|
var import_node_path17 = require("path");
|
|
13693
13751
|
|
|
13694
13752
|
// src/runbook-impact-scan.ts
|
|
@@ -13859,9 +13917,9 @@ ${body.split("\n").map((line2) => `+${line2}`).join("\n")}
|
|
|
13859
13917
|
function manifestLabeller(root) {
|
|
13860
13918
|
return (workspace) => {
|
|
13861
13919
|
const manifest = (0, import_node_path17.join)(root, workspace, "package.json");
|
|
13862
|
-
if (!(0,
|
|
13920
|
+
if (!(0, import_node_fs19.existsSync)(manifest)) return void 0;
|
|
13863
13921
|
try {
|
|
13864
|
-
const name = JSON.parse((0,
|
|
13922
|
+
const name = JSON.parse((0, import_node_fs19.readFileSync)(manifest, "utf8")).name;
|
|
13865
13923
|
return typeof name === "string" ? name : void 0;
|
|
13866
13924
|
} catch {
|
|
13867
13925
|
return void 0;
|
|
@@ -13928,7 +13986,7 @@ function report4(ctx, impacts) {
|
|
|
13928
13986
|
async function runbookImpact(ctx, options, deps = {}) {
|
|
13929
13987
|
const cwd = deps.cwd ?? process.cwd();
|
|
13930
13988
|
const runGit = deps.runGit ?? gitRunner(cwd);
|
|
13931
|
-
const read3 = deps.readRepoFile ?? ((path) => (0,
|
|
13989
|
+
const read3 = deps.readRepoFile ?? ((path) => (0, import_node_fs19.readFileSync)((0, import_node_path17.join)(cwd, path), "utf8"));
|
|
13932
13990
|
const surfaces = changedSurfaces(collectDiff(runGit, options.base, read3), manifestLabeller(cwd));
|
|
13933
13991
|
if (!surfaces.length) {
|
|
13934
13992
|
return ctx.out.log(
|
|
@@ -14061,7 +14119,7 @@ async function runbookComment(ctx, slug, body) {
|
|
|
14061
14119
|
|
|
14062
14120
|
// src/runbook-editor.ts
|
|
14063
14121
|
var import_node_child_process7 = require("child_process");
|
|
14064
|
-
var
|
|
14122
|
+
var import_node_fs20 = require("fs");
|
|
14065
14123
|
var import_node_os4 = require("os");
|
|
14066
14124
|
var import_node_path18 = require("path");
|
|
14067
14125
|
var import_node_process14 = __toESM(require("process"), 1);
|
|
@@ -14089,16 +14147,16 @@ function editText(initial, slug, deps = {}) {
|
|
|
14089
14147
|
);
|
|
14090
14148
|
if (!interactive())
|
|
14091
14149
|
throw new Error(`cannot open an editor without a terminal \u2014 pass --file <path> or --body "\u2026" instead`);
|
|
14092
|
-
const dir = (0,
|
|
14150
|
+
const dir = (0, import_node_fs20.mkdtempSync)((0, import_node_path18.join)((0, import_node_os4.tmpdir)(), "odla-runbook-"));
|
|
14093
14151
|
const file = (0, import_node_path18.join)(dir, `${slug}.md`);
|
|
14094
14152
|
try {
|
|
14095
|
-
(0,
|
|
14153
|
+
(0, import_node_fs20.writeFileSync)(file, initial, { mode: 384 });
|
|
14096
14154
|
const code = defaultRunOrInjected(deps)(editor, file);
|
|
14097
14155
|
if (code !== 0) throw new Error(`editor "${editor}" exited with ${code}; nothing was written`);
|
|
14098
|
-
const edited = (0,
|
|
14156
|
+
const edited = (0, import_node_fs20.readFileSync)(file, "utf8");
|
|
14099
14157
|
return edited === initial ? null : edited;
|
|
14100
14158
|
} finally {
|
|
14101
|
-
(0,
|
|
14159
|
+
(0, import_node_fs20.rmSync)(dir, { recursive: true, force: true });
|
|
14102
14160
|
}
|
|
14103
14161
|
}
|
|
14104
14162
|
var defaultRunOrInjected = (deps) => deps.run ?? defaultRun;
|
|
@@ -14990,6 +15048,23 @@ function exitCodeFor(err) {
|
|
|
14990
15048
|
|
|
14991
15049
|
// src/cli.ts
|
|
14992
15050
|
async function runCli(argv = process.argv.slice(2), dependencies = {}) {
|
|
15051
|
+
const out = redactingOutput(dependencies.stdout ?? console);
|
|
15052
|
+
const advisories = [];
|
|
15053
|
+
const withAdvisoryReader = {
|
|
15054
|
+
...dependencies,
|
|
15055
|
+
fetch: advisoryCollectingFetch(dependencies.fetch ?? fetch, advisories)
|
|
15056
|
+
};
|
|
15057
|
+
try {
|
|
15058
|
+
return await dispatchCli(argv, withAdvisoryReader);
|
|
15059
|
+
} catch (error) {
|
|
15060
|
+
const explanation = explainRejectedCredential(error);
|
|
15061
|
+
if (explanation) out.error(explanation);
|
|
15062
|
+
throw error;
|
|
15063
|
+
} finally {
|
|
15064
|
+
renderAdvisories(out, advisories);
|
|
15065
|
+
}
|
|
15066
|
+
}
|
|
15067
|
+
async function dispatchCli(argv, dependencies) {
|
|
14993
15068
|
const runtime = {
|
|
14994
15069
|
...dependencies,
|
|
14995
15070
|
stdout: redactingOutput(dependencies.stdout ?? console)
|