@odla-ai/cli 0.43.1 → 0.45.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 +671 -552
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +12 -14
- package/dist/bin.js.map +1 -1
- package/dist/chunk-5MEO3BVF.js +282 -0
- package/dist/chunk-5MEO3BVF.js.map +1 -0
- package/dist/{chunk-T4OPSRME.js → chunk-JHB6352A.js} +429 -471
- package/dist/chunk-JHB6352A.js.map +1 -0
- package/dist/cli-2FTL245Y.js +12 -0
- package/dist/index.cjs +341 -256
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-T4OPSRME.js.map +0 -1
- package/dist/chunk-UKLSRQ5J.js +0 -129
- package/dist/chunk-UKLSRQ5J.js.map +0 -1
- package/dist/cli-3JOB4OUV.js +0 -12
- /package/dist/{cli-3JOB4OUV.js.map → cli-2FTL245Y.js.map} +0 -0
package/dist/bin.cjs
CHANGED
|
@@ -99,17 +99,173 @@ var init_runbook_requires = __esm({
|
|
|
99
99
|
}
|
|
100
100
|
});
|
|
101
101
|
|
|
102
|
+
// src/odla-home.ts
|
|
103
|
+
function odlaHome(env = import_node_process.default.env) {
|
|
104
|
+
if (env.VITEST && !env.ODLA_HOME) {
|
|
105
|
+
throw new Error(
|
|
106
|
+
"ODLA_HOME must be set under test \u2014 resolving the real ~/.odla would write to the developer's machine"
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
return env.ODLA_HOME ?? (0, import_node_path.join)(env.HOME ?? (0, import_node_os.homedir)(), ".odla");
|
|
110
|
+
}
|
|
111
|
+
function odlaHomePath(segments, env = import_node_process.default.env) {
|
|
112
|
+
return (0, import_node_path.join)(odlaHome(env), ...segments);
|
|
113
|
+
}
|
|
114
|
+
function identityFile(env) {
|
|
115
|
+
return odlaHomePath(["identity.json"], env);
|
|
116
|
+
}
|
|
117
|
+
function deviceSessionFile(env) {
|
|
118
|
+
return odlaHomePath(["session.json"], env);
|
|
119
|
+
}
|
|
120
|
+
function appTokenFile(appId, env) {
|
|
121
|
+
return odlaHomePath(["apps", safeSegment(appId), "dev-token.json"], env);
|
|
122
|
+
}
|
|
123
|
+
function appCredentialsFile(appId, env) {
|
|
124
|
+
return odlaHomePath(["apps", safeSegment(appId), "credentials.json"], env);
|
|
125
|
+
}
|
|
126
|
+
function scopedTokenFile(env) {
|
|
127
|
+
return odlaHomePath(["admin-token.local.json"], env);
|
|
128
|
+
}
|
|
129
|
+
function pmContextFile(env) {
|
|
130
|
+
return odlaHomePath(["pm-context.json"], env);
|
|
131
|
+
}
|
|
132
|
+
function adoptRepoLocalCache(legacyPath, machinePath, out) {
|
|
133
|
+
if (!(0, import_node_fs.existsSync)(legacyPath) || legacyPath === machinePath) return false;
|
|
134
|
+
const superseded2 = (0, import_node_fs.existsSync)(machinePath);
|
|
135
|
+
if (!superseded2) {
|
|
136
|
+
(0, import_node_fs.mkdirSync)((0, import_node_path.dirname)(machinePath), { recursive: true });
|
|
137
|
+
(0, import_node_fs.copyFileSync)(legacyPath, machinePath);
|
|
138
|
+
(0, import_node_fs.chmodSync)(machinePath, 384);
|
|
139
|
+
}
|
|
140
|
+
(0, import_node_fs.rmSync)(legacyPath, { force: true });
|
|
141
|
+
out?.error(
|
|
142
|
+
superseded2 ? `auth: removed superseded ${legacyPath}; this machine's credentials live in ${odlaHome()}` : `auth: moved ${legacyPath} into ${machinePath}; credentials are per machine now, not per worktree`
|
|
143
|
+
);
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
function safeSegment(value2) {
|
|
147
|
+
const clean4 = value2.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/^-+|-+$/g, "");
|
|
148
|
+
if (!clean4) throw new Error(`"${value2}" is not a usable app id`);
|
|
149
|
+
return clean4;
|
|
150
|
+
}
|
|
151
|
+
var import_node_fs, import_node_os, import_node_path, import_node_process;
|
|
152
|
+
var init_odla_home = __esm({
|
|
153
|
+
"src/odla-home.ts"() {
|
|
154
|
+
"use strict";
|
|
155
|
+
init_cjs_shims();
|
|
156
|
+
import_node_fs = require("fs");
|
|
157
|
+
import_node_os = require("os");
|
|
158
|
+
import_node_path = require("path");
|
|
159
|
+
import_node_process = __toESM(require("process"), 1);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
|
|
102
163
|
// src/version.ts
|
|
103
164
|
function cliVersion() {
|
|
104
|
-
const pkg = JSON.parse((0,
|
|
165
|
+
const pkg = JSON.parse((0, import_node_fs2.readFileSync)(new URL("../package.json", importMetaUrl), "utf8"));
|
|
105
166
|
return pkg.version ?? "unknown";
|
|
106
167
|
}
|
|
107
|
-
var
|
|
168
|
+
var import_node_fs2;
|
|
108
169
|
var init_version = __esm({
|
|
109
170
|
"src/version.ts"() {
|
|
110
171
|
"use strict";
|
|
111
172
|
init_cjs_shims();
|
|
112
|
-
|
|
173
|
+
import_node_fs2 = require("fs");
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// src/update-notice.ts
|
|
178
|
+
function updateCacheFile(env) {
|
|
179
|
+
return odlaHomePath(["cli-update.json"], env);
|
|
180
|
+
}
|
|
181
|
+
function readUpdateCache(path) {
|
|
182
|
+
try {
|
|
183
|
+
const parsed = JSON.parse((0, import_node_fs3.readFileSync)(path, "utf8"));
|
|
184
|
+
if (typeof parsed.latest !== "string" || !VERSION.test(parsed.latest)) return null;
|
|
185
|
+
if (typeof parsed.checkedAt !== "number") return null;
|
|
186
|
+
return { latest: parsed.latest, checkedAt: parsed.checkedAt };
|
|
187
|
+
} catch {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
function writeUpdateCache(path, cache2) {
|
|
192
|
+
(0, import_node_fs3.mkdirSync)((0, import_node_path2.dirname)(path), { recursive: true });
|
|
193
|
+
(0, import_node_fs3.writeFileSync)(path, JSON.stringify(cache2));
|
|
194
|
+
}
|
|
195
|
+
function updateNotice(options = {}) {
|
|
196
|
+
const env = options.env ?? import_node_process2.default.env;
|
|
197
|
+
if (env.ODLA_CLI_UPDATE_CHECK === "0") return null;
|
|
198
|
+
const current = options.currentVersion ?? cliVersion();
|
|
199
|
+
if (!VERSION.test(current)) return null;
|
|
200
|
+
const path = updateCacheFile(env);
|
|
201
|
+
const cache2 = readUpdateCache(path);
|
|
202
|
+
const now = options.now ?? Date.now();
|
|
203
|
+
if ((!cache2 || now - cache2.checkedAt > INTERVAL_MS) && !refreshScheduled) {
|
|
204
|
+
refreshScheduled = true;
|
|
205
|
+
(options.refresh ?? spawnRefresh)(path, env.ODLA_CLI_REGISTRY_URL ?? REGISTRY_URL);
|
|
206
|
+
}
|
|
207
|
+
if (!cache2 || compareVersions(current, cache2.latest) >= 0) return null;
|
|
208
|
+
return renderNotice(current, cache2.latest, options.entryPath ?? import_node_process2.default.argv[1]);
|
|
209
|
+
}
|
|
210
|
+
function renderNotice(current, latest, entryPath) {
|
|
211
|
+
const resolved = resolvedEntryPath(entryPath);
|
|
212
|
+
const behindMajor = Number(latest.split(".")[0]) > Number(current.split(".")[0]);
|
|
213
|
+
const repair = isWorkspaceCli(resolved) ? `this is the workspace build at ${resolved} \u2014 rebase that worktree and rebuild it` : resolved.includes("/_npx/") ? `run npx --yes @odla-ai/cli@${latest} <command>` : `run npm i @odla-ai/cli@${latest}`;
|
|
214
|
+
const severity = behindMajor ? "a MAJOR version behind, so commands and flags this version has may no longer exist" : "behind";
|
|
215
|
+
return `odla-ai: ${current} is ${severity}; npm serves ${latest}. To update, ${repair}.`;
|
|
216
|
+
}
|
|
217
|
+
function spawnRefresh(cachePath, registryUrl) {
|
|
218
|
+
const script = `
|
|
219
|
+
const {mkdirSync,writeFileSync}=require("node:fs");
|
|
220
|
+
const {dirname}=require("node:path");
|
|
221
|
+
const [path,url]=process.argv.slice(1);
|
|
222
|
+
const done=setTimeout(()=>process.exit(0),5000); done.unref();
|
|
223
|
+
fetch(url,{headers:{accept:"application/vnd.npm.install-v1+json"}})
|
|
224
|
+
.then(r=>r.ok?r.json():null)
|
|
225
|
+
.then(b=>{
|
|
226
|
+
const v=b&&b.version;
|
|
227
|
+
if (typeof v!=="string"||!/^\\d+\\.\\d+\\.\\d+/.test(v)) return;
|
|
228
|
+
mkdirSync(dirname(path),{recursive:true});
|
|
229
|
+
writeFileSync(path,JSON.stringify({latest:v,checkedAt:Date.now()}));
|
|
230
|
+
})
|
|
231
|
+
.catch(()=>{});
|
|
232
|
+
`;
|
|
233
|
+
try {
|
|
234
|
+
(0, import_node_child_process.spawn)(import_node_process2.default.execPath, ["-e", script, cachePath, registryUrl], {
|
|
235
|
+
detached: true,
|
|
236
|
+
stdio: "ignore"
|
|
237
|
+
}).unref();
|
|
238
|
+
} catch {
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
function resolvedEntryPath(entryPath) {
|
|
242
|
+
if (!entryPath) return "unknown executable";
|
|
243
|
+
try {
|
|
244
|
+
return (0, import_node_fs3.realpathSync)(entryPath);
|
|
245
|
+
} catch {
|
|
246
|
+
return entryPath;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
function isWorkspaceCli(entryPath) {
|
|
250
|
+
const normalized = entryPath.replaceAll("\\", "/");
|
|
251
|
+
return /\/packages\/cli\/(dist|bin)\//.test(normalized) && !normalized.includes("/node_modules/");
|
|
252
|
+
}
|
|
253
|
+
var import_node_child_process, import_node_fs3, import_node_path2, import_node_process2, REGISTRY_URL, INTERVAL_MS, VERSION, refreshScheduled;
|
|
254
|
+
var init_update_notice = __esm({
|
|
255
|
+
"src/update-notice.ts"() {
|
|
256
|
+
"use strict";
|
|
257
|
+
init_cjs_shims();
|
|
258
|
+
import_node_child_process = require("child_process");
|
|
259
|
+
import_node_fs3 = require("fs");
|
|
260
|
+
import_node_path2 = require("path");
|
|
261
|
+
import_node_process2 = __toESM(require("process"), 1);
|
|
262
|
+
init_odla_home();
|
|
263
|
+
init_runbook_requires();
|
|
264
|
+
init_version();
|
|
265
|
+
REGISTRY_URL = "https://registry.npmjs.org/@odla-ai%2fcli/latest";
|
|
266
|
+
INTERVAL_MS = 3 * 60 * 60 * 1e3;
|
|
267
|
+
VERSION = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
|
|
268
|
+
refreshScheduled = false;
|
|
113
269
|
}
|
|
114
270
|
});
|
|
115
271
|
|
|
@@ -232,8 +388,8 @@ var init_approval_prompt = __esm({
|
|
|
232
388
|
|
|
233
389
|
// src/open.ts
|
|
234
390
|
async function openUrl(url, options = {}) {
|
|
235
|
-
const command = openerFor(options.platform ??
|
|
236
|
-
const doSpawn = options.spawnImpl ??
|
|
391
|
+
const command = openerFor(options.platform ?? import_node_process3.default.platform);
|
|
392
|
+
const doSpawn = options.spawnImpl ?? import_node_child_process2.spawn;
|
|
237
393
|
await new Promise((resolve15, reject) => {
|
|
238
394
|
const child = doSpawn(command.cmd, [...command.args, url], {
|
|
239
395
|
stdio: "ignore",
|
|
@@ -251,13 +407,13 @@ function openerFor(platform) {
|
|
|
251
407
|
if (platform === "win32") return { cmd: "cmd", args: ["/c", "start", ""] };
|
|
252
408
|
return { cmd: "xdg-open", args: [] };
|
|
253
409
|
}
|
|
254
|
-
var
|
|
410
|
+
var import_node_child_process2, import_node_process3;
|
|
255
411
|
var init_open = __esm({
|
|
256
412
|
"src/open.ts"() {
|
|
257
413
|
"use strict";
|
|
258
414
|
init_cjs_shims();
|
|
259
|
-
|
|
260
|
-
|
|
415
|
+
import_node_child_process2 = require("child_process");
|
|
416
|
+
import_node_process3 = __toESM(require("process"), 1);
|
|
261
417
|
}
|
|
262
418
|
});
|
|
263
419
|
|
|
@@ -265,7 +421,7 @@ var init_open = __esm({
|
|
|
265
421
|
function approvalBrowser(options, host = {}) {
|
|
266
422
|
if (options.open === false) return { open: false, reason: "disabled by --no-open" };
|
|
267
423
|
if (options.open === true) return { open: true, mode: "forced" };
|
|
268
|
-
const env = host.env ??
|
|
424
|
+
const env = host.env ?? import_node_process4.default.env;
|
|
269
425
|
if (env.VITEST || env.NODE_ENV === "test") {
|
|
270
426
|
return { open: false, reason: "test environment" };
|
|
271
427
|
}
|
|
@@ -295,12 +451,12 @@ function handshakeUrl(platformUrl, userCode) {
|
|
|
295
451
|
url.searchParams.set("code", userCode);
|
|
296
452
|
return url.toString();
|
|
297
453
|
}
|
|
298
|
-
var
|
|
454
|
+
var import_node_process4;
|
|
299
455
|
var init_handshake_approval = __esm({
|
|
300
456
|
"src/handshake-approval.ts"() {
|
|
301
457
|
"use strict";
|
|
302
458
|
init_cjs_shims();
|
|
303
|
-
|
|
459
|
+
import_node_process4 = __toESM(require("process"), 1);
|
|
304
460
|
init_approval_prompt();
|
|
305
461
|
init_open();
|
|
306
462
|
}
|
|
@@ -308,10 +464,10 @@ var init_handshake_approval = __esm({
|
|
|
308
464
|
|
|
309
465
|
// src/handshake-state.ts
|
|
310
466
|
function handshakeFile(cfg) {
|
|
311
|
-
return (0,
|
|
467
|
+
return (0, import_node_path4.join)((0, import_node_path4.dirname)(cfg.local.tokenFile), "handshake.local.json");
|
|
312
468
|
}
|
|
313
469
|
function clearPendingHandshake(path) {
|
|
314
|
-
(0,
|
|
470
|
+
(0, import_node_fs5.rmSync)(path, { force: true });
|
|
315
471
|
}
|
|
316
472
|
function minutesLeft(expiresAt) {
|
|
317
473
|
return Math.max(1, Math.round((expiresAt - Date.now()) / 6e4));
|
|
@@ -331,31 +487,31 @@ function approvalReminder(out, pending, periodMs = 3e4) {
|
|
|
331
487
|
timer.unref?.();
|
|
332
488
|
return () => clearInterval(timer);
|
|
333
489
|
}
|
|
334
|
-
function handshakeWaitMs(waitSeconds, interactive =
|
|
490
|
+
function handshakeWaitMs(waitSeconds, interactive = import_node_process5.default.stdout.isTTY === true) {
|
|
335
491
|
if (waitSeconds !== void 0) return waitSeconds * 1e3;
|
|
336
492
|
return interactive ? void 0 : 9e4;
|
|
337
493
|
}
|
|
338
|
-
var
|
|
494
|
+
var import_node_fs5, import_node_path4, import_node_process5;
|
|
339
495
|
var init_handshake_state = __esm({
|
|
340
496
|
"src/handshake-state.ts"() {
|
|
341
497
|
"use strict";
|
|
342
498
|
init_cjs_shims();
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
499
|
+
import_node_fs5 = require("fs");
|
|
500
|
+
import_node_path4 = require("path");
|
|
501
|
+
import_node_process5 = __toESM(require("process"), 1);
|
|
346
502
|
init_approval_prompt();
|
|
347
503
|
}
|
|
348
504
|
});
|
|
349
505
|
|
|
350
506
|
// src/device-session.ts
|
|
351
|
-
function deviceCredentialPath(env =
|
|
352
|
-
return env.ODLA_DEVICE_CREDENTIAL ?? (0,
|
|
507
|
+
function deviceCredentialPath(env = import_node_process6.default.env) {
|
|
508
|
+
return env.ODLA_DEVICE_CREDENTIAL ?? (0, import_node_path5.join)(env.HOME ?? (0, import_node_os2.homedir)(), ".odla", "device.json");
|
|
353
509
|
}
|
|
354
|
-
function readDeviceCredential(platform, env =
|
|
510
|
+
function readDeviceCredential(platform, env = import_node_process6.default.env) {
|
|
355
511
|
const path = deviceCredentialPath(env);
|
|
356
|
-
if (!(0,
|
|
512
|
+
if (!(0, import_node_fs6.existsSync)(path)) return null;
|
|
357
513
|
try {
|
|
358
|
-
const parsed = JSON.parse((0,
|
|
514
|
+
const parsed = JSON.parse((0, import_node_fs6.readFileSync)(path, "utf8"));
|
|
359
515
|
if (typeof parsed.token !== "string" || !parsed.token.startsWith("odla_device_")) return null;
|
|
360
516
|
if (parsed.platform !== platform) return null;
|
|
361
517
|
return { ...parsed, token: parsed.token, platform: parsed.platform };
|
|
@@ -389,76 +545,15 @@ async function mintDeviceSession(platformUrl, credential2, doFetch) {
|
|
|
389
545
|
...Array.isArray(body.scopes) ? { scopes: body.scopes } : {}
|
|
390
546
|
};
|
|
391
547
|
}
|
|
392
|
-
var
|
|
548
|
+
var import_node_fs6, import_node_os2, import_node_path5, import_node_process6;
|
|
393
549
|
var init_device_session = __esm({
|
|
394
550
|
"src/device-session.ts"() {
|
|
395
|
-
"use strict";
|
|
396
|
-
init_cjs_shims();
|
|
397
|
-
import_node_fs5 = require("fs");
|
|
398
|
-
import_node_os = require("os");
|
|
399
|
-
import_node_path3 = require("path");
|
|
400
|
-
import_node_process4 = __toESM(require("process"), 1);
|
|
401
|
-
}
|
|
402
|
-
});
|
|
403
|
-
|
|
404
|
-
// src/odla-home.ts
|
|
405
|
-
function odlaHome(env = import_node_process5.default.env) {
|
|
406
|
-
if (env.VITEST && !env.ODLA_HOME) {
|
|
407
|
-
throw new Error(
|
|
408
|
-
"ODLA_HOME must be set under test \u2014 resolving the real ~/.odla would write to the developer's machine"
|
|
409
|
-
);
|
|
410
|
-
}
|
|
411
|
-
return env.ODLA_HOME ?? (0, import_node_path4.join)(env.HOME ?? (0, import_node_os2.homedir)(), ".odla");
|
|
412
|
-
}
|
|
413
|
-
function odlaHomePath(segments, env = import_node_process5.default.env) {
|
|
414
|
-
return (0, import_node_path4.join)(odlaHome(env), ...segments);
|
|
415
|
-
}
|
|
416
|
-
function identityFile(env) {
|
|
417
|
-
return odlaHomePath(["identity.json"], env);
|
|
418
|
-
}
|
|
419
|
-
function deviceSessionFile(env) {
|
|
420
|
-
return odlaHomePath(["session.json"], env);
|
|
421
|
-
}
|
|
422
|
-
function appTokenFile(appId, env) {
|
|
423
|
-
return odlaHomePath(["apps", safeSegment(appId), "dev-token.json"], env);
|
|
424
|
-
}
|
|
425
|
-
function appCredentialsFile(appId, env) {
|
|
426
|
-
return odlaHomePath(["apps", safeSegment(appId), "credentials.json"], env);
|
|
427
|
-
}
|
|
428
|
-
function scopedTokenFile(env) {
|
|
429
|
-
return odlaHomePath(["admin-token.local.json"], env);
|
|
430
|
-
}
|
|
431
|
-
function pmContextFile(env) {
|
|
432
|
-
return odlaHomePath(["pm-context.json"], env);
|
|
433
|
-
}
|
|
434
|
-
function adoptRepoLocalCache(legacyPath, machinePath, out) {
|
|
435
|
-
if (!(0, import_node_fs6.existsSync)(legacyPath) || legacyPath === machinePath) return false;
|
|
436
|
-
const superseded2 = (0, import_node_fs6.existsSync)(machinePath);
|
|
437
|
-
if (!superseded2) {
|
|
438
|
-
(0, import_node_fs6.mkdirSync)((0, import_node_path4.dirname)(machinePath), { recursive: true });
|
|
439
|
-
(0, import_node_fs6.copyFileSync)(legacyPath, machinePath);
|
|
440
|
-
(0, import_node_fs6.chmodSync)(machinePath, 384);
|
|
441
|
-
}
|
|
442
|
-
(0, import_node_fs6.rmSync)(legacyPath, { force: true });
|
|
443
|
-
out?.error(
|
|
444
|
-
superseded2 ? `auth: removed superseded ${legacyPath}; this machine's credentials live in ${odlaHome()}` : `auth: moved ${legacyPath} into ${machinePath}; credentials are per machine now, not per worktree`
|
|
445
|
-
);
|
|
446
|
-
return true;
|
|
447
|
-
}
|
|
448
|
-
function safeSegment(value2) {
|
|
449
|
-
const clean4 = value2.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/^-+|-+$/g, "");
|
|
450
|
-
if (!clean4) throw new Error(`"${value2}" is not a usable app id`);
|
|
451
|
-
return clean4;
|
|
452
|
-
}
|
|
453
|
-
var import_node_fs6, import_node_os2, import_node_path4, import_node_process5;
|
|
454
|
-
var init_odla_home = __esm({
|
|
455
|
-
"src/odla-home.ts"() {
|
|
456
551
|
"use strict";
|
|
457
552
|
init_cjs_shims();
|
|
458
553
|
import_node_fs6 = require("fs");
|
|
459
554
|
import_node_os2 = require("os");
|
|
460
|
-
|
|
461
|
-
|
|
555
|
+
import_node_path5 = require("path");
|
|
556
|
+
import_node_process6 = __toESM(require("process"), 1);
|
|
462
557
|
}
|
|
463
558
|
});
|
|
464
559
|
|
|
@@ -508,7 +603,7 @@ function mergeCredential(current, update) {
|
|
|
508
603
|
return next;
|
|
509
604
|
}
|
|
510
605
|
function ensureGitignore(rootDir, localPaths = []) {
|
|
511
|
-
const path = (0,
|
|
606
|
+
const path = (0, import_node_path6.resolve)(rootDir, ".gitignore");
|
|
512
607
|
const existing = (0, import_node_fs7.existsSync)(path) ? (0, import_node_fs7.readFileSync)(path, "utf8") : "";
|
|
513
608
|
const configured = localPaths.map((localPath) => gitignoreEntry(rootDir, localPath)).filter((line2) => !!line2);
|
|
514
609
|
const wanted = [.../* @__PURE__ */ new Set([...GITIGNORE_LINES, ...configured])];
|
|
@@ -529,7 +624,7 @@ function o11yDevVars(cfg) {
|
|
|
529
624
|
function resolveWriteDevVarsTarget(cfg, requested) {
|
|
530
625
|
if (!requested) return null;
|
|
531
626
|
if (requested === true) return cfg.local.devVarsFile;
|
|
532
|
-
return (0,
|
|
627
|
+
return (0, import_node_path6.resolve)((0, import_node_path6.dirname)(cfg.configPath), requested);
|
|
533
628
|
}
|
|
534
629
|
function writeDevVars(path, credentials, env, o11y) {
|
|
535
630
|
const entry = credentials.envs[env];
|
|
@@ -557,28 +652,28 @@ function isManagedDevVar(line2) {
|
|
|
557
652
|
return !!match?.[1] && MANAGED_DEV_VARS.has(match[1]);
|
|
558
653
|
}
|
|
559
654
|
function writePrivateText(path, text4) {
|
|
560
|
-
(0, import_node_fs7.mkdirSync)((0,
|
|
655
|
+
(0, import_node_fs7.mkdirSync)((0, import_node_path6.dirname)(path), { recursive: true });
|
|
561
656
|
const temporary = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
562
657
|
(0, import_node_fs7.writeFileSync)(temporary, text4, { mode: 384 });
|
|
563
658
|
(0, import_node_fs7.chmodSync)(temporary, 384);
|
|
564
659
|
(0, import_node_fs7.renameSync)(temporary, path);
|
|
565
660
|
}
|
|
566
661
|
function gitignoreEntry(rootDir, path) {
|
|
567
|
-
const rel = (0,
|
|
568
|
-
if (!rel || rel === ".." || rel.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) || (0,
|
|
662
|
+
const rel = (0, import_node_path6.relative)((0, import_node_path6.resolve)(rootDir), (0, import_node_path6.resolve)(path));
|
|
663
|
+
if (!rel || rel === ".." || rel.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) || (0, import_node_path6.isAbsolute)(rel)) return null;
|
|
569
664
|
return rel.replaceAll("\\", "/");
|
|
570
665
|
}
|
|
571
666
|
function displayPath(path, rootDir = process.cwd()) {
|
|
572
|
-
const rel = (0,
|
|
667
|
+
const rel = (0, import_node_path6.relative)(rootDir, path);
|
|
573
668
|
return rel && !rel.startsWith("..") ? rel : path;
|
|
574
669
|
}
|
|
575
|
-
var import_node_fs7,
|
|
670
|
+
var import_node_fs7, import_node_path6, GITIGNORE_LINES, MANAGED_DEV_VARS;
|
|
576
671
|
var init_local = __esm({
|
|
577
672
|
"src/local.ts"() {
|
|
578
673
|
"use strict";
|
|
579
674
|
init_cjs_shims();
|
|
580
675
|
import_node_fs7 = require("fs");
|
|
581
|
-
|
|
676
|
+
import_node_path6 = require("path");
|
|
582
677
|
GITIGNORE_LINES = [".odla/*.local.json", ".odla/dev-token.json", ".dev.vars"];
|
|
583
678
|
MANAGED_DEV_VARS = /* @__PURE__ */ new Set([
|
|
584
679
|
"ODLA_PLATFORM",
|
|
@@ -596,7 +691,7 @@ var init_local = __esm({
|
|
|
596
691
|
});
|
|
597
692
|
|
|
598
693
|
// src/auth-guidance.ts
|
|
599
|
-
function machineAuthState(audience, env =
|
|
694
|
+
function machineAuthState(audience, env = import_node_process7.default.env) {
|
|
600
695
|
const device = readDeviceCredential(audience, env);
|
|
601
696
|
if (!device) return { enrolled: false };
|
|
602
697
|
const session = readJsonFile(deviceSessionFile(env));
|
|
@@ -640,12 +735,12 @@ function lapseNotice(state2, now = Date.now()) {
|
|
|
640
735
|
if (days < 0) return "this machine's enrollment has lapsed; the next command will ask for approval";
|
|
641
736
|
return `idle for ${days} more day${days === 1 ? "" : "s"} before this machine needs approving again (using it resets the clock)`;
|
|
642
737
|
}
|
|
643
|
-
var
|
|
738
|
+
var import_node_process7, ENROL_EVERYTHING, ENROL_PLATFORM_WIDE;
|
|
644
739
|
var init_auth_guidance = __esm({
|
|
645
740
|
"src/auth-guidance.ts"() {
|
|
646
741
|
"use strict";
|
|
647
742
|
init_cjs_shims();
|
|
648
|
-
|
|
743
|
+
import_node_process7 = __toESM(require("process"), 1);
|
|
649
744
|
init_device_session();
|
|
650
745
|
init_odla_home();
|
|
651
746
|
init_local();
|
|
@@ -687,7 +782,7 @@ var init_cached_credential = __esm({
|
|
|
687
782
|
});
|
|
688
783
|
|
|
689
784
|
// src/device-session-cache.ts
|
|
690
|
-
async function deviceSessionToken(platformUrl, audience, credential2, doFetch, env =
|
|
785
|
+
async function deviceSessionToken(platformUrl, audience, credential2, doFetch, env = import_node_process8.default.env) {
|
|
691
786
|
const path = deviceSessionFile(env);
|
|
692
787
|
const cached = readJsonFile(path);
|
|
693
788
|
if (cached?.token && cached.platform === audience && cached.deviceId === credential2.deviceId && (cached.expiresAt ?? 0) > Date.now() + SKEW_MS) return cached;
|
|
@@ -700,12 +795,12 @@ async function deviceSessionToken(platformUrl, audience, credential2, doFetch, e
|
|
|
700
795
|
writePrivateJson(path, session);
|
|
701
796
|
return session;
|
|
702
797
|
}
|
|
703
|
-
var
|
|
798
|
+
var import_node_process8, SKEW_MS;
|
|
704
799
|
var init_device_session_cache = __esm({
|
|
705
800
|
"src/device-session-cache.ts"() {
|
|
706
801
|
"use strict";
|
|
707
802
|
init_cjs_shims();
|
|
708
|
-
|
|
803
|
+
import_node_process8 = __toESM(require("process"), 1);
|
|
709
804
|
init_odla_home();
|
|
710
805
|
init_local();
|
|
711
806
|
init_device_session();
|
|
@@ -714,23 +809,23 @@ var init_device_session_cache = __esm({
|
|
|
714
809
|
});
|
|
715
810
|
|
|
716
811
|
// src/machine-identity.ts
|
|
717
|
-
function readMachineIdentity(audience, env =
|
|
812
|
+
function readMachineIdentity(audience, env = import_node_process9.default.env) {
|
|
718
813
|
const stored = readJsonFile(identityFile(env));
|
|
719
814
|
if (!stored || typeof stored.email !== "string" || !stored.email) return null;
|
|
720
815
|
return stored.platform === audience ? { platform: audience, email: stored.email } : null;
|
|
721
816
|
}
|
|
722
|
-
function rememberMachineIdentity(audience, email, env =
|
|
817
|
+
function rememberMachineIdentity(audience, email, env = import_node_process9.default.env) {
|
|
723
818
|
if (!email) return;
|
|
724
819
|
const existing = readMachineIdentity(audience, env);
|
|
725
820
|
if (existing?.email === email) return;
|
|
726
821
|
writePrivateJson(identityFile(env), { platform: audience, email });
|
|
727
822
|
}
|
|
728
|
-
var
|
|
823
|
+
var import_node_process9;
|
|
729
824
|
var init_machine_identity = __esm({
|
|
730
825
|
"src/machine-identity.ts"() {
|
|
731
826
|
"use strict";
|
|
732
827
|
init_cjs_shims();
|
|
733
|
-
|
|
828
|
+
import_node_process9 = __toESM(require("process"), 1);
|
|
734
829
|
init_odla_home();
|
|
735
830
|
init_local();
|
|
736
831
|
}
|
|
@@ -744,14 +839,14 @@ async function getDeveloperToken(cfg, options, doFetch, out, grantRequest = {})
|
|
|
744
839
|
const cached = readJsonFile(cfg.local.tokenFile);
|
|
745
840
|
if (!grantRequest.forceReview && !grantRequest.freshLogin) {
|
|
746
841
|
if (options.token) return options.token;
|
|
747
|
-
if (
|
|
748
|
-
const declared =
|
|
842
|
+
if (import_node_process10.default.env.ODLA_DEV_TOKEN) {
|
|
843
|
+
const declared = import_node_process10.default.env.ODLA_DEV_TOKEN_AUDIENCE;
|
|
749
844
|
if (declared) {
|
|
750
845
|
if (platformAudience(declared) !== audience) throw new Error("ODLA_DEV_TOKEN_AUDIENCE does not match the configured platform");
|
|
751
846
|
} else if (audience !== "https://odla.ai") {
|
|
752
847
|
throw new Error("ODLA_DEV_TOKEN_AUDIENCE is required for a non-default platform");
|
|
753
848
|
}
|
|
754
|
-
return
|
|
849
|
+
return import_node_process10.default.env.ODLA_DEV_TOKEN;
|
|
755
850
|
}
|
|
756
851
|
const device = readDeviceCredential(audience);
|
|
757
852
|
if (device) {
|
|
@@ -866,7 +961,7 @@ function stillPending(pending, email) {
|
|
|
866
961
|
);
|
|
867
962
|
}
|
|
868
963
|
function handshakeEmail(value2, cached) {
|
|
869
|
-
const email = (value2 ??
|
|
964
|
+
const email = (value2 ?? import_node_process10.default.env.ODLA_USER_EMAIL ?? cached ?? "").trim().toLowerCase();
|
|
870
965
|
if (/@users\.noreply\.github\.com$/i.test(email)) {
|
|
871
966
|
throw new Error(
|
|
872
967
|
`"${email}" is a GitHub commit identity, not an odla account email; use --email <signed-in-odla-account> or ODLA_USER_EMAIL`
|
|
@@ -895,14 +990,14 @@ function platformAudience(value2) {
|
|
|
895
990
|
}
|
|
896
991
|
return url.origin;
|
|
897
992
|
}
|
|
898
|
-
var import_db, import_node_crypto,
|
|
993
|
+
var import_db, import_node_crypto, import_node_process10;
|
|
899
994
|
var init_token = __esm({
|
|
900
995
|
"src/token.ts"() {
|
|
901
996
|
"use strict";
|
|
902
997
|
init_cjs_shims();
|
|
903
998
|
import_db = require("@odla-ai/db");
|
|
904
999
|
import_node_crypto = require("crypto");
|
|
905
|
-
|
|
1000
|
+
import_node_process10 = __toESM(require("process"), 1);
|
|
906
1001
|
init_handshake_approval();
|
|
907
1002
|
init_handshake_state();
|
|
908
1003
|
init_cached_credential();
|
|
@@ -917,7 +1012,7 @@ var init_token = __esm({
|
|
|
917
1012
|
async function secretInputValue(options, kind = "credential") {
|
|
918
1013
|
if (options.fromEnv && options.stdin) throw new Error("choose exactly one of --from-env or --stdin");
|
|
919
1014
|
let value2;
|
|
920
|
-
if (options.fromEnv) value2 =
|
|
1015
|
+
if (options.fromEnv) value2 = import_node_process11.default.env[options.fromEnv];
|
|
921
1016
|
else if (options.stdin) value2 = await (options.readStdin ?? (() => readSecretStream(kind)))();
|
|
922
1017
|
else throw new Error(`${kind} input required: use --from-env <NAME> or --stdin; values are never accepted as arguments`);
|
|
923
1018
|
value2 = value2?.replace(/[\r\n]+$/, "");
|
|
@@ -925,7 +1020,7 @@ async function secretInputValue(options, kind = "credential") {
|
|
|
925
1020
|
if (new TextEncoder().encode(value2).byteLength > MAX_BYTES) throw new Error(`${kind} exceeds 64 KiB`);
|
|
926
1021
|
return value2;
|
|
927
1022
|
}
|
|
928
|
-
async function readSecretStream(kind, stream =
|
|
1023
|
+
async function readSecretStream(kind, stream = import_node_process11.default.stdin) {
|
|
929
1024
|
let value2 = "";
|
|
930
1025
|
for await (const chunk of stream) {
|
|
931
1026
|
value2 += String(chunk);
|
|
@@ -933,12 +1028,12 @@ async function readSecretStream(kind, stream = import_node_process10.default.std
|
|
|
933
1028
|
}
|
|
934
1029
|
return value2;
|
|
935
1030
|
}
|
|
936
|
-
var
|
|
1031
|
+
var import_node_process11, MAX_BYTES;
|
|
937
1032
|
var init_secret_input = __esm({
|
|
938
1033
|
"src/secret-input.ts"() {
|
|
939
1034
|
"use strict";
|
|
940
1035
|
init_cjs_shims();
|
|
941
|
-
|
|
1036
|
+
import_node_process11 = __toESM(require("process"), 1);
|
|
942
1037
|
MAX_BYTES = 64 * 1024;
|
|
943
1038
|
}
|
|
944
1039
|
});
|
|
@@ -950,7 +1045,7 @@ async function getScopedPlatformToken(options) {
|
|
|
950
1045
|
async function resolveAdminPlatformToken(options) {
|
|
951
1046
|
const audience = platformAudience(options.platform);
|
|
952
1047
|
if (options.token) return options.token;
|
|
953
|
-
const fromEnv =
|
|
1048
|
+
const fromEnv = import_node_process12.default.env.ODLA_ADMIN_TOKEN;
|
|
954
1049
|
if (fromEnv) return audienceBoundEnvToken(fromEnv, audience);
|
|
955
1050
|
return scopedToken(
|
|
956
1051
|
audience,
|
|
@@ -962,7 +1057,7 @@ async function resolveAdminPlatformToken(options) {
|
|
|
962
1057
|
}
|
|
963
1058
|
function audienceBoundEnvToken(token, platform) {
|
|
964
1059
|
const audience = platformAudience(platform);
|
|
965
|
-
const declared =
|
|
1060
|
+
const declared = import_node_process12.default.env.ODLA_ADMIN_TOKEN_AUDIENCE;
|
|
966
1061
|
if (declared) {
|
|
967
1062
|
if (platformAudience(declared) !== audience) throw new Error("ODLA_ADMIN_TOKEN_AUDIENCE does not match the configured platform");
|
|
968
1063
|
} else if (audience !== "https://odla.ai") {
|
|
@@ -972,9 +1067,9 @@ function audienceBoundEnvToken(token, platform) {
|
|
|
972
1067
|
}
|
|
973
1068
|
async function scopedToken(platform, scope, options, doFetch, out) {
|
|
974
1069
|
const audience = platformAudience(platform);
|
|
975
|
-
const rootDir = options.rootDir ??
|
|
1070
|
+
const rootDir = options.rootDir ?? import_node_process12.default.cwd();
|
|
976
1071
|
const tokenFile = options.tokenFile ?? scopedTokenFile();
|
|
977
|
-
adoptRepoLocalCache((0,
|
|
1072
|
+
adoptRepoLocalCache((0, import_node_path7.join)(rootDir, ".odla/admin-token.local.json"), tokenFile, out);
|
|
978
1073
|
const device = readDeviceCredential(audience);
|
|
979
1074
|
if (device && options.cache !== false) {
|
|
980
1075
|
const session = await deviceSessionToken(platform, audience, device, doFetch);
|
|
@@ -1021,13 +1116,13 @@ async function scopedToken(platform, scope, options, doFetch, out) {
|
|
|
1021
1116
|
}
|
|
1022
1117
|
return token;
|
|
1023
1118
|
}
|
|
1024
|
-
var
|
|
1119
|
+
var import_node_path7, import_node_process12, import_db2, SCOPE_PURPOSE;
|
|
1025
1120
|
var init_admin_ai_auth = __esm({
|
|
1026
1121
|
"src/admin-ai-auth.ts"() {
|
|
1027
1122
|
"use strict";
|
|
1028
1123
|
init_cjs_shims();
|
|
1029
|
-
|
|
1030
|
-
|
|
1124
|
+
import_node_path7 = require("path");
|
|
1125
|
+
import_node_process12 = __toESM(require("process"), 1);
|
|
1031
1126
|
import_db2 = require("@odla-ai/db");
|
|
1032
1127
|
init_local();
|
|
1033
1128
|
init_handshake_approval();
|
|
@@ -1252,7 +1347,7 @@ var init_admin_ai_usage = __esm({
|
|
|
1252
1347
|
|
|
1253
1348
|
// src/admin-ai.ts
|
|
1254
1349
|
async function adminAi(options) {
|
|
1255
|
-
const platform = platformAudience(options.platform ??
|
|
1350
|
+
const platform = platformAudience(options.platform ?? import_node_process13.default.env.ODLA_PLATFORM ?? "https://odla.ai");
|
|
1256
1351
|
const doFetch = options.fetch ?? fetch;
|
|
1257
1352
|
const out = options.stdout ?? console;
|
|
1258
1353
|
const usageQuery = options.action === "usage" ? adminAiUsageQuery(options) : void 0;
|
|
@@ -1430,12 +1525,12 @@ function apiError3(action2, status, body) {
|
|
|
1430
1525
|
function isRecord3(value2) {
|
|
1431
1526
|
return Boolean(value2) && typeof value2 === "object" && !Array.isArray(value2);
|
|
1432
1527
|
}
|
|
1433
|
-
var
|
|
1528
|
+
var import_node_process13;
|
|
1434
1529
|
var init_admin_ai = __esm({
|
|
1435
1530
|
"src/admin-ai.ts"() {
|
|
1436
1531
|
"use strict";
|
|
1437
1532
|
init_cjs_shims();
|
|
1438
|
-
|
|
1533
|
+
import_node_process13 = __toESM(require("process"), 1);
|
|
1439
1534
|
init_token();
|
|
1440
1535
|
init_secret_input();
|
|
1441
1536
|
init_admin_ai_auth();
|
|
@@ -1480,10 +1575,17 @@ function parseArgv(argv2) {
|
|
|
1480
1575
|
function assertArgs(parsed, allowedOptions2, maxPositionals) {
|
|
1481
1576
|
const allowed = new Set(allowedOptions2);
|
|
1482
1577
|
for (const name of Object.keys(parsed.options)) {
|
|
1483
|
-
if (
|
|
1578
|
+
if (allowed.has(name)) continue;
|
|
1579
|
+
const accepts = [...allowed].sort().map((option) => `--${option}`).join(" ");
|
|
1580
|
+
throw new Error(
|
|
1581
|
+
`unknown option "--${name}"` + (accepts ? ` \u2014 this command accepts: ${accepts}` : " \u2014 this command takes no options")
|
|
1582
|
+
);
|
|
1484
1583
|
}
|
|
1485
1584
|
if (parsed.positionals.length > maxPositionals) {
|
|
1486
|
-
|
|
1585
|
+
const taken = parsed.positionals.slice(0, maxPositionals).join(" ");
|
|
1586
|
+
throw new Error(
|
|
1587
|
+
`unexpected argument "${parsed.positionals[maxPositionals]}" \u2014 ` + (maxPositionals ? `"odla-ai ${taken}" takes no further arguments` : "this command takes no arguments")
|
|
1588
|
+
);
|
|
1487
1589
|
}
|
|
1488
1590
|
}
|
|
1489
1591
|
function requiredString(value2, name) {
|
|
@@ -1527,6 +1629,196 @@ var init_argv = __esm({
|
|
|
1527
1629
|
}
|
|
1528
1630
|
});
|
|
1529
1631
|
|
|
1632
|
+
// src/surface.ts
|
|
1633
|
+
function acceptedAfter(path) {
|
|
1634
|
+
let node = COMMAND_SURFACE;
|
|
1635
|
+
for (const word of path) {
|
|
1636
|
+
node = node?.[word];
|
|
1637
|
+
if (!node) return [];
|
|
1638
|
+
}
|
|
1639
|
+
return Object.keys(node).sort();
|
|
1640
|
+
}
|
|
1641
|
+
function validateInvocation(words2) {
|
|
1642
|
+
let node = COMMAND_SURFACE;
|
|
1643
|
+
const walked = [];
|
|
1644
|
+
for (const word of words2) {
|
|
1645
|
+
if (Object.keys(node).length === 0) return null;
|
|
1646
|
+
const next = node[word];
|
|
1647
|
+
if (!next) return { validPrefix: walked.join(" "), word, accepted: Object.keys(node).sort() };
|
|
1648
|
+
walked.push(word);
|
|
1649
|
+
node = next;
|
|
1650
|
+
}
|
|
1651
|
+
return null;
|
|
1652
|
+
}
|
|
1653
|
+
function describeProblem(problem) {
|
|
1654
|
+
const where = problem.validPrefix ? `after "${problem.validPrefix}"` : "as a command";
|
|
1655
|
+
if (!problem.accepted.length) return `"${problem.word}" is not accepted ${where}. Run "odla-ai help"`;
|
|
1656
|
+
if (!problem.word) return `"odla-ai ${problem.validPrefix}" needs one of: ${problem.accepted.join(", ")}`;
|
|
1657
|
+
return `"${problem.word}" is not accepted ${where} \u2014 try: ${problem.accepted.join(", ")}`;
|
|
1658
|
+
}
|
|
1659
|
+
function rejectWord(path, word, note) {
|
|
1660
|
+
const sentence = describeProblem({
|
|
1661
|
+
validPrefix: path.join(" "),
|
|
1662
|
+
word: word ?? "",
|
|
1663
|
+
accepted: acceptedAfter(path)
|
|
1664
|
+
});
|
|
1665
|
+
throw new Error(note ? `${sentence}. ${note}` : sentence);
|
|
1666
|
+
}
|
|
1667
|
+
function invocationPath(words2) {
|
|
1668
|
+
let node = COMMAND_SURFACE;
|
|
1669
|
+
const path = [];
|
|
1670
|
+
for (const word of words2) {
|
|
1671
|
+
const next = node[word];
|
|
1672
|
+
if (!next) break;
|
|
1673
|
+
path.push(word);
|
|
1674
|
+
node = next;
|
|
1675
|
+
if (Object.keys(node).length === 0) break;
|
|
1676
|
+
}
|
|
1677
|
+
return path;
|
|
1678
|
+
}
|
|
1679
|
+
var PM_ACTIONS, PM_TASK_ACTIONS, PM_ENTITIES, COMMAND_SURFACE;
|
|
1680
|
+
var init_surface = __esm({
|
|
1681
|
+
"src/surface.ts"() {
|
|
1682
|
+
"use strict";
|
|
1683
|
+
init_cjs_shims();
|
|
1684
|
+
PM_ACTIONS = {
|
|
1685
|
+
list: {},
|
|
1686
|
+
add: {},
|
|
1687
|
+
create: {},
|
|
1688
|
+
get: {},
|
|
1689
|
+
set: {},
|
|
1690
|
+
update: {},
|
|
1691
|
+
status: {},
|
|
1692
|
+
move: {},
|
|
1693
|
+
done: {},
|
|
1694
|
+
comment: {},
|
|
1695
|
+
comments: {},
|
|
1696
|
+
history: {},
|
|
1697
|
+
link: {},
|
|
1698
|
+
ref: {},
|
|
1699
|
+
rm: {},
|
|
1700
|
+
delete: {}
|
|
1701
|
+
};
|
|
1702
|
+
PM_TASK_ACTIONS = {
|
|
1703
|
+
...PM_ACTIONS,
|
|
1704
|
+
ready: {},
|
|
1705
|
+
claim: {},
|
|
1706
|
+
release: {}
|
|
1707
|
+
};
|
|
1708
|
+
PM_ENTITIES = {
|
|
1709
|
+
...Object.fromEntries(
|
|
1710
|
+
["goal", "conformance", "decision", "bug"].map((entity) => [entity, PM_ACTIONS])
|
|
1711
|
+
),
|
|
1712
|
+
task: PM_TASK_ACTIONS,
|
|
1713
|
+
kanban: PM_TASK_ACTIONS
|
|
1714
|
+
};
|
|
1715
|
+
COMMAND_SURFACE = {
|
|
1716
|
+
agent: { jobs: {}, retry: {} },
|
|
1717
|
+
ai: { models: {} },
|
|
1718
|
+
admin: {
|
|
1719
|
+
ai: {
|
|
1720
|
+
show: {},
|
|
1721
|
+
set: {},
|
|
1722
|
+
credentials: {},
|
|
1723
|
+
models: {},
|
|
1724
|
+
usage: {},
|
|
1725
|
+
audit: {},
|
|
1726
|
+
credential: { set: {} }
|
|
1727
|
+
},
|
|
1728
|
+
spend: { show: {}, reset: {} }
|
|
1729
|
+
},
|
|
1730
|
+
app: {
|
|
1731
|
+
archive: {},
|
|
1732
|
+
restore: {},
|
|
1733
|
+
export: {},
|
|
1734
|
+
import: {},
|
|
1735
|
+
rename: {},
|
|
1736
|
+
"refresh-sandbox": {},
|
|
1737
|
+
"go-live": {},
|
|
1738
|
+
promote: {},
|
|
1739
|
+
owners: { list: {}, add: {}, remove: {} }
|
|
1740
|
+
},
|
|
1741
|
+
auth: { login: {} },
|
|
1742
|
+
brand: { design: { unpack: {} } },
|
|
1743
|
+
bug: { create: {}, list: {}, report: {} },
|
|
1744
|
+
calendar: { status: {}, calendars: {}, connect: {}, disconnect: {} },
|
|
1745
|
+
capabilities: {},
|
|
1746
|
+
code: {
|
|
1747
|
+
connect: {},
|
|
1748
|
+
grant: { request: {}, list: {}, approve: {}, revoke: {} },
|
|
1749
|
+
repository: { show: {}, list: {}, bind: {} }
|
|
1750
|
+
},
|
|
1751
|
+
config: { diff: {}, plan: {}, apply: {} },
|
|
1752
|
+
context: { show: {}, list: {}, save: {}, remove: {} },
|
|
1753
|
+
credentials: { list: {}, revoke: {} },
|
|
1754
|
+
device: { enroll: {}, list: {}, revoke: {} },
|
|
1755
|
+
// `watch`, `read`, `reply`, and `resolve` take a topic id from there on.
|
|
1756
|
+
discuss: {
|
|
1757
|
+
groups: {},
|
|
1758
|
+
list: {},
|
|
1759
|
+
topics: {},
|
|
1760
|
+
read: {},
|
|
1761
|
+
post: {},
|
|
1762
|
+
reply: {},
|
|
1763
|
+
resolve: {},
|
|
1764
|
+
who: {},
|
|
1765
|
+
watch: {}
|
|
1766
|
+
},
|
|
1767
|
+
doctor: {},
|
|
1768
|
+
help: {},
|
|
1769
|
+
init: {},
|
|
1770
|
+
monitor: { plan: {}, apply: {}, run: {}, status: {}, incidents: {}, report: {} },
|
|
1771
|
+
o11y: { status: {} },
|
|
1772
|
+
operations: { get: {}, wait: {} },
|
|
1773
|
+
platform: {
|
|
1774
|
+
status: {}
|
|
1775
|
+
},
|
|
1776
|
+
pm: {
|
|
1777
|
+
...PM_ENTITIES,
|
|
1778
|
+
project: { list: {}, add: {}, create: {}, use: {} },
|
|
1779
|
+
handoff: {},
|
|
1780
|
+
next: {},
|
|
1781
|
+
start: {},
|
|
1782
|
+
watch: {}
|
|
1783
|
+
},
|
|
1784
|
+
provision: {},
|
|
1785
|
+
runbook: {
|
|
1786
|
+
ask: {},
|
|
1787
|
+
search: {},
|
|
1788
|
+
impact: {},
|
|
1789
|
+
list: {},
|
|
1790
|
+
get: {},
|
|
1791
|
+
cat: {},
|
|
1792
|
+
new: {},
|
|
1793
|
+
edit: {},
|
|
1794
|
+
comment: {},
|
|
1795
|
+
import: {},
|
|
1796
|
+
visibility: {},
|
|
1797
|
+
publish: {},
|
|
1798
|
+
archive: {},
|
|
1799
|
+
history: {},
|
|
1800
|
+
revert: {},
|
|
1801
|
+
rm: {},
|
|
1802
|
+
lint: {}
|
|
1803
|
+
},
|
|
1804
|
+
secrets: { push: {}, status: {}, set: {}, "set-clerk-key": {} },
|
|
1805
|
+
security: {
|
|
1806
|
+
plan: {},
|
|
1807
|
+
sources: {},
|
|
1808
|
+
run: {},
|
|
1809
|
+
status: {},
|
|
1810
|
+
report: {},
|
|
1811
|
+
github: { connect: {}, disconnect: {} }
|
|
1812
|
+
},
|
|
1813
|
+
setup: {},
|
|
1814
|
+
skill: { install: {} },
|
|
1815
|
+
smoke: {},
|
|
1816
|
+
version: {},
|
|
1817
|
+
whoami: {}
|
|
1818
|
+
};
|
|
1819
|
+
}
|
|
1820
|
+
});
|
|
1821
|
+
|
|
1530
1822
|
// src/admin-spend.ts
|
|
1531
1823
|
async function call(ctx, method, scope) {
|
|
1532
1824
|
const url = `${ctx.platformUrl.replace(/\/$/, "")}/registry/platform/spend?scope=${encodeURIComponent(scope)}`;
|
|
@@ -1575,9 +1867,7 @@ async function spendReset(ctx, scope) {
|
|
|
1575
1867
|
async function adminSpend(parsed, ctx) {
|
|
1576
1868
|
const action2 = parsed.positionals[2];
|
|
1577
1869
|
const scope = parsed.positionals[3] ?? stringOpt(parsed.options.scope);
|
|
1578
|
-
if (action2 !== "show" && action2 !== "reset")
|
|
1579
|
-
throw new Error('unknown spend command. Try "odla-ai admin spend show <scope>".');
|
|
1580
|
-
}
|
|
1870
|
+
if (action2 !== "show" && action2 !== "reset") rejectWord(["admin", "spend"], action2);
|
|
1581
1871
|
if (!scope) {
|
|
1582
1872
|
throw new Error(
|
|
1583
1873
|
`"admin spend ${action2}" needs a scope, e.g. odla-ai admin spend ${action2} app:my-app:<incarnation>`
|
|
@@ -1591,6 +1881,7 @@ var init_admin_spend = __esm({
|
|
|
1591
1881
|
"use strict";
|
|
1592
1882
|
init_cjs_shims();
|
|
1593
1883
|
init_argv();
|
|
1884
|
+
init_surface();
|
|
1594
1885
|
money = (value2) => `$${value2.toFixed(2)}`;
|
|
1595
1886
|
}
|
|
1596
1887
|
});
|
|
@@ -2017,12 +2308,12 @@ var init_monitoring_validation = __esm({
|
|
|
2017
2308
|
|
|
2018
2309
|
// src/config.ts
|
|
2019
2310
|
async function loadProjectConfig(configPath = "odla.config.mjs", options = {}) {
|
|
2020
|
-
const resolved = (0,
|
|
2311
|
+
const resolved = (0, import_node_path8.resolve)(configPath);
|
|
2021
2312
|
if (!(0, import_node_fs9.existsSync)(resolved)) {
|
|
2022
2313
|
throw new Error(`config not found: ${configPath}. Run "odla-ai init" first or pass --config.`);
|
|
2023
2314
|
}
|
|
2024
2315
|
const raw = await loadConfigModule(resolved);
|
|
2025
|
-
const rootDir = (0,
|
|
2316
|
+
const rootDir = (0, import_node_path8.dirname)(resolved);
|
|
2026
2317
|
validateRawConfig(raw, resolved);
|
|
2027
2318
|
const platformUrl = trimSlash(process.env.ODLA_PLATFORM_URL || raw.platformUrl || DEFAULT_PLATFORM);
|
|
2028
2319
|
const dbEndpoint = trimSlash(process.env.ODLA_DB_ENDPOINT || raw.dbEndpoint || platformUrl);
|
|
@@ -2032,14 +2323,14 @@ async function loadProjectConfig(configPath = "odla.config.mjs", options = {}) {
|
|
|
2032
2323
|
validateCalendarConfig(raw, unique3([...envs, ...options.additionalEnvs ?? []]), services, resolved);
|
|
2033
2324
|
validateMonitoringConfig(raw, unique3([...envs, ...options.additionalEnvs ?? []]), services, resolved);
|
|
2034
2325
|
const local = {
|
|
2035
|
-
tokenFile: raw.local?.tokenFile ? (0,
|
|
2036
|
-
credentialsFile: raw.local?.credentialsFile ? (0,
|
|
2037
|
-
devVarsFile: (0,
|
|
2326
|
+
tokenFile: raw.local?.tokenFile ? (0, import_node_path8.resolve)(rootDir, raw.local.tokenFile) : appTokenFile(raw.app.id),
|
|
2327
|
+
credentialsFile: raw.local?.credentialsFile ? (0, import_node_path8.resolve)(rootDir, raw.local.credentialsFile) : appCredentialsFile(raw.app.id),
|
|
2328
|
+
devVarsFile: (0, import_node_path8.resolve)(rootDir, raw.local?.devVarsFile ?? ".dev.vars"),
|
|
2038
2329
|
gitignore: raw.local?.gitignore ?? true
|
|
2039
2330
|
};
|
|
2040
|
-
adoptRepoLocalCache((0,
|
|
2041
|
-
adoptRepoLocalCache((0,
|
|
2042
|
-
(0, import_node_fs9.rmSync)((0,
|
|
2331
|
+
adoptRepoLocalCache((0, import_node_path8.resolve)(rootDir, ".odla/dev-token.json"), local.tokenFile, stderr);
|
|
2332
|
+
adoptRepoLocalCache((0, import_node_path8.resolve)(rootDir, ".odla/credentials.local.json"), local.credentialsFile, stderr);
|
|
2333
|
+
(0, import_node_fs9.rmSync)((0, import_node_path8.resolve)(rootDir, ".odla/handshake.local.json"), { force: true });
|
|
2043
2334
|
return {
|
|
2044
2335
|
...raw,
|
|
2045
2336
|
configPath: resolved,
|
|
@@ -2054,7 +2345,7 @@ async function loadProjectConfig(configPath = "odla.config.mjs", options = {}) {
|
|
|
2054
2345
|
async function resolveDataExport(cfg, value2, names) {
|
|
2055
2346
|
if (value2 === void 0 || value2 === null || value2 === false) return void 0;
|
|
2056
2347
|
if (typeof value2 !== "string") return value2;
|
|
2057
|
-
const target = (0,
|
|
2348
|
+
const target = (0, import_node_path8.isAbsolute)(value2) ? value2 : (0, import_node_path8.resolve)(cfg.rootDir, value2);
|
|
2058
2349
|
if (target.endsWith(".json")) {
|
|
2059
2350
|
return JSON.parse((0, import_node_fs9.readFileSync)(target, "utf8"));
|
|
2060
2351
|
}
|
|
@@ -2145,13 +2436,13 @@ function trimSlash(value2) {
|
|
|
2145
2436
|
function unique3(values) {
|
|
2146
2437
|
return [...new Set(values.filter(Boolean))];
|
|
2147
2438
|
}
|
|
2148
|
-
var import_node_fs9,
|
|
2439
|
+
var import_node_fs9, import_node_path8, import_node_url, import_apps, DEFAULT_PLATFORM, DEFAULT_ENVS, DEFAULT_SERVICES, configImportSerial, GOOGLE_CALENDAR_EVENTS_SCOPE, stderr;
|
|
2149
2440
|
var init_config = __esm({
|
|
2150
2441
|
"src/config.ts"() {
|
|
2151
2442
|
"use strict";
|
|
2152
2443
|
init_cjs_shims();
|
|
2153
2444
|
import_node_fs9 = require("fs");
|
|
2154
|
-
|
|
2445
|
+
import_node_path8 = require("path");
|
|
2155
2446
|
import_node_url = require("url");
|
|
2156
2447
|
import_apps = require("@odla-ai/apps");
|
|
2157
2448
|
init_ai_config_validation();
|
|
@@ -2174,13 +2465,13 @@ var init_config = __esm({
|
|
|
2174
2465
|
|
|
2175
2466
|
// src/operator-profiles.ts
|
|
2176
2467
|
function operatorProfileFile() {
|
|
2177
|
-
return (0,
|
|
2178
|
-
clean(
|
|
2468
|
+
return (0, import_node_path9.resolve)(
|
|
2469
|
+
clean(import_node_process14.default.env.ODLA_CONTEXT_FILE) ?? (0, import_node_path9.join)((0, import_node_os3.homedir)(), ".odla", "contexts.json")
|
|
2179
2470
|
);
|
|
2180
2471
|
}
|
|
2181
2472
|
function resolveOperatorProfile(parsed) {
|
|
2182
2473
|
const fromFlag = clean(stringOpt(parsed.options.context));
|
|
2183
|
-
const fromEnvironment = clean(
|
|
2474
|
+
const fromEnvironment = clean(import_node_process14.default.env.ODLA_CONTEXT);
|
|
2184
2475
|
const name = fromFlag ?? fromEnvironment ?? null;
|
|
2185
2476
|
const file = operatorProfileFile();
|
|
2186
2477
|
if (!name) {
|
|
@@ -2220,10 +2511,10 @@ function removeOperatorProfile(name, file = operatorProfileFile()) {
|
|
|
2220
2511
|
return true;
|
|
2221
2512
|
}
|
|
2222
2513
|
function operatorCredentialFiles(selection) {
|
|
2223
|
-
const base = selection.name ? (0,
|
|
2514
|
+
const base = selection.name ? (0, import_node_path9.join)((0, import_node_path9.dirname)(selection.file), "profiles", selection.name) : (0, import_node_path9.join)((0, import_node_os3.homedir)(), ".odla");
|
|
2224
2515
|
return {
|
|
2225
|
-
developer: (0,
|
|
2226
|
-
scoped: (0,
|
|
2516
|
+
developer: (0, import_node_path9.join)(base, "dev-token.json"),
|
|
2517
|
+
scoped: (0, import_node_path9.join)(base, "admin-token.local.json")
|
|
2227
2518
|
};
|
|
2228
2519
|
}
|
|
2229
2520
|
function assertOperatorName(value2, label) {
|
|
@@ -2295,15 +2586,15 @@ function clean(value2) {
|
|
|
2295
2586
|
const normalized = value2?.trim();
|
|
2296
2587
|
return normalized || void 0;
|
|
2297
2588
|
}
|
|
2298
|
-
var import_node_fs10, import_node_os3,
|
|
2589
|
+
var import_node_fs10, import_node_os3, import_node_path9, import_node_process14;
|
|
2299
2590
|
var init_operator_profiles = __esm({
|
|
2300
2591
|
"src/operator-profiles.ts"() {
|
|
2301
2592
|
"use strict";
|
|
2302
2593
|
init_cjs_shims();
|
|
2303
2594
|
import_node_fs10 = require("fs");
|
|
2304
2595
|
import_node_os3 = require("os");
|
|
2305
|
-
|
|
2306
|
-
|
|
2596
|
+
import_node_path9 = require("path");
|
|
2597
|
+
import_node_process14 = __toESM(require("process"), 1);
|
|
2307
2598
|
init_argv();
|
|
2308
2599
|
init_local();
|
|
2309
2600
|
init_token();
|
|
@@ -2314,7 +2605,7 @@ var init_operator_profiles = __esm({
|
|
|
2314
2605
|
async function resolveOperatorContext(parsed, options = {}) {
|
|
2315
2606
|
const profile = resolveOperatorProfile(parsed);
|
|
2316
2607
|
const configArgument = stringOpt(parsed.options.config) ?? "odla.config.mjs";
|
|
2317
|
-
const configPath = (0,
|
|
2608
|
+
const configPath = (0, import_node_path10.resolve)(configArgument);
|
|
2318
2609
|
const explicitConfig = parsed.options.config !== void 0;
|
|
2319
2610
|
const hasConfig = (0, import_node_fs11.existsSync)(configPath);
|
|
2320
2611
|
if (!hasConfig && (!options.allowMissingConfig || explicitConfig)) {
|
|
@@ -2322,13 +2613,13 @@ async function resolveOperatorContext(parsed, options = {}) {
|
|
|
2322
2613
|
}
|
|
2323
2614
|
const loaded = hasConfig ? await loadProjectConfig(configArgument) : void 0;
|
|
2324
2615
|
const platformFlag = clean2(stringOpt(parsed.options.platform));
|
|
2325
|
-
const platformEnvironment = clean2(
|
|
2616
|
+
const platformEnvironment = clean2(import_node_process15.default.env.ODLA_PLATFORM_URL);
|
|
2326
2617
|
const platformValue = platformAudience(
|
|
2327
2618
|
platformFlag ?? platformEnvironment ?? profile.value?.platform ?? loaded?.platformUrl ?? DEFAULT_PLATFORM2
|
|
2328
2619
|
);
|
|
2329
2620
|
const platformSource = platformFlag ? "flag" : platformEnvironment ? "environment" : profile.value ? "profile" : loaded ? "config" : "default";
|
|
2330
2621
|
const appFlag = clean2(stringOpt(parsed.options.app));
|
|
2331
|
-
const appEnvironment = clean2(
|
|
2622
|
+
const appEnvironment = clean2(import_node_process15.default.env.ODLA_APP_ID);
|
|
2332
2623
|
const appValue = appFlag ?? appEnvironment ?? profile.value?.app ?? loaded?.app.id ?? null;
|
|
2333
2624
|
const appSource = appFlag ? "flag" : appEnvironment ? "environment" : profile.value?.app ? "profile" : loaded ? "config" : "unresolved";
|
|
2334
2625
|
if (appValue) {
|
|
@@ -2342,16 +2633,16 @@ async function resolveOperatorContext(parsed, options = {}) {
|
|
|
2342
2633
|
);
|
|
2343
2634
|
}
|
|
2344
2635
|
const envFlag = clean2(stringOpt(parsed.options.env));
|
|
2345
|
-
const envEnvironment = clean2(
|
|
2636
|
+
const envEnvironment = clean2(import_node_process15.default.env.ODLA_ENV);
|
|
2346
2637
|
const environmentValue = envFlag ?? envEnvironment ?? profile.value?.environment ?? options.defaultEnvironment ?? null;
|
|
2347
2638
|
const environmentSource = envFlag ? "flag" : envEnvironment ? "environment" : profile.value?.environment ? "profile" : options.defaultEnvironment ? "default" : "unresolved";
|
|
2348
2639
|
if (environmentValue) {
|
|
2349
2640
|
assertOperatorName(environmentValue, "environment");
|
|
2350
2641
|
}
|
|
2351
|
-
const rootDir = loaded?.rootDir ??
|
|
2642
|
+
const rootDir = loaded?.rootDir ?? import_node_process15.default.cwd();
|
|
2352
2643
|
const profileCredentials = operatorCredentialFiles(profile);
|
|
2353
|
-
const tokenFile = clean2(
|
|
2354
|
-
const scopedTokenFile2 = clean2(
|
|
2644
|
+
const tokenFile = clean2(import_node_process15.default.env.ODLA_DEV_TOKEN_FILE) ? (0, import_node_path10.resolve)(import_node_process15.default.env.ODLA_DEV_TOKEN_FILE) : profile.name ? profileCredentials.developer : loaded?.local.tokenFile ?? profileCredentials.developer;
|
|
2645
|
+
const scopedTokenFile2 = clean2(import_node_process15.default.env.ODLA_ADMIN_TOKEN_FILE) ? (0, import_node_path10.resolve)(import_node_process15.default.env.ODLA_ADMIN_TOKEN_FILE) : profile.name ? profileCredentials.scoped : loaded ? (0, import_node_path10.join)(loaded.rootDir, ".odla", "admin-token.local.json") : profileCredentials.scoped;
|
|
2355
2646
|
const cfg = loaded ? {
|
|
2356
2647
|
...loaded,
|
|
2357
2648
|
platformUrl: platformValue,
|
|
@@ -2373,8 +2664,8 @@ async function resolveOperatorContext(parsed, options = {}) {
|
|
|
2373
2664
|
services: [],
|
|
2374
2665
|
local: {
|
|
2375
2666
|
tokenFile,
|
|
2376
|
-
credentialsFile: (0,
|
|
2377
|
-
devVarsFile: (0,
|
|
2667
|
+
credentialsFile: (0, import_node_path10.join)(rootDir, ".odla", "credentials.local.json"),
|
|
2668
|
+
devVarsFile: (0, import_node_path10.join)(rootDir, ".dev.vars"),
|
|
2378
2669
|
gitignore: true
|
|
2379
2670
|
}
|
|
2380
2671
|
};
|
|
@@ -2406,14 +2697,14 @@ function clean2(value2) {
|
|
|
2406
2697
|
const normalized = value2?.trim();
|
|
2407
2698
|
return normalized || void 0;
|
|
2408
2699
|
}
|
|
2409
|
-
var import_node_fs11,
|
|
2700
|
+
var import_node_fs11, import_node_path10, import_node_process15, DEFAULT_PLATFORM2;
|
|
2410
2701
|
var init_operator_context = __esm({
|
|
2411
2702
|
"src/operator-context.ts"() {
|
|
2412
2703
|
"use strict";
|
|
2413
2704
|
init_cjs_shims();
|
|
2414
2705
|
import_node_fs11 = require("fs");
|
|
2415
|
-
|
|
2416
|
-
|
|
2706
|
+
import_node_path10 = require("path");
|
|
2707
|
+
import_node_process15 = __toESM(require("process"), 1);
|
|
2417
2708
|
init_argv();
|
|
2418
2709
|
init_config();
|
|
2419
2710
|
init_operator_profiles();
|
|
@@ -2426,6 +2717,11 @@ var init_operator_context = __esm({
|
|
|
2426
2717
|
async function adminCommand(parsed, deps = {}) {
|
|
2427
2718
|
const area = parsed.positionals[1];
|
|
2428
2719
|
const action2 = parsed.positionals[2];
|
|
2720
|
+
if (area !== "ai" && area !== "spend") rejectWord(["admin"], area);
|
|
2721
|
+
if (!acceptedAfter(["admin", area]).includes(action2 ?? "")) rejectWord(["admin", area], action2);
|
|
2722
|
+
if (action2 === "credential" && !acceptedAfter(["admin", "ai", "credential"]).includes(parsed.positionals[3] ?? "")) {
|
|
2723
|
+
rejectWord(["admin", "ai", "credential"], parsed.positionals[3]);
|
|
2724
|
+
}
|
|
2429
2725
|
if (area === "spend") {
|
|
2430
2726
|
assertArgs(parsed, JSON_OPTIONS, 4);
|
|
2431
2727
|
const context2 = await resolveOperatorContext(parsed, { allowMissingConfig: true });
|
|
@@ -2451,14 +2747,11 @@ async function adminCommand(parsed, deps = {}) {
|
|
|
2451
2747
|
out
|
|
2452
2748
|
});
|
|
2453
2749
|
}
|
|
2454
|
-
const credentialSet = action2 === "credential"
|
|
2750
|
+
const credentialSet = action2 === "credential";
|
|
2455
2751
|
const credentials = action2 === "credentials";
|
|
2456
2752
|
const models = action2 === "models";
|
|
2457
2753
|
const usage = action2 === "usage";
|
|
2458
2754
|
const audit = action2 === "audit";
|
|
2459
|
-
if (area !== "ai" || action2 !== "show" && action2 !== "set" && !credentialSet && !credentials && !models && !usage && !audit) {
|
|
2460
|
-
throw new Error('unknown admin command. Try "odla-ai admin ai show".');
|
|
2461
|
-
}
|
|
2462
2755
|
const allowed = credentialSet ? [...CONTEXT_OPTIONS, "from-env", "stdin"] : action2 === "set" ? SET_OPTIONS : models ? [...JSON_OPTIONS, "provider"] : usage ? [...JSON_OPTIONS, "app-id", "env", "run-id", "limit"] : audit ? [...JSON_OPTIONS, "limit"] : JSON_OPTIONS;
|
|
2463
2756
|
assertArgs(parsed, allowed, credentialSet ? 5 : action2 === "set" ? 4 : 3);
|
|
2464
2757
|
const context = await resolveOperatorContext(parsed, { allowMissingConfig: true });
|
|
@@ -2504,6 +2797,7 @@ var init_admin_command = __esm({
|
|
|
2504
2797
|
init_token();
|
|
2505
2798
|
init_argv();
|
|
2506
2799
|
init_operator_context();
|
|
2800
|
+
init_surface();
|
|
2507
2801
|
CONTEXT_OPTIONS = ["platform", "config", "context", "token", "open", "email"];
|
|
2508
2802
|
JSON_OPTIONS = [...CONTEXT_OPTIONS, "json"];
|
|
2509
2803
|
SET_OPTIONS = [
|
|
@@ -2708,9 +3002,7 @@ async function authCommand(parsed, deps = {}) {
|
|
|
2708
3002
|
"json"
|
|
2709
3003
|
], 2);
|
|
2710
3004
|
const action2 = parsed.positionals[1] ?? "login";
|
|
2711
|
-
if (action2 !== "login")
|
|
2712
|
-
throw new Error(`unknown auth action "${action2}". Try "odla-ai auth login --app <id> --email <odla-account>".`);
|
|
2713
|
-
}
|
|
3005
|
+
if (action2 !== "login") rejectWord(["auth"], action2);
|
|
2714
3006
|
const context = await resolveOperatorContext(parsed, {
|
|
2715
3007
|
allowMissingConfig: true,
|
|
2716
3008
|
requireApp: true
|
|
@@ -2718,7 +3010,7 @@ async function authCommand(parsed, deps = {}) {
|
|
|
2718
3010
|
const { cfg } = context;
|
|
2719
3011
|
const out = deps.stdout ?? console;
|
|
2720
3012
|
const doFetch = deps.fetch ?? fetch;
|
|
2721
|
-
const email = stringOpt(parsed.options.email) ??
|
|
3013
|
+
const email = stringOpt(parsed.options.email) ?? import_node_process16.default.env.ODLA_USER_EMAIL?.trim();
|
|
2722
3014
|
if (!email) {
|
|
2723
3015
|
throw new Error(
|
|
2724
3016
|
"auth login requires --email <odla-account> or ODLA_USER_EMAIL; confirm the signed-in odla email instead of using git or GitHub identity"
|
|
@@ -2757,17 +3049,18 @@ async function authCommand(parsed, deps = {}) {
|
|
|
2757
3049
|
out.log(`Authorized ${identity.displayName}${handle} for ${cfg.app.id}.`);
|
|
2758
3050
|
out.log(`odla account: ${identity.email ?? "not returned"}`);
|
|
2759
3051
|
}
|
|
2760
|
-
var
|
|
3052
|
+
var import_node_process16;
|
|
2761
3053
|
var init_auth_command = __esm({
|
|
2762
3054
|
"src/auth-command.ts"() {
|
|
2763
3055
|
"use strict";
|
|
2764
3056
|
init_cjs_shims();
|
|
2765
|
-
|
|
3057
|
+
import_node_process16 = __toESM(require("process"), 1);
|
|
2766
3058
|
init_argv();
|
|
2767
3059
|
init_operator_context();
|
|
2768
3060
|
init_token();
|
|
2769
3061
|
init_auth_guidance();
|
|
2770
3062
|
init_whoami_command();
|
|
3063
|
+
init_surface();
|
|
2771
3064
|
}
|
|
2772
3065
|
});
|
|
2773
3066
|
|
|
@@ -2803,9 +3096,7 @@ var init_tenant = __esm({
|
|
|
2803
3096
|
// src/agent-command.ts
|
|
2804
3097
|
async function agentCommand(parsed, deps = {}) {
|
|
2805
3098
|
const action2 = parsed.positionals[1];
|
|
2806
|
-
if (action2 !== "jobs" && action2 !== "retry")
|
|
2807
|
-
throw new Error(`unknown agent action "${action2 ?? ""}". Try "odla-ai agent jobs --json".`);
|
|
2808
|
-
}
|
|
3099
|
+
if (action2 !== "jobs" && action2 !== "retry") rejectWord(["agent"], action2);
|
|
2809
3100
|
assertArgs(parsed, ["config", "env", "state", "limit", "json", "token"], action2 === "jobs" ? 2 : 3);
|
|
2810
3101
|
if (action2 === "retry" && (parsed.options.state !== void 0 || parsed.options.limit !== void 0)) {
|
|
2811
3102
|
throw new Error('--state and --limit are supported only by "agent jobs"');
|
|
@@ -2887,6 +3178,7 @@ var init_agent_command = __esm({
|
|
|
2887
3178
|
init_config();
|
|
2888
3179
|
init_tenant();
|
|
2889
3180
|
init_local();
|
|
3181
|
+
init_surface();
|
|
2890
3182
|
}
|
|
2891
3183
|
});
|
|
2892
3184
|
|
|
@@ -3010,9 +3302,7 @@ async function appOwnersCommand(parsed, dependencies = {}) {
|
|
|
3010
3302
|
await (sub === "add" ? ownersAdd(email, options) : ownersRemove(email, options));
|
|
3011
3303
|
return;
|
|
3012
3304
|
}
|
|
3013
|
-
|
|
3014
|
-
`unknown app owners subcommand "${sub}". Try "odla-ai app owners list", "odla-ai app owners add <email>", or "odla-ai app owners remove <email>".`
|
|
3015
|
-
);
|
|
3305
|
+
rejectWord(["app", "owners"], sub);
|
|
3016
3306
|
}
|
|
3017
3307
|
var init_app_owners = __esm({
|
|
3018
3308
|
"src/app-owners.ts"() {
|
|
@@ -3020,6 +3310,7 @@ var init_app_owners = __esm({
|
|
|
3020
3310
|
init_cjs_shims();
|
|
3021
3311
|
init_argv();
|
|
3022
3312
|
init_human_session();
|
|
3313
|
+
init_surface();
|
|
3023
3314
|
}
|
|
3024
3315
|
});
|
|
3025
3316
|
|
|
@@ -3143,8 +3434,10 @@ async function appCommand(parsed, dependencies = {}) {
|
|
|
3143
3434
|
return;
|
|
3144
3435
|
}
|
|
3145
3436
|
if (sub !== "archive" && sub !== "restore") {
|
|
3146
|
-
|
|
3147
|
-
|
|
3437
|
+
rejectWord(
|
|
3438
|
+
["app"],
|
|
3439
|
+
sub,
|
|
3440
|
+
"Permanent deletion has no CLI: it requires a signed-in owner in Studio."
|
|
3148
3441
|
);
|
|
3149
3442
|
}
|
|
3150
3443
|
assertArgs(parsed, ["config", "token", "email", "yes", "json"], 2);
|
|
@@ -3171,6 +3464,7 @@ var init_app_lifecycle = __esm({
|
|
|
3171
3464
|
init_app_transfer();
|
|
3172
3465
|
init_argv();
|
|
3173
3466
|
init_human_session();
|
|
3467
|
+
init_surface();
|
|
3174
3468
|
}
|
|
3175
3469
|
});
|
|
3176
3470
|
|
|
@@ -3280,15 +3574,15 @@ var init_brand_design_unpack = __esm({
|
|
|
3280
3574
|
|
|
3281
3575
|
// src/brand-command.ts
|
|
3282
3576
|
async function readBundle(source, deps) {
|
|
3283
|
-
if (source !== "-") return (0, import_promises.readFile)((0,
|
|
3577
|
+
if (source !== "-") return (0, import_promises.readFile)((0, import_node_path11.resolve)(source), "utf8");
|
|
3284
3578
|
const readStdin = deps.readStdin;
|
|
3285
3579
|
if (!readStdin) throw new Error("reading a bundle from stdin is not supported here");
|
|
3286
3580
|
return readStdin();
|
|
3287
3581
|
}
|
|
3288
3582
|
async function writeAll(result, outDir) {
|
|
3289
3583
|
for (const file of result.files) {
|
|
3290
|
-
const target = (0,
|
|
3291
|
-
await (0, import_promises.mkdir)((0,
|
|
3584
|
+
const target = (0, import_node_path11.resolve)(outDir, file.path);
|
|
3585
|
+
await (0, import_promises.mkdir)((0, import_node_path11.dirname)(target), { recursive: true });
|
|
3292
3586
|
await (0, import_promises.writeFile)(target, file.bytes);
|
|
3293
3587
|
}
|
|
3294
3588
|
}
|
|
@@ -3296,7 +3590,7 @@ async function designUnpack(parsed, deps) {
|
|
|
3296
3590
|
assertArgs(parsed, ["out", "json"], 4);
|
|
3297
3591
|
const source = parsed.positionals[3];
|
|
3298
3592
|
if (!source) throw new Error(USAGE);
|
|
3299
|
-
const outDir = (0,
|
|
3593
|
+
const outDir = (0, import_node_path11.resolve)(stringOpt(parsed.options.out) ?? "design");
|
|
3300
3594
|
const result = unpackDesign(await readBundle(source, deps));
|
|
3301
3595
|
await writeAll(result, outDir);
|
|
3302
3596
|
const out = deps.stdout ?? console;
|
|
@@ -3320,17 +3614,19 @@ async function brandCommand(parsed, deps) {
|
|
|
3320
3614
|
await designUnpack(parsed, deps);
|
|
3321
3615
|
return;
|
|
3322
3616
|
}
|
|
3323
|
-
|
|
3617
|
+
if (subject !== "design") rejectWord(["brand"], subject);
|
|
3618
|
+
rejectWord(["brand", "design"], action2, USAGE);
|
|
3324
3619
|
}
|
|
3325
|
-
var import_promises,
|
|
3620
|
+
var import_promises, import_node_path11, USAGE;
|
|
3326
3621
|
var init_brand_command = __esm({
|
|
3327
3622
|
"src/brand-command.ts"() {
|
|
3328
3623
|
"use strict";
|
|
3329
3624
|
init_cjs_shims();
|
|
3330
3625
|
import_promises = require("fs/promises");
|
|
3331
|
-
|
|
3626
|
+
import_node_path11 = require("path");
|
|
3332
3627
|
init_argv();
|
|
3333
3628
|
init_brand_design_unpack();
|
|
3629
|
+
init_surface();
|
|
3334
3630
|
USAGE = "usage: odla-ai brand design unpack <bundle.html|-> [--out <dir>] [--json]";
|
|
3335
3631
|
}
|
|
3336
3632
|
});
|
|
@@ -4376,7 +4672,7 @@ async function operationClient(cfg, options, purpose) {
|
|
|
4376
4672
|
platform: cfg.platformUrl,
|
|
4377
4673
|
scope: "app:config:write",
|
|
4378
4674
|
token: options.token,
|
|
4379
|
-
tokenFile: (0,
|
|
4675
|
+
tokenFile: (0, import_node_path12.join)(cfg.rootDir, ".odla", "admin-token.local.json"),
|
|
4380
4676
|
rootDir: cfg.rootDir,
|
|
4381
4677
|
email: options.email,
|
|
4382
4678
|
open: options.open,
|
|
@@ -4428,13 +4724,13 @@ function normalizeRequestError(error) {
|
|
|
4428
4724
|
function record4(value2) {
|
|
4429
4725
|
return !!value2 && typeof value2 === "object" && !Array.isArray(value2);
|
|
4430
4726
|
}
|
|
4431
|
-
var import_apps6,
|
|
4727
|
+
var import_apps6, import_node_path12, IDEMPOTENCY_KEY, DEFAULT_WAIT_SECONDS, DEFAULT_INTERVAL_SECONDS;
|
|
4432
4728
|
var init_config_operation_command = __esm({
|
|
4433
4729
|
"src/config-operation-command.ts"() {
|
|
4434
4730
|
"use strict";
|
|
4435
4731
|
init_cjs_shims();
|
|
4436
4732
|
import_apps6 = require("@odla-ai/apps");
|
|
4437
|
-
|
|
4733
|
+
import_node_path12 = require("path");
|
|
4438
4734
|
init_admin_ai_auth();
|
|
4439
4735
|
init_version();
|
|
4440
4736
|
init_config();
|
|
@@ -4757,7 +5053,7 @@ async function inspectConfig(options) {
|
|
|
4757
5053
|
platform: cfg.platformUrl,
|
|
4758
5054
|
scope: "app:config:read",
|
|
4759
5055
|
token: options.token,
|
|
4760
|
-
tokenFile: (0,
|
|
5056
|
+
tokenFile: (0, import_node_path13.join)(cfg.rootDir, ".odla", "admin-token.local.json"),
|
|
4761
5057
|
rootDir: cfg.rootDir,
|
|
4762
5058
|
email: options.email,
|
|
4763
5059
|
open: options.open,
|
|
@@ -4886,13 +5182,13 @@ function studioSettingsUrl(reconciliation) {
|
|
|
4886
5182
|
function quoteArg2(value2) {
|
|
4887
5183
|
return `'${value2.replace(/'/g, `'\\''`)}'`;
|
|
4888
5184
|
}
|
|
4889
|
-
var import_apps8,
|
|
5185
|
+
var import_apps8, import_node_path13;
|
|
4890
5186
|
var init_config_reconcile_command = __esm({
|
|
4891
5187
|
"src/config-reconcile-command.ts"() {
|
|
4892
5188
|
"use strict";
|
|
4893
5189
|
init_cjs_shims();
|
|
4894
5190
|
import_apps8 = require("@odla-ai/apps");
|
|
4895
|
-
|
|
5191
|
+
import_node_path13 = require("path");
|
|
4896
5192
|
init_admin_ai_auth();
|
|
4897
5193
|
init_config();
|
|
4898
5194
|
init_config_reconcile_digest();
|
|
@@ -4905,7 +5201,7 @@ var init_config_reconcile_command = __esm({
|
|
|
4905
5201
|
// src/wrangler.ts
|
|
4906
5202
|
function findWranglerConfig(rootDir) {
|
|
4907
5203
|
for (const name of WRANGLER_CONFIG_FILES) {
|
|
4908
|
-
const path = (0,
|
|
5204
|
+
const path = (0, import_node_path14.join)(rootDir, name);
|
|
4909
5205
|
if ((0, import_node_fs14.existsSync)(path)) return path;
|
|
4910
5206
|
}
|
|
4911
5207
|
return null;
|
|
@@ -5017,16 +5313,16 @@ function wranglerBulkSecrets(run, opts) {
|
|
|
5017
5313
|
];
|
|
5018
5314
|
return run("npx", args, { input: JSON.stringify(opts.secrets), cwd: opts.cwd });
|
|
5019
5315
|
}
|
|
5020
|
-
var
|
|
5316
|
+
var import_node_child_process3, import_node_fs14, import_node_path14, defaultRunner, WRANGLER_CONFIG_FILES;
|
|
5021
5317
|
var init_wrangler = __esm({
|
|
5022
5318
|
"src/wrangler.ts"() {
|
|
5023
5319
|
"use strict";
|
|
5024
5320
|
init_cjs_shims();
|
|
5025
|
-
|
|
5321
|
+
import_node_child_process3 = require("child_process");
|
|
5026
5322
|
import_node_fs14 = require("fs");
|
|
5027
|
-
|
|
5323
|
+
import_node_path14 = require("path");
|
|
5028
5324
|
defaultRunner = (cmd, args, opts) => new Promise((resolvePromise, reject) => {
|
|
5029
|
-
const child = (0,
|
|
5325
|
+
const child = (0, import_node_child_process3.spawn)(cmd, args, { cwd: opts?.cwd, stdio: ["pipe", "pipe", "pipe"] });
|
|
5030
5326
|
let stdout = "";
|
|
5031
5327
|
let stderr2 = "";
|
|
5032
5328
|
child.stdout.on("data", (chunk) => stdout += chunk.toString());
|
|
@@ -5083,10 +5379,10 @@ function wranglerWarnings(rootDir) {
|
|
|
5083
5379
|
for (const { label, block: block2 } of blocks) {
|
|
5084
5380
|
const assets = block2.assets;
|
|
5085
5381
|
if (assets?.directory) {
|
|
5086
|
-
const dir = (0,
|
|
5087
|
-
if (dir === (0,
|
|
5382
|
+
const dir = (0, import_node_path15.resolve)(rootDir, assets.directory);
|
|
5383
|
+
if (dir === (0, import_node_path15.resolve)(rootDir)) {
|
|
5088
5384
|
warnings.push(`${label}assets.directory is the project root \u2014 point it at a dedicated build dir (wrangler dev fails with "spawn EBADF")`);
|
|
5089
|
-
} else if ((0, import_node_fs15.existsSync)((0,
|
|
5385
|
+
} else if ((0, import_node_fs15.existsSync)((0, import_node_path15.join)(dir, "node_modules"))) {
|
|
5090
5386
|
warnings.push(`${label}assets.directory contains node_modules \u2014 wrangler dev's watcher will exhaust file descriptors`);
|
|
5091
5387
|
}
|
|
5092
5388
|
}
|
|
@@ -5121,7 +5417,7 @@ function o11yProjectWarnings(rootDir) {
|
|
|
5121
5417
|
warnings.push("cannot verify o11y Worker instrumentation \u2014 add a parseable wrangler.jsonc/json config");
|
|
5122
5418
|
return warnings;
|
|
5123
5419
|
}
|
|
5124
|
-
const main = typeof config.main === "string" ? (0,
|
|
5420
|
+
const main = typeof config.main === "string" ? (0, import_node_path15.resolve)(rootDir, config.main) : null;
|
|
5125
5421
|
if (!main || !(0, import_node_fs15.existsSync)(main)) {
|
|
5126
5422
|
warnings.push("cannot verify o11y Worker instrumentation \u2014 wrangler main is missing or unreadable");
|
|
5127
5423
|
} else {
|
|
@@ -5151,23 +5447,23 @@ function calendarProjectWarnings(rootDir) {
|
|
|
5151
5447
|
}
|
|
5152
5448
|
function readPackageJson(rootDir) {
|
|
5153
5449
|
try {
|
|
5154
|
-
return JSON.parse((0, import_node_fs15.readFileSync)((0,
|
|
5450
|
+
return JSON.parse((0, import_node_fs15.readFileSync)((0, import_node_path15.join)(rootDir, "package.json"), "utf8"));
|
|
5155
5451
|
} catch {
|
|
5156
5452
|
return null;
|
|
5157
5453
|
}
|
|
5158
5454
|
}
|
|
5159
|
-
var
|
|
5455
|
+
var import_node_child_process4, import_node_fs15, import_node_path15, defaultExec;
|
|
5160
5456
|
var init_doctor_checks = __esm({
|
|
5161
5457
|
"src/doctor-checks.ts"() {
|
|
5162
5458
|
"use strict";
|
|
5163
5459
|
init_cjs_shims();
|
|
5164
|
-
|
|
5460
|
+
import_node_child_process4 = require("child_process");
|
|
5165
5461
|
import_node_fs15 = require("fs");
|
|
5166
|
-
|
|
5462
|
+
import_node_path15 = require("path");
|
|
5167
5463
|
init_redact();
|
|
5168
5464
|
init_local();
|
|
5169
5465
|
init_wrangler();
|
|
5170
|
-
defaultExec = (cmd, args, cwd) => (0,
|
|
5466
|
+
defaultExec = (cmd, args, cwd) => (0, import_node_child_process4.execFileSync)(cmd, args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
5171
5467
|
}
|
|
5172
5468
|
});
|
|
5173
5469
|
|
|
@@ -5500,8 +5796,8 @@ var init_harness_options = __esm({
|
|
|
5500
5796
|
// src/init.ts
|
|
5501
5797
|
function initProject(options) {
|
|
5502
5798
|
const out = options.stdout ?? console;
|
|
5503
|
-
const rootDir = (0,
|
|
5504
|
-
const configPath = (0,
|
|
5799
|
+
const rootDir = (0, import_node_path16.resolve)(options.rootDir ?? process.cwd());
|
|
5800
|
+
const configPath = (0, import_node_path16.resolve)(rootDir, options.configPath ?? "odla.config.mjs");
|
|
5505
5801
|
if ((0, import_node_fs16.existsSync)(configPath) && !options.force) {
|
|
5506
5802
|
throw new Error(`${configPath} already exists. Pass --force to overwrite.`);
|
|
5507
5803
|
}
|
|
@@ -5518,12 +5814,12 @@ function initProject(options) {
|
|
|
5518
5814
|
}
|
|
5519
5815
|
}
|
|
5520
5816
|
const aiProvider = options.aiProvider;
|
|
5521
|
-
(0, import_node_fs16.mkdirSync)((0,
|
|
5522
|
-
(0, import_node_fs16.mkdirSync)((0,
|
|
5523
|
-
(0, import_node_fs16.mkdirSync)((0,
|
|
5817
|
+
(0, import_node_fs16.mkdirSync)((0, import_node_path16.dirname)(configPath), { recursive: true });
|
|
5818
|
+
(0, import_node_fs16.mkdirSync)((0, import_node_path16.resolve)(rootDir, "src/odla"), { recursive: true });
|
|
5819
|
+
(0, import_node_fs16.mkdirSync)((0, import_node_path16.resolve)(rootDir, ".odla"), { recursive: true });
|
|
5524
5820
|
(0, import_node_fs16.writeFileSync)(configPath, configTemplate({ appId: options.appId, name: options.name, envs, services, aiProvider }));
|
|
5525
|
-
writeIfMissing((0,
|
|
5526
|
-
writeIfMissing((0,
|
|
5821
|
+
writeIfMissing((0, import_node_path16.resolve)(rootDir, "src/odla/schema.mjs"), schemaTemplate());
|
|
5822
|
+
writeIfMissing((0, import_node_path16.resolve)(rootDir, "src/odla/rules.mjs"), rulesTemplate());
|
|
5527
5823
|
ensureGitignore(rootDir);
|
|
5528
5824
|
out.log(`created ${relativeDisplay(configPath, rootDir)}`);
|
|
5529
5825
|
out.log("created src/odla/schema.mjs and src/odla/rules.mjs");
|
|
@@ -5636,13 +5932,13 @@ function defaultKeyEnv(provider) {
|
|
|
5636
5932
|
function relativeDisplay(path, rootDir) {
|
|
5637
5933
|
return path.startsWith(rootDir) ? path.slice(rootDir.length + 1) : path;
|
|
5638
5934
|
}
|
|
5639
|
-
var import_node_fs16,
|
|
5935
|
+
var import_node_fs16, import_node_path16, import_apps9;
|
|
5640
5936
|
var init_init = __esm({
|
|
5641
5937
|
"src/init.ts"() {
|
|
5642
5938
|
"use strict";
|
|
5643
5939
|
init_cjs_shims();
|
|
5644
5940
|
import_node_fs16 = require("fs");
|
|
5645
|
-
|
|
5941
|
+
import_node_path16 = require("path");
|
|
5646
5942
|
import_apps9 = require("@odla-ai/apps");
|
|
5647
5943
|
init_local();
|
|
5648
5944
|
}
|
|
@@ -5975,8 +6271,8 @@ function installSkill(options = {}) {
|
|
|
5975
6271
|
const files = listFiles(sourceDir);
|
|
5976
6272
|
if (files.length === 0) throw new Error(`no bundled skills found at ${sourceDir}`);
|
|
5977
6273
|
const harnesses = normalizeHarnesses(options.harnesses, options.global === true);
|
|
5978
|
-
const root = (0,
|
|
5979
|
-
const home = (0,
|
|
6274
|
+
const root = (0, import_node_path17.resolve)(options.dir ?? process.cwd());
|
|
6275
|
+
const home = (0, import_node_path17.resolve)(options.homeDir ?? (0, import_node_os4.homedir)());
|
|
5980
6276
|
const plans = /* @__PURE__ */ new Map();
|
|
5981
6277
|
const targets = /* @__PURE__ */ new Map();
|
|
5982
6278
|
const rememberTarget = (harness, target) => {
|
|
@@ -5990,48 +6286,48 @@ function installSkill(options = {}) {
|
|
|
5990
6286
|
plans.set(target, { target, content: content2, boundary, managedMerge });
|
|
5991
6287
|
};
|
|
5992
6288
|
const planSkillTree = (targetDir2, boundary = root) => {
|
|
5993
|
-
for (const rel of files) plan((0,
|
|
6289
|
+
for (const rel of files) plan((0, import_node_path17.join)(targetDir2, rel), (0, import_node_fs17.readFileSync)((0, import_node_path17.join)(sourceDir, rel), "utf8"), false, boundary);
|
|
5994
6290
|
};
|
|
5995
6291
|
let targetDir;
|
|
5996
6292
|
if (options.global) {
|
|
5997
|
-
const claudeRoot = (0,
|
|
5998
|
-
const codexRoot = (0,
|
|
6293
|
+
const claudeRoot = (0, import_node_path17.join)(home, ".claude", "skills");
|
|
6294
|
+
const codexRoot = (0, import_node_path17.resolve)(options.codexHomeDir ?? process.env.CODEX_HOME ?? (0, import_node_path17.join)(home, ".codex"), "skills");
|
|
5999
6295
|
targetDir = harnesses[0] === "codex" ? codexRoot : claudeRoot;
|
|
6000
6296
|
for (const harness of harnesses) {
|
|
6001
6297
|
const skillRoot = harness === "claude" ? claudeRoot : codexRoot;
|
|
6002
|
-
planSkillTree(skillRoot, harness === "claude" ? home : (0,
|
|
6298
|
+
planSkillTree(skillRoot, harness === "claude" ? home : (0, import_node_path17.dirname)((0, import_node_path17.dirname)(codexRoot)));
|
|
6003
6299
|
rememberTarget(harness, skillRoot);
|
|
6004
6300
|
}
|
|
6005
6301
|
} else {
|
|
6006
|
-
const sharedRoot = (0,
|
|
6302
|
+
const sharedRoot = (0, import_node_path17.join)(root, ".agents", "skills");
|
|
6007
6303
|
planSkillTree(sharedRoot);
|
|
6008
|
-
const claudeRoot = (0,
|
|
6304
|
+
const claudeRoot = (0, import_node_path17.join)(root, ".claude", "skills");
|
|
6009
6305
|
targetDir = harnesses.includes("claude") ? claudeRoot : sharedRoot;
|
|
6010
6306
|
for (const harness of harnesses) rememberTarget(harness, sharedRoot);
|
|
6011
6307
|
if (harnesses.includes("claude")) {
|
|
6012
6308
|
for (const skill of skillNames(files)) {
|
|
6013
|
-
const canonical2 = (0, import_node_fs17.readFileSync)((0,
|
|
6014
|
-
plan((0,
|
|
6309
|
+
const canonical2 = (0, import_node_fs17.readFileSync)((0, import_node_path17.join)(sourceDir, skill, "SKILL.md"), "utf8");
|
|
6310
|
+
plan((0, import_node_path17.join)(claudeRoot, skill, "SKILL.md"), claudeAdapter(skill, canonical2));
|
|
6015
6311
|
}
|
|
6016
6312
|
rememberTarget("claude", claudeRoot);
|
|
6017
6313
|
}
|
|
6018
6314
|
if (harnesses.includes("cursor")) {
|
|
6019
|
-
const cursorRule = (0,
|
|
6315
|
+
const cursorRule = (0, import_node_path17.join)(root, ".cursor", "rules", "odla.mdc");
|
|
6020
6316
|
plan(cursorRule, CURSOR_RULE);
|
|
6021
6317
|
rememberTarget("cursor", cursorRule);
|
|
6022
6318
|
}
|
|
6023
6319
|
if (harnesses.includes("agents")) {
|
|
6024
|
-
const agentsFile = (0,
|
|
6320
|
+
const agentsFile = (0, import_node_path17.join)(root, "AGENTS.md");
|
|
6025
6321
|
plan(agentsFile, managedFileContent(agentsFile, PROJECT_INSTRUCTIONS, options.force === true, root), true);
|
|
6026
6322
|
rememberTarget("agents", agentsFile);
|
|
6027
6323
|
}
|
|
6028
6324
|
if (harnesses.includes("copilot")) {
|
|
6029
|
-
const copilotFile = (0,
|
|
6325
|
+
const copilotFile = (0, import_node_path17.join)(root, ".github", "copilot-instructions.md");
|
|
6030
6326
|
plan(copilotFile, managedFileContent(copilotFile, PROJECT_INSTRUCTIONS, options.force === true, root), true);
|
|
6031
6327
|
rememberTarget("copilot", copilotFile);
|
|
6032
6328
|
}
|
|
6033
6329
|
if (harnesses.includes("gemini")) {
|
|
6034
|
-
const geminiFile = (0,
|
|
6330
|
+
const geminiFile = (0, import_node_path17.join)(root, "GEMINI.md");
|
|
6035
6331
|
plan(geminiFile, managedFileContent(geminiFile, PROJECT_INSTRUCTIONS, options.force === true, root), true);
|
|
6036
6332
|
rememberTarget("gemini", geminiFile);
|
|
6037
6333
|
}
|
|
@@ -6067,7 +6363,7 @@ ${conflicts.map((f) => ` - ${f}`).join("\n")}`
|
|
|
6067
6363
|
}
|
|
6068
6364
|
for (const file of plans.values()) {
|
|
6069
6365
|
if (!(0, import_node_fs17.existsSync)(file.target) || (0, import_node_fs17.readFileSync)(file.target, "utf8") !== file.content) {
|
|
6070
|
-
(0, import_node_fs17.mkdirSync)((0,
|
|
6366
|
+
(0, import_node_fs17.mkdirSync)((0, import_node_path17.dirname)(file.target), { recursive: true });
|
|
6071
6367
|
(0, import_node_fs17.writeFileSync)(file.target, file.content);
|
|
6072
6368
|
}
|
|
6073
6369
|
}
|
|
@@ -6087,7 +6383,7 @@ ${conflicts.map((f) => ` - ${f}`).join("\n")}`
|
|
|
6087
6383
|
};
|
|
6088
6384
|
}
|
|
6089
6385
|
function pathsUnder(root, paths2) {
|
|
6090
|
-
return [...paths2].map((path) => (0,
|
|
6386
|
+
return [...paths2].map((path) => (0, import_node_path17.relative)(root, path)).filter((path) => path !== ".." && !path.startsWith(`..${import_node_path17.sep}`) && !(0, import_node_path17.isAbsolute)(path)).sort();
|
|
6091
6387
|
}
|
|
6092
6388
|
function normalizeHarnesses(values, global) {
|
|
6093
6389
|
const requested = values?.length ? values : ["claude"];
|
|
@@ -6132,13 +6428,13 @@ function managedFileContent(path, block2, force, boundary) {
|
|
|
6132
6428
|
return `${current.slice(0, startAt)}${block2}${current.slice(afterEnd)}`;
|
|
6133
6429
|
}
|
|
6134
6430
|
function symlinkedComponent(boundary, target) {
|
|
6135
|
-
const rel = (0,
|
|
6136
|
-
if (rel === ".." || rel.startsWith(`..${
|
|
6431
|
+
const rel = (0, import_node_path17.relative)(boundary, target);
|
|
6432
|
+
if (rel === ".." || rel.startsWith(`..${import_node_path17.sep}`) || (0, import_node_path17.isAbsolute)(rel)) {
|
|
6137
6433
|
throw new Error(`agent setup target escapes its install root: ${target}`);
|
|
6138
6434
|
}
|
|
6139
6435
|
let current = boundary;
|
|
6140
|
-
for (const part of rel.split(
|
|
6141
|
-
current = (0,
|
|
6436
|
+
for (const part of rel.split(import_node_path17.sep).filter(Boolean)) {
|
|
6437
|
+
current = (0, import_node_path17.join)(current, part);
|
|
6142
6438
|
try {
|
|
6143
6439
|
if ((0, import_node_fs17.lstatSync)(current).isSymbolicLink()) return current;
|
|
6144
6440
|
} catch (error) {
|
|
@@ -6155,22 +6451,22 @@ function listFiles(dir) {
|
|
|
6155
6451
|
const results = [];
|
|
6156
6452
|
const walk = (current) => {
|
|
6157
6453
|
for (const entry of (0, import_node_fs17.readdirSync)(current, { withFileTypes: true })) {
|
|
6158
|
-
const path = (0,
|
|
6454
|
+
const path = (0, import_node_path17.join)(current, entry.name);
|
|
6159
6455
|
if (entry.isDirectory()) walk(path);
|
|
6160
|
-
else results.push((0,
|
|
6456
|
+
else results.push((0, import_node_path17.relative)(dir, path));
|
|
6161
6457
|
}
|
|
6162
6458
|
};
|
|
6163
6459
|
walk(dir);
|
|
6164
6460
|
return results.sort();
|
|
6165
6461
|
}
|
|
6166
|
-
var import_node_fs17, import_node_os4,
|
|
6462
|
+
var import_node_fs17, import_node_os4, import_node_path17, import_node_url2, AGENT_HARNESSES;
|
|
6167
6463
|
var init_skill = __esm({
|
|
6168
6464
|
"src/skill.ts"() {
|
|
6169
6465
|
"use strict";
|
|
6170
6466
|
init_cjs_shims();
|
|
6171
6467
|
import_node_fs17 = require("fs");
|
|
6172
6468
|
import_node_os4 = require("os");
|
|
6173
|
-
|
|
6469
|
+
import_node_path17 = require("path");
|
|
6174
6470
|
import_node_url2 = require("url");
|
|
6175
6471
|
init_skill_adapters();
|
|
6176
6472
|
AGENT_HARNESSES = ["claude", "codex", "cursor", "copilot", "gemini", "agents"];
|
|
@@ -6392,9 +6688,7 @@ async function secretsCommand(parsed, deps) {
|
|
|
6392
6688
|
return;
|
|
6393
6689
|
}
|
|
6394
6690
|
if (sub !== "push") {
|
|
6395
|
-
|
|
6396
|
-
`unknown secrets subcommand "${sub ?? ""}". Try "odla-ai secrets push --env dev", "odla-ai secrets status --env dev", "odla-ai secrets set <name> --env dev --stdin", or "odla-ai secrets set-clerk-key --env dev --stdin".`
|
|
6397
|
-
);
|
|
6691
|
+
rejectWord(["secrets"], sub);
|
|
6398
6692
|
}
|
|
6399
6693
|
assertArgs(parsed, ["config", "env", "dry-run", "yes"], 2);
|
|
6400
6694
|
await secretsPush({
|
|
@@ -6407,7 +6701,7 @@ async function secretsCommand(parsed, deps) {
|
|
|
6407
6701
|
async function projectCommand(command, parsed, deps) {
|
|
6408
6702
|
if (command === "ai") {
|
|
6409
6703
|
const sub = parsed.positionals[1];
|
|
6410
|
-
if (sub !== "models")
|
|
6704
|
+
if (sub !== "models") rejectWord(["ai"], sub);
|
|
6411
6705
|
assertArgs(parsed, ["config", "env", "provider", "json"], 2);
|
|
6412
6706
|
await aiModels({
|
|
6413
6707
|
configPath: stringOpt(parsed.options.config) ?? "odla.config.mjs",
|
|
@@ -6421,9 +6715,7 @@ async function projectCommand(command, parsed, deps) {
|
|
|
6421
6715
|
}
|
|
6422
6716
|
if (command === "config") {
|
|
6423
6717
|
const sub = parsed.positionals[1];
|
|
6424
|
-
if (sub !== "diff" && sub !== "plan" && sub !== "apply")
|
|
6425
|
-
throw new Error(`unknown config subcommand "${sub ?? ""}". Try "odla-ai config diff --json".`);
|
|
6426
|
-
}
|
|
6718
|
+
if (sub !== "diff" && sub !== "plan" && sub !== "apply") rejectWord(["config"], sub);
|
|
6427
6719
|
assertArgs(
|
|
6428
6720
|
parsed,
|
|
6429
6721
|
sub === "apply" ? ["config", "plan", "idempotency-key", "token", "email", "open", "json"] : ["config", "token", "email", "open", "json"],
|
|
@@ -6451,7 +6743,7 @@ async function projectCommand(command, parsed, deps) {
|
|
|
6451
6743
|
if (command === "operations") {
|
|
6452
6744
|
const sub = parsed.positionals[1];
|
|
6453
6745
|
if (sub !== "get" && sub !== "wait") {
|
|
6454
|
-
|
|
6746
|
+
rejectWord(["operations"], sub);
|
|
6455
6747
|
}
|
|
6456
6748
|
assertArgs(
|
|
6457
6749
|
parsed,
|
|
@@ -6525,7 +6817,7 @@ async function projectCommand(command, parsed, deps) {
|
|
|
6525
6817
|
}
|
|
6526
6818
|
if (command === "skill") {
|
|
6527
6819
|
const sub = parsed.positionals[1];
|
|
6528
|
-
if (sub !== "install")
|
|
6820
|
+
if (sub !== "install") rejectWord(["skill"], sub);
|
|
6529
6821
|
install(parsed, 2, deps);
|
|
6530
6822
|
return true;
|
|
6531
6823
|
}
|
|
@@ -6553,6 +6845,7 @@ var init_cli_project = __esm({
|
|
|
6553
6845
|
init_secrets_status();
|
|
6554
6846
|
init_skill();
|
|
6555
6847
|
init_smoke();
|
|
6848
|
+
init_surface();
|
|
6556
6849
|
SKILL_OPTS = ["dir", "global", "force", "agent", "harness"];
|
|
6557
6850
|
}
|
|
6558
6851
|
});
|
|
@@ -7743,7 +8036,7 @@ var init_dist2 = __esm({
|
|
|
7743
8036
|
});
|
|
7744
8037
|
|
|
7745
8038
|
// ../graph/dist/code/index.js
|
|
7746
|
-
function
|
|
8039
|
+
function dirname11(path) {
|
|
7747
8040
|
const at = path.lastIndexOf("/");
|
|
7748
8041
|
return at <= 0 ? "." : path.slice(0, at);
|
|
7749
8042
|
}
|
|
@@ -7759,7 +8052,7 @@ function join14(base, specifier) {
|
|
|
7759
8052
|
}
|
|
7760
8053
|
function resolveImport(fromPath, specifier, known) {
|
|
7761
8054
|
if (!specifier.startsWith(".")) return null;
|
|
7762
|
-
const base = join14(
|
|
8055
|
+
const base = join14(dirname11(fromPath), specifier);
|
|
7763
8056
|
const candidates = [
|
|
7764
8057
|
base,
|
|
7765
8058
|
base.replace(/\.js$/, ".ts"),
|
|
@@ -10870,19 +11163,19 @@ async function inferGitHubRepository(cwd = process.cwd(), readOrigin = defaultRe
|
|
|
10870
11163
|
return repositoryFromGitRemote(remote);
|
|
10871
11164
|
}
|
|
10872
11165
|
async function defaultReadOrigin(cwd) {
|
|
10873
|
-
const result = await (0, import_node_util2.promisify)(
|
|
11166
|
+
const result = await (0, import_node_util2.promisify)(import_node_child_process5.execFile)(
|
|
10874
11167
|
"git",
|
|
10875
11168
|
["remote", "get-url", "origin"],
|
|
10876
11169
|
{ cwd, encoding: "utf8" }
|
|
10877
11170
|
);
|
|
10878
11171
|
return result.stdout;
|
|
10879
11172
|
}
|
|
10880
|
-
var
|
|
11173
|
+
var import_node_child_process5, import_node_util2;
|
|
10881
11174
|
var init_security_hosted_github = __esm({
|
|
10882
11175
|
"src/security-hosted-github.ts"() {
|
|
10883
11176
|
"use strict";
|
|
10884
11177
|
init_cjs_shims();
|
|
10885
|
-
|
|
11178
|
+
import_node_child_process5 = require("child_process");
|
|
10886
11179
|
import_node_util2 = require("util");
|
|
10887
11180
|
init_security_hosted_request();
|
|
10888
11181
|
}
|
|
@@ -10929,7 +11222,7 @@ async function prepareCodeLocalSource(cwd, repository, readHead = readGitHead) {
|
|
|
10929
11222
|
}
|
|
10930
11223
|
async function readGitHead(cwd) {
|
|
10931
11224
|
const value2 = await new Promise((accept, reject) => {
|
|
10932
|
-
(0,
|
|
11225
|
+
(0, import_node_child_process6.execFile)("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf8", maxBuffer: 16384 }, (error, stdout) => {
|
|
10933
11226
|
if (error) reject(new Error("code connect requires a Git checkout with an initial commit"));
|
|
10934
11227
|
else accept(stdout.trim());
|
|
10935
11228
|
});
|
|
@@ -10940,12 +11233,12 @@ async function readGitHead(cwd) {
|
|
|
10940
11233
|
function digestText(value2) {
|
|
10941
11234
|
return `sha256:${(0, import_node_crypto3.createHash)("sha256").update(value2).digest("hex")}`;
|
|
10942
11235
|
}
|
|
10943
|
-
var
|
|
11236
|
+
var import_node_child_process6, import_node_crypto3, SOURCE_LIMITS2;
|
|
10944
11237
|
var init_code_local_source = __esm({
|
|
10945
11238
|
"src/code-local-source.ts"() {
|
|
10946
11239
|
"use strict";
|
|
10947
11240
|
init_cjs_shims();
|
|
10948
|
-
|
|
11241
|
+
import_node_child_process6 = require("child_process");
|
|
10949
11242
|
import_node_crypto3 = require("crypto");
|
|
10950
11243
|
init_node();
|
|
10951
11244
|
SOURCE_LIMITS2 = { maxFiles: 2e4, maxBytes: 512 * 1024 * 1024 };
|
|
@@ -10986,7 +11279,7 @@ var init_code_runtime_config = __esm({
|
|
|
10986
11279
|
// src/code-connect.ts
|
|
10987
11280
|
async function codeConnect(options) {
|
|
10988
11281
|
const cwd = options.cwd ?? process.cwd();
|
|
10989
|
-
const configPath = (0,
|
|
11282
|
+
const configPath = (0, import_node_path18.resolve)(cwd, options.configPath);
|
|
10990
11283
|
const cfg = (0, import_node_fs18.existsSync)(configPath) ? await loadProjectConfig(configPath) : null;
|
|
10991
11284
|
const requestedAppId = options.appId?.trim();
|
|
10992
11285
|
if (requestedAppId && !/^[a-z0-9][a-z0-9-]{1,62}$/.test(requestedAppId)) {
|
|
@@ -11152,14 +11445,14 @@ function apiFailure(action2, status, value2) {
|
|
|
11152
11445
|
function record6(value2) {
|
|
11153
11446
|
return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
|
|
11154
11447
|
}
|
|
11155
|
-
var import_node_fs18, import_node_os5,
|
|
11448
|
+
var import_node_fs18, import_node_os5, import_node_path18;
|
|
11156
11449
|
var init_code_connect = __esm({
|
|
11157
11450
|
"src/code-connect.ts"() {
|
|
11158
11451
|
"use strict";
|
|
11159
11452
|
init_cjs_shims();
|
|
11160
11453
|
import_node_fs18 = require("fs");
|
|
11161
11454
|
import_node_os5 = require("os");
|
|
11162
|
-
|
|
11455
|
+
import_node_path18 = require("path");
|
|
11163
11456
|
init_node();
|
|
11164
11457
|
init_admin_ai_auth();
|
|
11165
11458
|
init_config();
|
|
@@ -11198,9 +11491,7 @@ function grantsUrl(cfg, suffix = "") {
|
|
|
11198
11491
|
async function codeGrantCommand(parsed, deps = {}) {
|
|
11199
11492
|
const action2 = parsed.positionals[2];
|
|
11200
11493
|
if (!isAction(action2)) {
|
|
11201
|
-
|
|
11202
|
-
`unknown code grant action "${action2 ?? ""}". Try "odla-ai code grant list --env dev".`
|
|
11203
|
-
);
|
|
11494
|
+
rejectWord(["code", "grant"], action2);
|
|
11204
11495
|
}
|
|
11205
11496
|
const decides = action2 === "approve" || action2 === "revoke";
|
|
11206
11497
|
assertArgs(parsed, ["config", "env", "json", "token", "email", "open"], decides ? 4 : 3);
|
|
@@ -11267,6 +11558,7 @@ var init_code_grant_command = __esm({
|
|
|
11267
11558
|
init_config();
|
|
11268
11559
|
init_redact();
|
|
11269
11560
|
init_token();
|
|
11561
|
+
init_surface();
|
|
11270
11562
|
ACTIONS = ["request", "list", "approve", "revoke"];
|
|
11271
11563
|
isAction = (value2) => ACTIONS.includes(value2 ?? "");
|
|
11272
11564
|
}
|
|
@@ -11331,9 +11623,7 @@ function repositoryUrl(cfg, suffix = "") {
|
|
|
11331
11623
|
async function codeRepositoryCommand(parsed, deps = {}) {
|
|
11332
11624
|
const action2 = parsed.positionals[2];
|
|
11333
11625
|
if (!isAction2(action2)) {
|
|
11334
|
-
|
|
11335
|
-
`unknown code repository action "${action2 ?? ""}". Try "odla-ai code repository show --env dev".`
|
|
11336
|
-
);
|
|
11626
|
+
rejectWord(["code", "repository"], action2);
|
|
11337
11627
|
}
|
|
11338
11628
|
assertArgs(parsed, ["config", "env", "repo", "json", "token", "email", "open"], 3);
|
|
11339
11629
|
const cfg = await loadProjectConfig(stringOpt(parsed.options.config) ?? "odla.config.mjs");
|
|
@@ -11398,6 +11688,7 @@ var init_code_repository_command = __esm({
|
|
|
11398
11688
|
init_config();
|
|
11399
11689
|
init_redact();
|
|
11400
11690
|
init_token();
|
|
11691
|
+
init_surface();
|
|
11401
11692
|
ACTIONS2 = ["show", "list", "bind"];
|
|
11402
11693
|
isAction2 = (value2) => ACTIONS2.includes(value2 ?? "");
|
|
11403
11694
|
}
|
|
@@ -11421,9 +11712,7 @@ async function codeCommand(parsed, dependencies) {
|
|
|
11421
11712
|
});
|
|
11422
11713
|
}
|
|
11423
11714
|
if (sub !== "connect") {
|
|
11424
|
-
|
|
11425
|
-
`unknown code subcommand "${sub ?? ""}". Try "odla-ai code connect --env dev" or "odla-ai code grant list --env dev".`
|
|
11426
|
-
);
|
|
11715
|
+
rejectWord(["code"], sub);
|
|
11427
11716
|
}
|
|
11428
11717
|
assertArgs(parsed, [
|
|
11429
11718
|
"config",
|
|
@@ -11468,6 +11757,7 @@ var init_code_command = __esm({
|
|
|
11468
11757
|
init_code_connect();
|
|
11469
11758
|
init_code_grant_command();
|
|
11470
11759
|
init_code_repository_command();
|
|
11760
|
+
init_surface();
|
|
11471
11761
|
}
|
|
11472
11762
|
});
|
|
11473
11763
|
|
|
@@ -11477,7 +11767,7 @@ function developerTokenStatus(context, parsed, now = Date.now()) {
|
|
|
11477
11767
|
const cacheStatus = !cached?.token ? "missing" : cached.platform !== context.platform.value ? "other-platform" : (cached.expiresAt ?? 0) <= now + 6e4 ? "expired" : "valid";
|
|
11478
11768
|
const source = clean3(
|
|
11479
11769
|
stringOpt(parsed.options.token)
|
|
11480
|
-
) ? "flag" : clean3(
|
|
11770
|
+
) ? "flag" : clean3(import_node_process17.default.env.ODLA_DEV_TOKEN) ? "environment" : cacheStatus === "valid" ? "cache" : "missing";
|
|
11481
11771
|
return {
|
|
11482
11772
|
source,
|
|
11483
11773
|
cacheFile: context.cfg.local.tokenFile,
|
|
@@ -11488,12 +11778,12 @@ function clean3(value2) {
|
|
|
11488
11778
|
const normalized = value2?.trim();
|
|
11489
11779
|
return normalized || void 0;
|
|
11490
11780
|
}
|
|
11491
|
-
var
|
|
11781
|
+
var import_node_process17;
|
|
11492
11782
|
var init_operator_credentials = __esm({
|
|
11493
11783
|
"src/operator-credentials.ts"() {
|
|
11494
11784
|
"use strict";
|
|
11495
11785
|
init_cjs_shims();
|
|
11496
|
-
|
|
11786
|
+
import_node_process17 = __toESM(require("process"), 1);
|
|
11497
11787
|
init_argv();
|
|
11498
11788
|
init_local();
|
|
11499
11789
|
}
|
|
@@ -11579,9 +11869,7 @@ async function contextCommand(parsed, deps = {}) {
|
|
|
11579
11869
|
return;
|
|
11580
11870
|
}
|
|
11581
11871
|
if (action2 !== "show") {
|
|
11582
|
-
|
|
11583
|
-
`unknown context action "${action2 ?? ""}". Try show|list|save|remove.`
|
|
11584
|
-
);
|
|
11872
|
+
rejectWord(["context"], action2);
|
|
11585
11873
|
}
|
|
11586
11874
|
const context = await resolveOperatorContext(parsed, {
|
|
11587
11875
|
allowMissingConfig: true,
|
|
@@ -11638,6 +11926,7 @@ var init_context_command = __esm({
|
|
|
11638
11926
|
init_operator_credentials();
|
|
11639
11927
|
init_operator_context();
|
|
11640
11928
|
init_operator_profiles();
|
|
11929
|
+
init_surface();
|
|
11641
11930
|
}
|
|
11642
11931
|
});
|
|
11643
11932
|
|
|
@@ -11647,9 +11936,7 @@ async function responseError(response2) {
|
|
|
11647
11936
|
}
|
|
11648
11937
|
async function credentialCommand(parsed, deps = {}) {
|
|
11649
11938
|
const action2 = parsed.positionals[1] ?? "list";
|
|
11650
|
-
if (action2 !== "list" && action2 !== "revoke")
|
|
11651
|
-
throw new Error(`unknown credentials action "${action2}". Try "odla-ai credentials list".`);
|
|
11652
|
-
}
|
|
11939
|
+
if (action2 !== "list" && action2 !== "revoke") rejectWord(["credentials"], action2);
|
|
11653
11940
|
assertArgs(parsed, ["config", "env", "all", "json", "token", "email", "open"], action2 === "revoke" ? 3 : 2);
|
|
11654
11941
|
const cfg = await loadProjectConfig(stringOpt(parsed.options.config) ?? "odla.config.mjs");
|
|
11655
11942
|
const doFetch = deps.fetch ?? fetch;
|
|
@@ -11697,6 +11984,7 @@ var init_credential_command = __esm({
|
|
|
11697
11984
|
init_config();
|
|
11698
11985
|
init_redact();
|
|
11699
11986
|
init_token();
|
|
11987
|
+
init_surface();
|
|
11700
11988
|
}
|
|
11701
11989
|
});
|
|
11702
11990
|
|
|
@@ -12075,9 +12363,17 @@ Safety:
|
|
|
12075
12363
|
grant, run it once with --request-grant. That flag ignores ODLA_DEV_TOKEN and
|
|
12076
12364
|
the local cache, prints and opens a fresh exact-project owner-review URL, then
|
|
12077
12365
|
continues provisioning with the approved replacement credential.
|
|
12078
|
-
|
|
12079
|
-
|
|
12080
|
-
|
|
12366
|
+
Every command says so on STDERR when this CLI is older than the one npm
|
|
12367
|
+
serves, naming the repair for how this executable was launched \u2014 rebuild the
|
|
12368
|
+
worktree, npm i the dependency, or npx the scoped package. The answer is read
|
|
12369
|
+
from a cache under ~/.odla refreshed in the background at most every three
|
|
12370
|
+
hours, so no invocation waits on the registry and stdout is never touched.
|
|
12371
|
+
Set ODLA_CLI_UPDATE_CHECK=0 to switch it off.
|
|
12372
|
+
Before a non-dry-run provision, the executable additionally checks npm LIVE
|
|
12373
|
+
rather than trusting that cache: a security-sensitive grant shape must not
|
|
12374
|
+
ride on a three-hour-old answer. A confirmed stale client stops with a safe
|
|
12375
|
+
npx rerun command; a workspace-linked client also identifies the worktree
|
|
12376
|
+
that must be updated.
|
|
12081
12377
|
Run Code from a GitHub checkout already connected to an app in Studio; an
|
|
12082
12378
|
odla.config.mjs may select the app explicitly but is not required. With an
|
|
12083
12379
|
enrolled code.session device, the Studio repository selection authorizes the
|
|
@@ -12697,7 +12993,7 @@ async function discussCommand(parsed, deps = {}) {
|
|
|
12697
12993
|
assertArgs(parsed, ALLOWED, 3);
|
|
12698
12994
|
const action2 = parsed.positionals[1];
|
|
12699
12995
|
const id2 = parsed.positionals[2];
|
|
12700
|
-
if (!
|
|
12996
|
+
if (!acceptedAfter(["discuss"]).includes(action2 ?? "")) rejectWord(["discuss"], action2);
|
|
12701
12997
|
const ctx = await buildContext(parsed, deps);
|
|
12702
12998
|
switch (action2) {
|
|
12703
12999
|
case "groups":
|
|
@@ -12721,7 +13017,7 @@ async function discussCommand(parsed, deps = {}) {
|
|
|
12721
13017
|
return;
|
|
12722
13018
|
}
|
|
12723
13019
|
default:
|
|
12724
|
-
|
|
13020
|
+
rejectWord(["discuss"], action2);
|
|
12725
13021
|
}
|
|
12726
13022
|
}
|
|
12727
13023
|
var ALLOWED;
|
|
@@ -12734,6 +13030,7 @@ var init_discuss_command = __esm({
|
|
|
12734
13030
|
init_discuss_actions();
|
|
12735
13031
|
init_discuss_watch();
|
|
12736
13032
|
init_token();
|
|
13033
|
+
init_surface();
|
|
12737
13034
|
ALLOWED = [
|
|
12738
13035
|
"config",
|
|
12739
13036
|
"token",
|
|
@@ -13578,7 +13875,7 @@ function writePmProjectContext(rootDir, value2) {
|
|
|
13578
13875
|
});
|
|
13579
13876
|
}
|
|
13580
13877
|
function adoptLegacySelection(rootDir) {
|
|
13581
|
-
const legacy = (0,
|
|
13878
|
+
const legacy = (0, import_node_path19.resolve)(rootDir, ".odla", "pm-project.local.json");
|
|
13582
13879
|
if (!(0, import_node_fs19.existsSync)(legacy)) return;
|
|
13583
13880
|
const previous = readJsonFile(legacy);
|
|
13584
13881
|
(0, import_node_fs19.rmSync)(legacy, { force: true });
|
|
@@ -13593,13 +13890,13 @@ function readSelections() {
|
|
|
13593
13890
|
function isSelection(value2) {
|
|
13594
13891
|
return !!value2 && typeof value2.appId === "string" && typeof value2.projectId === "string" && typeof value2.selectedAt === "string";
|
|
13595
13892
|
}
|
|
13596
|
-
var import_node_fs19,
|
|
13893
|
+
var import_node_fs19, import_node_path19, pmProjectContextFile;
|
|
13597
13894
|
var init_pm_project_context = __esm({
|
|
13598
13895
|
"src/pm-project-context.ts"() {
|
|
13599
13896
|
"use strict";
|
|
13600
13897
|
init_cjs_shims();
|
|
13601
13898
|
import_node_fs19 = require("fs");
|
|
13602
|
-
|
|
13899
|
+
import_node_path19 = require("path");
|
|
13603
13900
|
init_local();
|
|
13604
13901
|
init_odla_home();
|
|
13605
13902
|
pmProjectContextFile = () => pmContextFile();
|
|
@@ -13722,7 +14019,7 @@ async function pmCommand(parsed, deps = {}) {
|
|
|
13722
14019
|
assertArgs(parsed, COMMON_OPTIONS, 4);
|
|
13723
14020
|
return pmProjectUse(await buildContext2(parsed, deps), requireId2(parsed.positionals[3], action3));
|
|
13724
14021
|
}
|
|
13725
|
-
|
|
14022
|
+
rejectWord(["pm", "project"], action3);
|
|
13726
14023
|
}
|
|
13727
14024
|
if (word === "next") {
|
|
13728
14025
|
assertArgs(parsed, [...COMMON_OPTIONS, "app", "project", "verbose"], 2);
|
|
@@ -13753,10 +14050,10 @@ async function pmCommand(parsed, deps = {}) {
|
|
|
13753
14050
|
return pmHandoff(await buildContext2(parsed, deps), parsed);
|
|
13754
14051
|
}
|
|
13755
14052
|
const entity = ALIASES[word];
|
|
13756
|
-
if (!entity)
|
|
14053
|
+
if (!entity) rejectWord(["pm"], word);
|
|
13757
14054
|
const requestedAction = parsed.positionals[2] ?? "list";
|
|
13758
14055
|
const action2 = canonicalAction(requestedAction);
|
|
13759
|
-
if (!action2)
|
|
14056
|
+
if (!action2) rejectWord(["pm", word], requestedAction);
|
|
13760
14057
|
assertArgs(parsed, allowedOptions(entity, action2), 4);
|
|
13761
14058
|
if ((action2 === "ready" || action2 === "claim" || action2 === "release") && entity !== "task") {
|
|
13762
14059
|
throw new Error(`pm ${action2} is only valid for tasks`);
|
|
@@ -13809,6 +14106,7 @@ var init_pm_command = __esm({
|
|
|
13809
14106
|
init_pm_watch();
|
|
13810
14107
|
init_pm_project_actions();
|
|
13811
14108
|
init_pm_project_context();
|
|
14109
|
+
init_surface();
|
|
13812
14110
|
ALIASES = {
|
|
13813
14111
|
goal: "goal",
|
|
13814
14112
|
conformance: "goal",
|
|
@@ -13918,12 +14216,7 @@ async function platformCommand(parsed, deps = {}) {
|
|
|
13918
14216
|
if (action2 === "status") {
|
|
13919
14217
|
return platformStatus(parsed, deps);
|
|
13920
14218
|
}
|
|
13921
|
-
|
|
13922
|
-
`unknown platform action "${[
|
|
13923
|
-
action2,
|
|
13924
|
-
parsed.positionals[2]
|
|
13925
|
-
].filter(Boolean).join(" ")}". Try "odla-ai platform status --json".`
|
|
13926
|
-
);
|
|
14219
|
+
rejectWord(["platform"], action2);
|
|
13927
14220
|
}
|
|
13928
14221
|
async function platformStatus(parsed, deps) {
|
|
13929
14222
|
assertArgs(
|
|
@@ -13989,6 +14282,7 @@ var init_platform_command = __esm({
|
|
|
13989
14282
|
init_argv();
|
|
13990
14283
|
init_operator_context();
|
|
13991
14284
|
init_platform_output();
|
|
14285
|
+
init_surface();
|
|
13992
14286
|
}
|
|
13993
14287
|
});
|
|
13994
14288
|
|
|
@@ -14282,9 +14576,7 @@ async function o11yCommand(parsed, deps = {}) {
|
|
|
14282
14576
|
);
|
|
14283
14577
|
const action2 = parsed.positionals[1];
|
|
14284
14578
|
if (action2 !== "status") {
|
|
14285
|
-
|
|
14286
|
-
`unknown o11y action "${action2 ?? ""}". Try "odla-ai o11y status --json".`
|
|
14287
|
-
);
|
|
14579
|
+
rejectWord(["o11y"], action2);
|
|
14288
14580
|
}
|
|
14289
14581
|
const minutes = statusMinutes(
|
|
14290
14582
|
numberOpt(parsed.options.minutes, "--minutes") ?? 60
|
|
@@ -14420,6 +14712,7 @@ var init_o11y_command = __esm({
|
|
|
14420
14712
|
init_o11y_verdict();
|
|
14421
14713
|
init_o11y_output();
|
|
14422
14714
|
init_token();
|
|
14715
|
+
init_surface();
|
|
14423
14716
|
}
|
|
14424
14717
|
});
|
|
14425
14718
|
|
|
@@ -14540,9 +14833,7 @@ var init_monitoring_config = __esm({
|
|
|
14540
14833
|
async function monitorCommand(parsed, deps = {}) {
|
|
14541
14834
|
assertArgs(parsed, OPTIONS, 3);
|
|
14542
14835
|
const action2 = parsed.positionals[1] ?? "status";
|
|
14543
|
-
if (!["
|
|
14544
|
-
throw new Error(`unknown monitor action "${action2}". Try "odla-ai monitor status --json".`);
|
|
14545
|
-
}
|
|
14836
|
+
if (!acceptedAfter(["monitor"]).includes(action2)) rejectWord(["monitor"], action2);
|
|
14546
14837
|
const context = await resolveOperatorContext(parsed, {
|
|
14547
14838
|
allowMissingConfig: action2 !== "plan" && action2 !== "apply",
|
|
14548
14839
|
requireApp: true
|
|
@@ -14696,6 +14987,7 @@ var init_monitor_command = __esm({
|
|
|
14696
14987
|
init_monitoring_config();
|
|
14697
14988
|
init_operator_context();
|
|
14698
14989
|
init_token();
|
|
14990
|
+
init_surface();
|
|
14699
14991
|
OPTIONS = [
|
|
14700
14992
|
"config",
|
|
14701
14993
|
"context",
|
|
@@ -15182,7 +15474,7 @@ async function provision(options) {
|
|
|
15182
15474
|
await provisionIntegrationSeeds(doFetch, cfg.dbEndpoint, tenantId, dbKey, database.integrations, env, out);
|
|
15183
15475
|
}
|
|
15184
15476
|
if (cfg.services.includes("ai") && cfg.ai?.provider && cfg.ai.keyEnv) {
|
|
15185
|
-
const key =
|
|
15477
|
+
const key = import_node_process18.default.env[cfg.ai.keyEnv];
|
|
15186
15478
|
if (key) {
|
|
15187
15479
|
const secretName = cfg.ai.secretName ?? defaultSecretName(cfg.ai.provider);
|
|
15188
15480
|
await (0, import_ai6.putSecret)({ endpoint: cfg.dbEndpoint, token, fetch: doFetch }, tenantId, secretName, key);
|
|
@@ -15221,14 +15513,14 @@ async function provision(options) {
|
|
|
15221
15513
|
}
|
|
15222
15514
|
}
|
|
15223
15515
|
}
|
|
15224
|
-
var import_apps13, import_ai6,
|
|
15516
|
+
var import_apps13, import_ai6, import_node_process18;
|
|
15225
15517
|
var init_provision = __esm({
|
|
15226
15518
|
"src/provision.ts"() {
|
|
15227
15519
|
"use strict";
|
|
15228
15520
|
init_cjs_shims();
|
|
15229
15521
|
import_apps13 = require("@odla-ai/apps");
|
|
15230
15522
|
import_ai6 = require("@odla-ai/ai");
|
|
15231
|
-
|
|
15523
|
+
import_node_process18 = __toESM(require("process"), 1);
|
|
15232
15524
|
init_config();
|
|
15233
15525
|
init_calendar();
|
|
15234
15526
|
init_calendar_errors();
|
|
@@ -15245,186 +15537,9 @@ var init_provision = __esm({
|
|
|
15245
15537
|
}
|
|
15246
15538
|
});
|
|
15247
15539
|
|
|
15248
|
-
// src/surface.ts
|
|
15249
|
-
function acceptedAfter(path) {
|
|
15250
|
-
let node = COMMAND_SURFACE;
|
|
15251
|
-
for (const word of path) {
|
|
15252
|
-
node = node?.[word];
|
|
15253
|
-
if (!node) return [];
|
|
15254
|
-
}
|
|
15255
|
-
return Object.keys(node).sort();
|
|
15256
|
-
}
|
|
15257
|
-
function validateInvocation(words2) {
|
|
15258
|
-
let node = COMMAND_SURFACE;
|
|
15259
|
-
const walked = [];
|
|
15260
|
-
for (const word of words2) {
|
|
15261
|
-
if (Object.keys(node).length === 0) return null;
|
|
15262
|
-
const next = node[word];
|
|
15263
|
-
if (!next) return { validPrefix: walked.join(" "), word, accepted: Object.keys(node).sort() };
|
|
15264
|
-
walked.push(word);
|
|
15265
|
-
node = next;
|
|
15266
|
-
}
|
|
15267
|
-
return null;
|
|
15268
|
-
}
|
|
15269
|
-
function describeProblem(problem) {
|
|
15270
|
-
const where = problem.validPrefix ? `after "${problem.validPrefix}"` : "as a command";
|
|
15271
|
-
return `"${problem.word}" is not accepted ${where} \u2014 try: ${problem.accepted.join(", ")}`;
|
|
15272
|
-
}
|
|
15273
|
-
function invocationPath(words2) {
|
|
15274
|
-
let node = COMMAND_SURFACE;
|
|
15275
|
-
const path = [];
|
|
15276
|
-
for (const word of words2) {
|
|
15277
|
-
const next = node[word];
|
|
15278
|
-
if (!next) break;
|
|
15279
|
-
path.push(word);
|
|
15280
|
-
node = next;
|
|
15281
|
-
if (Object.keys(node).length === 0) break;
|
|
15282
|
-
}
|
|
15283
|
-
return path;
|
|
15284
|
-
}
|
|
15285
|
-
var PM_ACTIONS, PM_TASK_ACTIONS, PM_ENTITIES, COMMAND_SURFACE;
|
|
15286
|
-
var init_surface = __esm({
|
|
15287
|
-
"src/surface.ts"() {
|
|
15288
|
-
"use strict";
|
|
15289
|
-
init_cjs_shims();
|
|
15290
|
-
PM_ACTIONS = {
|
|
15291
|
-
list: {},
|
|
15292
|
-
add: {},
|
|
15293
|
-
create: {},
|
|
15294
|
-
get: {},
|
|
15295
|
-
set: {},
|
|
15296
|
-
update: {},
|
|
15297
|
-
status: {},
|
|
15298
|
-
move: {},
|
|
15299
|
-
done: {},
|
|
15300
|
-
comment: {},
|
|
15301
|
-
comments: {},
|
|
15302
|
-
ref: {},
|
|
15303
|
-
rm: {},
|
|
15304
|
-
delete: {}
|
|
15305
|
-
};
|
|
15306
|
-
PM_TASK_ACTIONS = {
|
|
15307
|
-
...PM_ACTIONS,
|
|
15308
|
-
ready: {},
|
|
15309
|
-
claim: {},
|
|
15310
|
-
release: {}
|
|
15311
|
-
};
|
|
15312
|
-
PM_ENTITIES = {
|
|
15313
|
-
...Object.fromEntries(
|
|
15314
|
-
["goal", "conformance", "decision", "bug"].map((entity) => [entity, PM_ACTIONS])
|
|
15315
|
-
),
|
|
15316
|
-
task: PM_TASK_ACTIONS,
|
|
15317
|
-
kanban: PM_TASK_ACTIONS
|
|
15318
|
-
};
|
|
15319
|
-
COMMAND_SURFACE = {
|
|
15320
|
-
agent: { jobs: {}, retry: {} },
|
|
15321
|
-
ai: { models: {} },
|
|
15322
|
-
admin: {
|
|
15323
|
-
ai: {
|
|
15324
|
-
show: {},
|
|
15325
|
-
set: {},
|
|
15326
|
-
credentials: {},
|
|
15327
|
-
models: {},
|
|
15328
|
-
usage: {},
|
|
15329
|
-
audit: {},
|
|
15330
|
-
credential: { set: {} }
|
|
15331
|
-
}
|
|
15332
|
-
},
|
|
15333
|
-
app: {
|
|
15334
|
-
archive: {},
|
|
15335
|
-
restore: {},
|
|
15336
|
-
export: {},
|
|
15337
|
-
import: {},
|
|
15338
|
-
rename: {},
|
|
15339
|
-
"refresh-sandbox": {},
|
|
15340
|
-
"go-live": {},
|
|
15341
|
-
promote: {},
|
|
15342
|
-
owners: { list: {}, add: {}, remove: {} }
|
|
15343
|
-
},
|
|
15344
|
-
auth: { login: {} },
|
|
15345
|
-
brand: { design: { unpack: {} } },
|
|
15346
|
-
bug: { create: {}, list: {}, report: {} },
|
|
15347
|
-
calendar: { status: {}, calendars: {}, connect: {}, disconnect: {} },
|
|
15348
|
-
capabilities: {},
|
|
15349
|
-
code: {
|
|
15350
|
-
connect: {},
|
|
15351
|
-
grant: { request: {}, list: {}, approve: {}, revoke: {} },
|
|
15352
|
-
repository: { show: {}, list: {}, bind: {} }
|
|
15353
|
-
},
|
|
15354
|
-
config: { diff: {}, plan: {}, apply: {} },
|
|
15355
|
-
context: { show: {}, list: {}, save: {}, remove: {} },
|
|
15356
|
-
credentials: { list: {}, revoke: {} },
|
|
15357
|
-
device: { enroll: {}, list: {}, revoke: {} },
|
|
15358
|
-
// `watch`, `read`, `reply`, and `resolve` take a topic id from there on.
|
|
15359
|
-
discuss: {
|
|
15360
|
-
groups: {},
|
|
15361
|
-
list: {},
|
|
15362
|
-
topics: {},
|
|
15363
|
-
read: {},
|
|
15364
|
-
post: {},
|
|
15365
|
-
reply: {},
|
|
15366
|
-
resolve: {},
|
|
15367
|
-
who: {},
|
|
15368
|
-
watch: {}
|
|
15369
|
-
},
|
|
15370
|
-
doctor: {},
|
|
15371
|
-
help: {},
|
|
15372
|
-
init: {},
|
|
15373
|
-
monitor: { plan: {}, apply: {}, run: {}, status: {}, incidents: {}, report: {} },
|
|
15374
|
-
o11y: { status: {} },
|
|
15375
|
-
operations: { get: {}, wait: {} },
|
|
15376
|
-
platform: {
|
|
15377
|
-
status: {}
|
|
15378
|
-
},
|
|
15379
|
-
pm: {
|
|
15380
|
-
...PM_ENTITIES,
|
|
15381
|
-
project: { list: {}, add: {}, create: {}, use: {} },
|
|
15382
|
-
handoff: {},
|
|
15383
|
-
next: {},
|
|
15384
|
-
start: {},
|
|
15385
|
-
watch: {}
|
|
15386
|
-
},
|
|
15387
|
-
provision: {},
|
|
15388
|
-
runbook: {
|
|
15389
|
-
ask: {},
|
|
15390
|
-
search: {},
|
|
15391
|
-
impact: {},
|
|
15392
|
-
list: {},
|
|
15393
|
-
get: {},
|
|
15394
|
-
cat: {},
|
|
15395
|
-
new: {},
|
|
15396
|
-
edit: {},
|
|
15397
|
-
comment: {},
|
|
15398
|
-
import: {},
|
|
15399
|
-
visibility: {},
|
|
15400
|
-
publish: {},
|
|
15401
|
-
archive: {},
|
|
15402
|
-
history: {},
|
|
15403
|
-
revert: {},
|
|
15404
|
-
rm: {},
|
|
15405
|
-
lint: {}
|
|
15406
|
-
},
|
|
15407
|
-
secrets: { push: {}, status: {}, set: {}, "set-clerk-key": {} },
|
|
15408
|
-
security: {
|
|
15409
|
-
plan: {},
|
|
15410
|
-
sources: {},
|
|
15411
|
-
run: {},
|
|
15412
|
-
status: {},
|
|
15413
|
-
report: {},
|
|
15414
|
-
github: { connect: {}, disconnect: {} }
|
|
15415
|
-
},
|
|
15416
|
-
setup: {},
|
|
15417
|
-
skill: { install: {} },
|
|
15418
|
-
smoke: {},
|
|
15419
|
-
version: {},
|
|
15420
|
-
whoami: {}
|
|
15421
|
-
};
|
|
15422
|
-
}
|
|
15423
|
-
});
|
|
15424
|
-
|
|
15425
15540
|
// src/record.ts
|
|
15426
15541
|
function recordInvocation(parsed) {
|
|
15427
|
-
const file =
|
|
15542
|
+
const file = import_node_process19.default.env.ODLA_CLI_RECORD;
|
|
15428
15543
|
if (!file) return;
|
|
15429
15544
|
try {
|
|
15430
15545
|
const entry = {
|
|
@@ -15437,13 +15552,13 @@ function recordInvocation(parsed) {
|
|
|
15437
15552
|
} catch {
|
|
15438
15553
|
}
|
|
15439
15554
|
}
|
|
15440
|
-
var import_node_fs20,
|
|
15555
|
+
var import_node_fs20, import_node_process19;
|
|
15441
15556
|
var init_record = __esm({
|
|
15442
15557
|
"src/record.ts"() {
|
|
15443
15558
|
"use strict";
|
|
15444
15559
|
init_cjs_shims();
|
|
15445
15560
|
import_node_fs20 = require("fs");
|
|
15446
|
-
|
|
15561
|
+
import_node_process19 = __toESM(require("process"), 1);
|
|
15447
15562
|
init_surface();
|
|
15448
15563
|
}
|
|
15449
15564
|
});
|
|
@@ -15529,6 +15644,7 @@ async function deviceCommand(parsed, deps) {
|
|
|
15529
15644
|
"wait"
|
|
15530
15645
|
], 3);
|
|
15531
15646
|
const action2 = parsed.positionals[1] ?? "";
|
|
15647
|
+
if (!acceptedAfter(["device"]).includes(action2)) rejectWord(["device"], action2);
|
|
15532
15648
|
const out = deps.stdout ?? console;
|
|
15533
15649
|
const doFetch = deps.fetch ?? fetch;
|
|
15534
15650
|
const cfg = await loadProjectConfig(stringOpt(parsed.options.config));
|
|
@@ -15536,7 +15652,7 @@ async function deviceCommand(parsed, deps) {
|
|
|
15536
15652
|
if (action2 === "enroll") return enroll(parsed, deps, cfg, doFetch, out, json);
|
|
15537
15653
|
if (action2 === "list") return list2(parsed, deps, cfg, doFetch, out, json);
|
|
15538
15654
|
if (action2 === "revoke") return revoke(parsed, deps, cfg, doFetch, out, json);
|
|
15539
|
-
|
|
15655
|
+
rejectWord(["device"], action2);
|
|
15540
15656
|
}
|
|
15541
15657
|
async function enroll(parsed, deps, cfg, doFetch, out, json) {
|
|
15542
15658
|
const name = stringOpt(parsed.options.name) ?? defaultDeviceName();
|
|
@@ -15567,7 +15683,7 @@ async function enroll(parsed, deps, cfg, doFetch, out, json) {
|
|
|
15567
15683
|
headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
|
|
15568
15684
|
body: JSON.stringify({
|
|
15569
15685
|
name,
|
|
15570
|
-
platform:
|
|
15686
|
+
platform: import_node_process20.default.platform,
|
|
15571
15687
|
appIds: apps,
|
|
15572
15688
|
...capabilities ? { capabilities } : {},
|
|
15573
15689
|
...scopes ? { scopes } : {},
|
|
@@ -15579,7 +15695,7 @@ async function enroll(parsed, deps, cfg, doFetch, out, json) {
|
|
|
15579
15695
|
throw new Error(`device enroll failed: ${body.error?.message ?? `registry returned ${response2.status}`} (${response2.status})`);
|
|
15580
15696
|
}
|
|
15581
15697
|
const path = deviceCredentialPath();
|
|
15582
|
-
(0, import_node_fs21.mkdirSync)((0,
|
|
15698
|
+
(0, import_node_fs21.mkdirSync)((0, import_node_path20.dirname)(path), { recursive: true });
|
|
15583
15699
|
(0, import_node_fs21.writeFileSync)(path, JSON.stringify({
|
|
15584
15700
|
token: body.token,
|
|
15585
15701
|
platform: cfg.platformUrl.replace(/\/$/, ""),
|
|
@@ -15686,9 +15802,9 @@ async function scopedToken2(parsed, deps, cfg, doFetch, out, label, scope = "app
|
|
|
15686
15802
|
});
|
|
15687
15803
|
}
|
|
15688
15804
|
function defaultDeviceName() {
|
|
15689
|
-
return `${
|
|
15805
|
+
return `${import_node_process20.default.env.HOSTNAME ?? import_node_process20.default.env.HOST ?? "machine"}-${import_node_process20.default.platform}`;
|
|
15690
15806
|
}
|
|
15691
|
-
var import_db4, import_node_fs21,
|
|
15807
|
+
var import_db4, import_node_fs21, import_node_path20, import_node_process20;
|
|
15692
15808
|
var init_device_command = __esm({
|
|
15693
15809
|
"src/device-command.ts"() {
|
|
15694
15810
|
"use strict";
|
|
@@ -15699,13 +15815,14 @@ var init_device_command = __esm({
|
|
|
15699
15815
|
init_auth_guidance();
|
|
15700
15816
|
init_advisory_output();
|
|
15701
15817
|
import_node_fs21 = require("fs");
|
|
15702
|
-
|
|
15703
|
-
|
|
15818
|
+
import_node_path20 = require("path");
|
|
15819
|
+
import_node_process20 = __toESM(require("process"), 1);
|
|
15704
15820
|
init_argv();
|
|
15705
15821
|
init_admin_ai_auth();
|
|
15706
15822
|
init_device_session();
|
|
15707
15823
|
init_config();
|
|
15708
15824
|
init_operator_context();
|
|
15825
|
+
init_surface();
|
|
15709
15826
|
}
|
|
15710
15827
|
});
|
|
15711
15828
|
|
|
@@ -15886,8 +16003,8 @@ function readRunbookDir(dir) {
|
|
|
15886
16003
|
const files = (0, import_node_fs23.readdirSync)(dir).filter((f) => f.endsWith(".md")).sort();
|
|
15887
16004
|
if (!files.length) throw new Error(`no .md files in ${dir}`);
|
|
15888
16005
|
return files.map((file) => {
|
|
15889
|
-
const slug = (0,
|
|
15890
|
-
const parsed = parseRunbook((0, import_node_fs23.readFileSync)((0,
|
|
16006
|
+
const slug = (0, import_node_path21.basename)(file, ".md");
|
|
16007
|
+
const parsed = parseRunbook((0, import_node_fs23.readFileSync)((0, import_node_path21.join)(dir, file), "utf8"), slug);
|
|
15891
16008
|
return { file, slug, ...parsed, words: parsed.body.split(/\s+/).filter(Boolean).length };
|
|
15892
16009
|
});
|
|
15893
16010
|
}
|
|
@@ -15952,13 +16069,13 @@ async function upsert(ctx, r, visibility) {
|
|
|
15952
16069
|
);
|
|
15953
16070
|
return "updated";
|
|
15954
16071
|
}
|
|
15955
|
-
var import_node_fs23,
|
|
16072
|
+
var import_node_fs23, import_node_path21;
|
|
15956
16073
|
var init_runbook_import = __esm({
|
|
15957
16074
|
"src/runbook-import.ts"() {
|
|
15958
16075
|
"use strict";
|
|
15959
16076
|
init_cjs_shims();
|
|
15960
16077
|
import_node_fs23 = require("fs");
|
|
15961
|
-
|
|
16078
|
+
import_node_path21 = require("path");
|
|
15962
16079
|
init_runbook_actions();
|
|
15963
16080
|
}
|
|
15964
16081
|
});
|
|
@@ -16091,7 +16208,7 @@ var init_runbook_impact_scan = __esm({
|
|
|
16091
16208
|
|
|
16092
16209
|
// src/runbook-impact.ts
|
|
16093
16210
|
function gitRunner(cwd) {
|
|
16094
|
-
return (args) => (0,
|
|
16211
|
+
return (args) => (0, import_node_child_process7.execFileSync)("git", args, { cwd, encoding: "utf8", maxBuffer: 64 * 1024 * 1024, stdio: ["ignore", "pipe", "pipe"] });
|
|
16095
16212
|
}
|
|
16096
16213
|
function collectDiff(runGit, base, read3) {
|
|
16097
16214
|
let merged = "";
|
|
@@ -16136,7 +16253,7 @@ ${body.split("\n").map((line2) => `+${line2}`).join("\n")}
|
|
|
16136
16253
|
}
|
|
16137
16254
|
function manifestLabeller(root) {
|
|
16138
16255
|
return (workspace) => {
|
|
16139
|
-
const manifest = (0,
|
|
16256
|
+
const manifest = (0, import_node_path22.join)(root, workspace, "package.json");
|
|
16140
16257
|
if (!(0, import_node_fs24.existsSync)(manifest)) return void 0;
|
|
16141
16258
|
try {
|
|
16142
16259
|
const name = JSON.parse((0, import_node_fs24.readFileSync)(manifest, "utf8")).name;
|
|
@@ -16205,7 +16322,7 @@ function report4(ctx, impacts) {
|
|
|
16205
16322
|
async function runbookImpact(ctx, options, deps = {}) {
|
|
16206
16323
|
const cwd = deps.cwd ?? process.cwd();
|
|
16207
16324
|
const runGit = deps.runGit ?? gitRunner(cwd);
|
|
16208
|
-
const read3 = deps.readRepoFile ?? ((path) => (0, import_node_fs24.readFileSync)((0,
|
|
16325
|
+
const read3 = deps.readRepoFile ?? ((path) => (0, import_node_fs24.readFileSync)((0, import_node_path22.join)(cwd, path), "utf8"));
|
|
16209
16326
|
const surfaces = changedSurfaces(collectDiff(runGit, options.base, read3), manifestLabeller(cwd));
|
|
16210
16327
|
if (!surfaces.length) {
|
|
16211
16328
|
return ctx.out.log(
|
|
@@ -16216,14 +16333,14 @@ async function runbookImpact(ctx, options, deps = {}) {
|
|
|
16216
16333
|
if (ctx.json) return ctx.out.log(JSON.stringify({ base: options.base, impacts }, null, 2));
|
|
16217
16334
|
report4(ctx, impacts);
|
|
16218
16335
|
}
|
|
16219
|
-
var
|
|
16336
|
+
var import_node_child_process7, import_node_fs24, import_node_path22, SOURCE3, editHint;
|
|
16220
16337
|
var init_runbook_impact = __esm({
|
|
16221
16338
|
"src/runbook-impact.ts"() {
|
|
16222
16339
|
"use strict";
|
|
16223
16340
|
init_cjs_shims();
|
|
16224
|
-
|
|
16341
|
+
import_node_child_process7 = require("child_process");
|
|
16225
16342
|
import_node_fs24 = require("fs");
|
|
16226
|
-
|
|
16343
|
+
import_node_path22 = require("path");
|
|
16227
16344
|
init_runbook_impact_scan();
|
|
16228
16345
|
init_runbook_actions();
|
|
16229
16346
|
SOURCE3 = /\.(ts|tsx|js|jsx|mts|cts)$/;
|
|
@@ -16363,7 +16480,7 @@ var init_runbook_search_command = __esm({
|
|
|
16363
16480
|
});
|
|
16364
16481
|
|
|
16365
16482
|
// src/runbook-editor.ts
|
|
16366
|
-
function resolveEditor(env =
|
|
16483
|
+
function resolveEditor(env = import_node_process21.default.env) {
|
|
16367
16484
|
for (const name of EDITOR_ENV) {
|
|
16368
16485
|
const value2 = env[name];
|
|
16369
16486
|
if (value2 && value2.trim()) return value2.trim();
|
|
@@ -16372,13 +16489,13 @@ function resolveEditor(env = import_node_process20.default.env) {
|
|
|
16372
16489
|
}
|
|
16373
16490
|
function defaultRun(command, path) {
|
|
16374
16491
|
const [bin, ...args] = command.split(/\s+/);
|
|
16375
|
-
const result = (0,
|
|
16492
|
+
const result = (0, import_node_child_process8.spawnSync)(bin, [...args, path], { stdio: "inherit" });
|
|
16376
16493
|
if (result.error) throw new Error(`could not start editor "${command}": ${result.error.message}`);
|
|
16377
16494
|
return result.status ?? 0;
|
|
16378
16495
|
}
|
|
16379
16496
|
function editText(initial, slug, deps = {}) {
|
|
16380
|
-
const env = deps.env ??
|
|
16381
|
-
const interactive = deps.interactive ?? (() => Boolean(
|
|
16497
|
+
const env = deps.env ?? import_node_process21.default.env;
|
|
16498
|
+
const interactive = deps.interactive ?? (() => Boolean(import_node_process21.default.stdin.isTTY));
|
|
16382
16499
|
const editor = resolveEditor(env);
|
|
16383
16500
|
if (!editor)
|
|
16384
16501
|
throw new Error(
|
|
@@ -16386,8 +16503,8 @@ function editText(initial, slug, deps = {}) {
|
|
|
16386
16503
|
);
|
|
16387
16504
|
if (!interactive())
|
|
16388
16505
|
throw new Error(`cannot open an editor without a terminal \u2014 pass --file <path> or --body "\u2026" instead`);
|
|
16389
|
-
const dir = (0, import_node_fs25.mkdtempSync)((0,
|
|
16390
|
-
const file = (0,
|
|
16506
|
+
const dir = (0, import_node_fs25.mkdtempSync)((0, import_node_path23.join)((0, import_node_os6.tmpdir)(), "odla-runbook-"));
|
|
16507
|
+
const file = (0, import_node_path23.join)(dir, `${slug}.md`);
|
|
16391
16508
|
try {
|
|
16392
16509
|
(0, import_node_fs25.writeFileSync)(file, initial, { mode: 384 });
|
|
16393
16510
|
const code = defaultRunOrInjected(deps)(editor, file);
|
|
@@ -16398,16 +16515,16 @@ function editText(initial, slug, deps = {}) {
|
|
|
16398
16515
|
(0, import_node_fs25.rmSync)(dir, { recursive: true, force: true });
|
|
16399
16516
|
}
|
|
16400
16517
|
}
|
|
16401
|
-
var
|
|
16518
|
+
var import_node_child_process8, import_node_fs25, import_node_os6, import_node_path23, import_node_process21, EDITOR_ENV, defaultRunOrInjected;
|
|
16402
16519
|
var init_runbook_editor = __esm({
|
|
16403
16520
|
"src/runbook-editor.ts"() {
|
|
16404
16521
|
"use strict";
|
|
16405
16522
|
init_cjs_shims();
|
|
16406
|
-
|
|
16523
|
+
import_node_child_process8 = require("child_process");
|
|
16407
16524
|
import_node_fs25 = require("fs");
|
|
16408
16525
|
import_node_os6 = require("os");
|
|
16409
|
-
|
|
16410
|
-
|
|
16526
|
+
import_node_path23 = require("path");
|
|
16527
|
+
import_node_process21 = __toESM(require("process"), 1);
|
|
16411
16528
|
EDITOR_ENV = ["ODLA_EDITOR", "VISUAL", "EDITOR"];
|
|
16412
16529
|
defaultRunOrInjected = (deps) => deps.run ?? defaultRun;
|
|
16413
16530
|
}
|
|
@@ -16494,6 +16611,7 @@ async function buildContext3(parsed, deps, action2) {
|
|
|
16494
16611
|
async function runbookCommand(parsed, deps = {}) {
|
|
16495
16612
|
const action2 = parsed.positionals[1] ?? "list";
|
|
16496
16613
|
assertArgs(parsed, ALLOWED2, action2 === "ask" || action2 === "search" ? 64 : 4);
|
|
16614
|
+
if (!acceptedAfter(["runbook"]).includes(action2)) rejectWord(["runbook"], action2);
|
|
16497
16615
|
const ctx = await buildContext3(parsed, deps, action2);
|
|
16498
16616
|
const slug = parsed.positionals[2];
|
|
16499
16617
|
switch (action2) {
|
|
@@ -16583,7 +16701,7 @@ async function runbookCommand(parsed, deps = {}) {
|
|
|
16583
16701
|
case "rm":
|
|
16584
16702
|
return runbookRemove(ctx, requireSlug(slug, "rm"));
|
|
16585
16703
|
default:
|
|
16586
|
-
|
|
16704
|
+
rejectWord(["runbook"], action2);
|
|
16587
16705
|
}
|
|
16588
16706
|
}
|
|
16589
16707
|
var ALLOWED2, WRITES2;
|
|
@@ -16796,9 +16914,9 @@ async function runHostedSecurity(options) {
|
|
|
16796
16914
|
const appId = selfAudit ? "odla-ai" : cfg.app.id;
|
|
16797
16915
|
const env = selfAudit ? "prod" : selectEnv(options.env, cfg.envs, cfg.configPath, cfg.rootDir);
|
|
16798
16916
|
const platform = options.platform ?? cfg?.platformUrl ?? "https://odla.ai";
|
|
16799
|
-
const target = (0,
|
|
16800
|
-
const output = (0,
|
|
16801
|
-
const outputRelative = (0,
|
|
16917
|
+
const target = (0, import_node_path24.resolve)(options.target ?? cfg?.rootDir ?? ".");
|
|
16918
|
+
const output = (0, import_node_path24.resolve)(options.out ?? (0, import_node_path24.resolve)(target, ".odla/security/hosted"));
|
|
16919
|
+
const outputRelative = (0, import_node_path24.relative)(target, output).split(import_node_path24.sep).join("/");
|
|
16802
16920
|
if (!outputRelative) throw new Error("Hosted security output cannot be the repository root");
|
|
16803
16921
|
const profile = profileFor(options.profile ?? "odla", options.maxHuntTasks ?? 12);
|
|
16804
16922
|
const tokenRequest = {
|
|
@@ -16810,7 +16928,7 @@ async function runHostedSecurity(options) {
|
|
|
16810
16928
|
};
|
|
16811
16929
|
const token = await injectedToken(options, tokenRequest);
|
|
16812
16930
|
const snapshot = await (0, import_node3.snapshotDirectory)(target, {
|
|
16813
|
-
exclude: !outputRelative.startsWith("../") && !(0,
|
|
16931
|
+
exclude: !outputRelative.startsWith("../") && !(0, import_node_path24.isAbsolute)(outputRelative) ? [outputRelative] : []
|
|
16814
16932
|
});
|
|
16815
16933
|
const hosted = await (0, import_security.createPlatformSecurityReasoners)({
|
|
16816
16934
|
platform,
|
|
@@ -16828,7 +16946,7 @@ async function runHostedSecurity(options) {
|
|
|
16828
16946
|
});
|
|
16829
16947
|
const harness = (0, import_security.createSecurityHarness)({
|
|
16830
16948
|
profile,
|
|
16831
|
-
store: new import_node3.FileRunStore((0,
|
|
16949
|
+
store: new import_node3.FileRunStore((0, import_node_path24.resolve)(output, "state")),
|
|
16832
16950
|
discoveryReasoner: hosted.discoveryReasoner,
|
|
16833
16951
|
validationReasoner: hosted.validationReasoner,
|
|
16834
16952
|
policy: {
|
|
@@ -16852,7 +16970,7 @@ async function runHostedSecurity(options) {
|
|
|
16852
16970
|
function selectEnv(requested, declared, configPath, rootDir) {
|
|
16853
16971
|
const env = requested ?? (declared.includes("dev") ? "dev" : declared[0]);
|
|
16854
16972
|
if (!env || !declared.includes(env)) {
|
|
16855
|
-
const shown = (0,
|
|
16973
|
+
const shown = (0, import_node_path24.relative)(rootDir, configPath) || configPath;
|
|
16856
16974
|
throw new Error(`env "${env ?? ""}" is not declared in ${shown}`);
|
|
16857
16975
|
}
|
|
16858
16976
|
return env;
|
|
@@ -16881,17 +16999,17 @@ function printSummary(out, appId, env, run, report5, output) {
|
|
|
16881
16999
|
out.log(` coverage: ${report5.coverageStatus} ${complete}/${report5.coverage.length} blocked=${report5.metrics.blockedCells} shallow=${report5.metrics.shallowCells} unscheduled=${report5.metrics.unscheduledCells} budget_exhausted=${report5.metrics.budgetExhaustedCells}`);
|
|
16882
17000
|
if (report5.callBudget) out.log(` calls: discovery=${formatBudget(report5.callBudget.discovery)} validation=${formatBudget(report5.callBudget.validation)}`);
|
|
16883
17001
|
out.log(` findings: confirmed=${report5.metrics.confirmed} needs_reproduction=${report5.metrics.needsReproduction} candidates=${report5.metrics.candidates}`);
|
|
16884
|
-
out.log(` report: ${(0,
|
|
17002
|
+
out.log(` report: ${(0, import_node_path24.resolve)(output, "REPORT.md")}`);
|
|
16885
17003
|
}
|
|
16886
17004
|
function formatBudget(usage) {
|
|
16887
17005
|
return usage ? `${usage.usedCalls}/${usage.maxCalls} skipped=${usage.skippedCalls}` : "caller-managed";
|
|
16888
17006
|
}
|
|
16889
|
-
var
|
|
17007
|
+
var import_node_path24, import_security, import_node3;
|
|
16890
17008
|
var init_security = __esm({
|
|
16891
17009
|
"src/security.ts"() {
|
|
16892
17010
|
"use strict";
|
|
16893
17011
|
init_cjs_shims();
|
|
16894
|
-
|
|
17012
|
+
import_node_path24 = require("path");
|
|
16895
17013
|
import_security = require("@odla-ai/security");
|
|
16896
17014
|
import_node3 = require("@odla-ai/security/node");
|
|
16897
17015
|
init_config();
|
|
@@ -17292,9 +17410,7 @@ async function securityCommand(parsed, dependencies) {
|
|
|
17292
17410
|
else printHostedReport(context.stdout, report5);
|
|
17293
17411
|
return;
|
|
17294
17412
|
}
|
|
17295
|
-
if (sub !== "run")
|
|
17296
|
-
throw new Error('unknown security command. Try "odla-ai security plan", "security sources", or "security run".');
|
|
17297
|
-
}
|
|
17413
|
+
if (sub !== "run") rejectWord(["security"], sub);
|
|
17298
17414
|
const sourceId = stringOpt(parsed.options.source);
|
|
17299
17415
|
if (sourceId) await runSourceSecurityCommand(parsed, dependencies, sourceId);
|
|
17300
17416
|
else await runLocalSecurityCommand(parsed, dependencies);
|
|
@@ -17311,9 +17427,7 @@ async function githubSecurityCommand(parsed, dependencies) {
|
|
|
17311
17427
|
stringOpt(parsed.options.env)
|
|
17312
17428
|
);
|
|
17313
17429
|
}
|
|
17314
|
-
if (action2 !== "connect")
|
|
17315
|
-
throw new Error('unknown security github command. Try "odla-ai security github connect".');
|
|
17316
|
-
}
|
|
17430
|
+
if (action2 !== "connect") rejectWord(["security", "github"], action2);
|
|
17317
17431
|
assertArgs(parsed, ["config", "env", "platform", "repo", "email", "open"], 3);
|
|
17318
17432
|
await requireStudioHuman(
|
|
17319
17433
|
stringOpt(parsed.options.config) ?? "odla.config.mjs",
|
|
@@ -17369,6 +17483,7 @@ var init_security_command = __esm({
|
|
|
17369
17483
|
init_security_run_command();
|
|
17370
17484
|
init_security_hosted();
|
|
17371
17485
|
init_human_session();
|
|
17486
|
+
init_surface();
|
|
17372
17487
|
}
|
|
17373
17488
|
});
|
|
17374
17489
|
|
|
@@ -17393,6 +17508,11 @@ async function runCli(argv2 = process.argv.slice(2), dependencies = {}) {
|
|
|
17393
17508
|
throw error;
|
|
17394
17509
|
} finally {
|
|
17395
17510
|
renderAdvisories(out, advisories);
|
|
17511
|
+
try {
|
|
17512
|
+
const behind = updateNotice();
|
|
17513
|
+
if (behind) out.error(behind);
|
|
17514
|
+
} catch {
|
|
17515
|
+
}
|
|
17396
17516
|
}
|
|
17397
17517
|
}
|
|
17398
17518
|
async function dispatchCli(argv2, dependencies) {
|
|
@@ -17473,6 +17593,7 @@ async function dispatchCli(argv2, dependencies) {
|
|
|
17473
17593
|
}
|
|
17474
17594
|
if (command === "bug") {
|
|
17475
17595
|
const action2 = parsed.positionals[1] ?? "list";
|
|
17596
|
+
if (!acceptedAfter(["bug"]).includes(action2)) rejectWord(["bug"], action2);
|
|
17476
17597
|
const canonical2 = action2 === "report" || action2 === "create" ? "add" : action2;
|
|
17477
17598
|
await pmCommand({
|
|
17478
17599
|
...parsed,
|
|
@@ -17501,7 +17622,7 @@ async function dispatchCli(argv2, dependencies) {
|
|
|
17501
17622
|
return;
|
|
17502
17623
|
}
|
|
17503
17624
|
if (await projectCommand(command, parsed, runtime)) return;
|
|
17504
|
-
|
|
17625
|
+
rejectWord([], command);
|
|
17505
17626
|
}
|
|
17506
17627
|
async function provisionCommand(parsed, dependencies) {
|
|
17507
17628
|
assertArgs(parsed, [
|
|
@@ -17545,7 +17666,7 @@ async function provisionCommand(parsed, dependencies) {
|
|
|
17545
17666
|
async function calendarCommand(parsed, dependencies) {
|
|
17546
17667
|
const sub = parsed.positionals[1];
|
|
17547
17668
|
if (sub !== "status" && sub !== "calendars" && sub !== "connect" && sub !== "disconnect") {
|
|
17548
|
-
|
|
17669
|
+
rejectWord(["calendar"], sub);
|
|
17549
17670
|
}
|
|
17550
17671
|
assertArgs(parsed, ["config", "env", "json", "token", "email", "open", "yes"], 2);
|
|
17551
17672
|
if (sub !== "status" && sub !== "calendars" && parsed.options.json !== void 0) throw new Error(`--json is supported only by calendar status/calendars`);
|
|
@@ -17599,6 +17720,8 @@ var init_cli = __esm({
|
|
|
17599
17720
|
init_runbook_command();
|
|
17600
17721
|
init_security_command();
|
|
17601
17722
|
init_whoami_command();
|
|
17723
|
+
init_surface();
|
|
17724
|
+
init_update_notice();
|
|
17602
17725
|
init_exit_code();
|
|
17603
17726
|
}
|
|
17604
17727
|
});
|
|
@@ -17608,16 +17731,17 @@ init_cjs_shims();
|
|
|
17608
17731
|
|
|
17609
17732
|
// src/cli-update.ts
|
|
17610
17733
|
init_cjs_shims();
|
|
17611
|
-
var import_node_fs2 = require("fs");
|
|
17612
17734
|
init_runbook_requires();
|
|
17735
|
+
init_update_notice();
|
|
17613
17736
|
init_version();
|
|
17614
17737
|
var DEFAULT_REGISTRY_URL = "https://registry.npmjs.org/@odla-ai%2fcli/latest";
|
|
17615
|
-
var
|
|
17738
|
+
var VERSION2 = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
|
|
17616
17739
|
async function requireCurrentCliForProvision(argv2, options = {}) {
|
|
17617
17740
|
if (argv2[0] !== "provision" || argv2.includes("--dry-run")) return;
|
|
17618
17741
|
const current = options.currentVersion ?? cliVersion();
|
|
17619
|
-
if (!
|
|
17742
|
+
if (!VERSION2.test(current)) return;
|
|
17620
17743
|
const latest = await fetchLatestCliVersion(options);
|
|
17744
|
+
if (latest) rememberLatest(latest);
|
|
17621
17745
|
if (!latest || compareVersions(current, latest) >= 0) return;
|
|
17622
17746
|
const entryPath = resolvedEntryPath(options.entryPath ?? process.argv[1]);
|
|
17623
17747
|
const workspace = isWorkspaceCli(entryPath);
|
|
@@ -17646,25 +17770,19 @@ async function fetchLatestCliVersion(options) {
|
|
|
17646
17770
|
);
|
|
17647
17771
|
if (!response2.ok) return null;
|
|
17648
17772
|
const body = await response2.json();
|
|
17649
|
-
return typeof body.version === "string" &&
|
|
17773
|
+
return typeof body.version === "string" && VERSION2.test(body.version) ? body.version : null;
|
|
17650
17774
|
} catch {
|
|
17651
17775
|
return null;
|
|
17652
17776
|
} finally {
|
|
17653
17777
|
clearTimeout(timeout);
|
|
17654
17778
|
}
|
|
17655
17779
|
}
|
|
17656
|
-
function
|
|
17657
|
-
if (!entryPath) return "unknown executable";
|
|
17780
|
+
function rememberLatest(latest) {
|
|
17658
17781
|
try {
|
|
17659
|
-
|
|
17782
|
+
writeUpdateCache(updateCacheFile(), { latest, checkedAt: Date.now() });
|
|
17660
17783
|
} catch {
|
|
17661
|
-
return entryPath;
|
|
17662
17784
|
}
|
|
17663
17785
|
}
|
|
17664
|
-
function isWorkspaceCli(entryPath) {
|
|
17665
|
-
const normalized = entryPath.replaceAll("\\", "/");
|
|
17666
|
-
return normalized.includes("/packages/cli/dist/bin.") && !normalized.includes("/node_modules/");
|
|
17667
|
-
}
|
|
17668
17786
|
function renderReleasedProvisionCommand(latest, argv2) {
|
|
17669
17787
|
const safeArgs = [];
|
|
17670
17788
|
for (let index = 0; index < argv2.length; index++) {
|
|
@@ -17692,8 +17810,9 @@ function shellQuote(value2) {
|
|
|
17692
17810
|
// src/cli-runtime.ts
|
|
17693
17811
|
init_cjs_shims();
|
|
17694
17812
|
var import_node_module = require("module");
|
|
17695
|
-
var
|
|
17696
|
-
var
|
|
17813
|
+
var import_node_fs4 = require("fs");
|
|
17814
|
+
var import_node_path3 = require("path");
|
|
17815
|
+
init_update_notice();
|
|
17697
17816
|
init_version();
|
|
17698
17817
|
var EXACT_VERSION = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
|
|
17699
17818
|
var RUNTIME_MODULES = [
|
|
@@ -17752,26 +17871,26 @@ function installedRuntimeModules(entryPath) {
|
|
|
17752
17871
|
}));
|
|
17753
17872
|
}
|
|
17754
17873
|
function findPackageManifest(fromPath, expectedName) {
|
|
17755
|
-
let directory = (0,
|
|
17756
|
-
const root = (0,
|
|
17874
|
+
let directory = (0, import_node_path3.dirname)(resolvedEntryPath(fromPath));
|
|
17875
|
+
const root = (0, import_node_path3.parse)(directory).root;
|
|
17757
17876
|
while (true) {
|
|
17758
|
-
const path = (0,
|
|
17759
|
-
if ((0,
|
|
17877
|
+
const path = (0, import_node_path3.join)(directory, "package.json");
|
|
17878
|
+
if ((0, import_node_fs4.existsSync)(path)) {
|
|
17760
17879
|
try {
|
|
17761
|
-
const json = JSON.parse((0,
|
|
17880
|
+
const json = JSON.parse((0, import_node_fs4.readFileSync)(path, "utf8"));
|
|
17762
17881
|
if (json?.name === expectedName && typeof json.version === "string") return { path, json };
|
|
17763
17882
|
} catch {
|
|
17764
17883
|
}
|
|
17765
17884
|
}
|
|
17766
17885
|
if (directory === root) return void 0;
|
|
17767
|
-
directory = (0,
|
|
17886
|
+
directory = (0, import_node_path3.dirname)(directory);
|
|
17768
17887
|
}
|
|
17769
17888
|
}
|
|
17770
17889
|
function absoluteEntryPath(entryPath) {
|
|
17771
|
-
const candidate = entryPath || (0,
|
|
17772
|
-
const absolute = (0,
|
|
17890
|
+
const candidate = entryPath || (0, import_node_path3.join)(process.cwd(), "odla-ai-cli.js");
|
|
17891
|
+
const absolute = (0, import_node_path3.isAbsolute)(candidate) ? candidate : (0, import_node_path3.resolve)(candidate);
|
|
17773
17892
|
try {
|
|
17774
|
-
return (0,
|
|
17893
|
+
return (0, import_node_fs4.realpathSync)(absolute);
|
|
17775
17894
|
} catch {
|
|
17776
17895
|
return absolute;
|
|
17777
17896
|
}
|