@odla-ai/cli 0.39.0 → 0.40.1
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 +90 -35
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-PJ3RATDD.js → chunk-XUTMQMXZ.js} +86 -34
- package/dist/chunk-XUTMQMXZ.js.map +1 -0
- package/dist/{cli-ALS5OZPB.js → cli-WJSQEBDO.js} +2 -2
- package/dist/index.cjs +85 -33
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/skills/odla/SKILL.md +6 -5
- package/skills/odla/references/agent-identity.md +1 -1
- package/dist/chunk-PJ3RATDD.js.map +0 -1
- /package/dist/{cli-ALS5OZPB.js.map → cli-WJSQEBDO.js.map} +0 -0
package/dist/bin.cjs
CHANGED
|
@@ -403,6 +403,11 @@ var init_device_session = __esm({
|
|
|
403
403
|
|
|
404
404
|
// src/odla-home.ts
|
|
405
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
|
+
}
|
|
406
411
|
return env.ODLA_HOME ?? (0, import_node_path4.join)(env.HOME ?? (0, import_node_os2.homedir)(), ".odla");
|
|
407
412
|
}
|
|
408
413
|
function odlaHomePath(segments, env = import_node_process5.default.env) {
|
|
@@ -428,15 +433,15 @@ function pmContextFile(env) {
|
|
|
428
433
|
}
|
|
429
434
|
function adoptRepoLocalCache(legacyPath, machinePath, out) {
|
|
430
435
|
if (!(0, import_node_fs6.existsSync)(legacyPath) || legacyPath === machinePath) return false;
|
|
431
|
-
const
|
|
432
|
-
if (!
|
|
436
|
+
const superseded2 = (0, import_node_fs6.existsSync)(machinePath);
|
|
437
|
+
if (!superseded2) {
|
|
433
438
|
(0, import_node_fs6.mkdirSync)((0, import_node_path4.dirname)(machinePath), { recursive: true });
|
|
434
439
|
(0, import_node_fs6.copyFileSync)(legacyPath, machinePath);
|
|
435
440
|
(0, import_node_fs6.chmodSync)(machinePath, 384);
|
|
436
441
|
}
|
|
437
442
|
(0, import_node_fs6.rmSync)(legacyPath, { force: true });
|
|
438
443
|
out?.error(
|
|
439
|
-
|
|
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`
|
|
440
445
|
);
|
|
441
446
|
return true;
|
|
442
447
|
}
|
|
@@ -615,6 +620,20 @@ function scopeInterruptionNotice(scope, state2) {
|
|
|
615
620
|
platformScope ? " A platform scope needs an administrator's approval; an app owner's cannot carry it." : " One approval, every app you own, and it rolls forward while you keep working."
|
|
616
621
|
].join("\n");
|
|
617
622
|
}
|
|
623
|
+
function narrowEnrollmentNotice(envelope) {
|
|
624
|
+
const everyApp = envelope.appIds.includes("*");
|
|
625
|
+
if (everyApp && envelope.capabilities.length > 0 && envelope.scopes.length > 0) return null;
|
|
626
|
+
const missing = [
|
|
627
|
+
everyApp ? null : `only ${envelope.appIds.length} app${envelope.appIds.length === 1 ? "" : "s"} \u2014 a new one will need a new approval`,
|
|
628
|
+
envelope.capabilities.length ? null : "no optional capabilities \u2014 app.manage, crm.read and code.session are not included",
|
|
629
|
+
envelope.scopes.length ? null : "no platform scopes \u2014 runbook edits, config plans and host connect will each ask again"
|
|
630
|
+
].filter(Boolean);
|
|
631
|
+
return [
|
|
632
|
+
`odla: this is a NARROW enrollment: ${missing.join("; ")}.`,
|
|
633
|
+
" That is a fine choice if you meant it. If you did not, drop the flags:",
|
|
634
|
+
` ${ENROL_EVERYTHING}`
|
|
635
|
+
].join("\n");
|
|
636
|
+
}
|
|
618
637
|
function lapseNotice(state2, now = Date.now()) {
|
|
619
638
|
if (!state2.enrolled || !state2.lapsesAt) return null;
|
|
620
639
|
const days = Math.floor((state2.lapsesAt - now) / (24 * 60 * 60 * 1e3));
|
|
@@ -630,7 +649,7 @@ var init_auth_guidance = __esm({
|
|
|
630
649
|
init_device_session();
|
|
631
650
|
init_odla_home();
|
|
632
651
|
init_local();
|
|
633
|
-
ENROL_EVERYTHING = "npx odla-ai device enroll --
|
|
652
|
+
ENROL_EVERYTHING = "npx odla-ai device enroll --no-open --wait 600";
|
|
634
653
|
ENROL_PLATFORM_WIDE = "npx odla-ai device enroll --platform-wide --device-ttl 6w --no-open --wait 600";
|
|
635
654
|
}
|
|
636
655
|
});
|
|
@@ -2705,6 +2724,11 @@ async function authCommand(parsed, deps = {}) {
|
|
|
2705
2724
|
"auth login requires --email <odla-account> or ODLA_USER_EMAIL; confirm the signed-in odla email instead of using git or GitHub identity"
|
|
2706
2725
|
);
|
|
2707
2726
|
}
|
|
2727
|
+
if (!machineAuthState(platformAudience(cfg.platformUrl)).enrolled) {
|
|
2728
|
+
out.error("odla: this machine is not enrolled, so this approval buys one project until it lapses.");
|
|
2729
|
+
out.error(` For one approval that covers every app you own, with no repeats:
|
|
2730
|
+
${ENROL_EVERYTHING}`);
|
|
2731
|
+
}
|
|
2708
2732
|
const token = await getDeveloperToken(
|
|
2709
2733
|
cfg,
|
|
2710
2734
|
{
|
|
@@ -2742,6 +2766,7 @@ var init_auth_command = __esm({
|
|
|
2742
2766
|
init_argv();
|
|
2743
2767
|
init_operator_context();
|
|
2744
2768
|
init_token();
|
|
2769
|
+
init_auth_guidance();
|
|
2745
2770
|
init_whoami_command();
|
|
2746
2771
|
}
|
|
2747
2772
|
});
|
|
@@ -7890,7 +7915,7 @@ var init_code2 = __esm({
|
|
|
7890
7915
|
}
|
|
7891
7916
|
});
|
|
7892
7917
|
|
|
7893
|
-
// ../harness/dist/chunk-
|
|
7918
|
+
// ../harness/dist/chunk-L2T3LPEF.js
|
|
7894
7919
|
async function digestStagedWorkspace(root, limits) {
|
|
7895
7920
|
const files = [];
|
|
7896
7921
|
const walk = async (directory) => {
|
|
@@ -8107,6 +8132,7 @@ function parseSnapshot(value2) {
|
|
|
8107
8132
|
return { host, bindings, commands };
|
|
8108
8133
|
}
|
|
8109
8134
|
async function parseSource(value2) {
|
|
8135
|
+
const repositoryLimits = { maximumFiles: 1e5, maximumBytes: 80 * 1024 * 1024 };
|
|
8110
8136
|
const snapshot = record5(record5(value2)?.snapshot);
|
|
8111
8137
|
if (!snapshot || typeof snapshot.repository !== "string" || typeof snapshot.commitSha !== "string" || typeof snapshot.treeDigest !== "string" || !Array.isArray(snapshot.files)) throw invalid("source");
|
|
8112
8138
|
const files = snapshot.files.map((value22) => {
|
|
@@ -8128,12 +8154,12 @@ async function parseSource(value2) {
|
|
|
8128
8154
|
return { path: file.path, content: file.content };
|
|
8129
8155
|
});
|
|
8130
8156
|
const source2 = { repository: reference.repository, commitSha: reference.commitSha, files: referenceFiles };
|
|
8131
|
-
const referenceDigest = await digestCodeRepositorySnapshot(source2,
|
|
8157
|
+
const referenceDigest = await digestCodeRepositorySnapshot(source2, repositoryLimits);
|
|
8132
8158
|
if (referenceDigest !== reference.treeDigest) throw invalid("reference source digest");
|
|
8133
8159
|
references.push({ alias: reference.alias, ...source2, treeDigest: referenceDigest });
|
|
8134
8160
|
}
|
|
8135
8161
|
const source = { repository: snapshot.repository, commitSha: snapshot.commitSha, files };
|
|
8136
|
-
const digest = await digestCodeRepositorySnapshot(source,
|
|
8162
|
+
const digest = await digestCodeRepositorySnapshot(source, repositoryLimits);
|
|
8137
8163
|
if (digest !== snapshot.treeDigest) throw invalid("source digest");
|
|
8138
8164
|
return { ...source, treeDigest: digest, ...references.length ? { references } : {} };
|
|
8139
8165
|
}
|
|
@@ -8722,7 +8748,7 @@ async function prepareRuntimeLocalSource(input) {
|
|
|
8722
8748
|
return { workspace, sourceDigest: descriptor2.snapshotDigest, trustedBaseDigest };
|
|
8723
8749
|
}
|
|
8724
8750
|
async function materializeCodeRuntimeSource(snapshot, tempRoot = (0, import_os3.tmpdir)()) {
|
|
8725
|
-
if (!snapshot.files.length || snapshot.files.length >
|
|
8751
|
+
if (!snapshot.files.length || snapshot.files.length > SOURCE_MAX_FILES) throw new TypeError("Code source file count is invalid");
|
|
8726
8752
|
const root = await (0, import_promises8.mkdtemp)((0, import_path8.join)(tempRoot, "odla-code-source-"));
|
|
8727
8753
|
const sourceDir = (0, import_path8.join)(root, "source");
|
|
8728
8754
|
await (0, import_promises8.mkdir)(sourceDir);
|
|
@@ -8734,7 +8760,7 @@ async function materializeCodeRuntimeSource(snapshot, tempRoot = (0, import_os3.
|
|
|
8734
8760
|
if (seen.has(file.path)) throw new TypeError("Code source repeats a path");
|
|
8735
8761
|
seen.add(file.path);
|
|
8736
8762
|
bytes += Buffer.byteLength(file.path) + Buffer.byteLength(file.content);
|
|
8737
|
-
if (bytes >
|
|
8763
|
+
if (bytes > SOURCE_MAX_BYTES) throw new TypeError("Code source exceeds its byte bound");
|
|
8738
8764
|
const target = (0, import_path8.resolve)(sourceDir, file.path);
|
|
8739
8765
|
if (!target.startsWith(`${(0, import_path8.resolve)(sourceDir)}${import_path8.sep}`)) throw new TypeError("Code source path escapes its root");
|
|
8740
8766
|
await (0, import_promises8.mkdir)((0, import_path8.dirname)(target), { recursive: true });
|
|
@@ -8742,14 +8768,14 @@ async function materializeCodeRuntimeSource(snapshot, tempRoot = (0, import_os3.
|
|
|
8742
8768
|
}
|
|
8743
8769
|
for (const reference of snapshot.references ?? []) {
|
|
8744
8770
|
validateAlias(reference.alias);
|
|
8745
|
-
if (!reference.files.length || reference.files.length >
|
|
8771
|
+
if (!reference.files.length || reference.files.length > SOURCE_MAX_FILES) throw new TypeError("Code reference file count is invalid");
|
|
8746
8772
|
for (const file of reference.files) {
|
|
8747
8773
|
validatePath(file.path);
|
|
8748
8774
|
const path = `.odla-references/${reference.alias}/${file.path}`;
|
|
8749
8775
|
if (seen.has(path)) throw new TypeError("Code reference repeats a path");
|
|
8750
8776
|
seen.add(path);
|
|
8751
8777
|
bytes += Buffer.byteLength(path) + Buffer.byteLength(file.content);
|
|
8752
|
-
if (bytes >
|
|
8778
|
+
if (bytes > SOURCE_SET_MAX_BYTES) throw new TypeError("Code source set exceeds its byte bound");
|
|
8753
8779
|
const target = (0, import_path8.resolve)(sourceDir, path);
|
|
8754
8780
|
if (!target.startsWith(`${(0, import_path8.resolve)(sourceDir)}${import_path8.sep}`)) throw new TypeError("Code reference path escapes its root");
|
|
8755
8781
|
await (0, import_promises8.mkdir)((0, import_path8.dirname)(target), { recursive: true });
|
|
@@ -8775,7 +8801,7 @@ async function attachCodeRuntimeReferences(workspace, references) {
|
|
|
8775
8801
|
validatePath(file.path);
|
|
8776
8802
|
const path = `.odla-references/${reference.alias}/${file.path}`;
|
|
8777
8803
|
bytes += Buffer.byteLength(path) + Buffer.byteLength(file.content);
|
|
8778
|
-
if (bytes >
|
|
8804
|
+
if (bytes > SOURCE_SET_MAX_BYTES - SOURCE_MAX_BYTES) throw new TypeError("Code reference set exceeds its byte bound");
|
|
8779
8805
|
for (const root of [workspace.baselineDir, workspace.workspaceDir]) {
|
|
8780
8806
|
const target = (0, import_path8.resolve)(root, path);
|
|
8781
8807
|
if (!target.startsWith(`${(0, import_path8.resolve)(root)}${import_path8.sep}`)) throw new TypeError("Code reference path escapes its root");
|
|
@@ -8825,7 +8851,10 @@ async function materializeCommandWorkspace(input) {
|
|
|
8825
8851
|
trustedBaseDir: materialized.sourceDir,
|
|
8826
8852
|
trustedBaseCommitSha: source.commitSha,
|
|
8827
8853
|
checkpoint: codeCheckpointPayload(command.payload)
|
|
8828
|
-
})).workspace : await stageWorkspace(materialized.sourceDir
|
|
8854
|
+
})).workspace : await stageWorkspace(materialized.sourceDir, {
|
|
8855
|
+
maxFiles: SOURCE_MAX_FILES,
|
|
8856
|
+
maxBytes: SOURCE_SET_MAX_BYTES
|
|
8857
|
+
});
|
|
8829
8858
|
return { workspace, sourceDigest: source.treeDigest, requestedLocal: null };
|
|
8830
8859
|
} finally {
|
|
8831
8860
|
await materialized.cleanup();
|
|
@@ -9885,9 +9914,9 @@ async function appendCodeRuntimeEvent(control, command, event, refs) {
|
|
|
9885
9914
|
const bounded = event.type === "message" ? { ...event, body: event.body.trim().slice(0, 2e4) || `${event.actor} event` } : event;
|
|
9886
9915
|
await control.appendSessionEvent(command.sessionId, eventId, bounded);
|
|
9887
9916
|
}
|
|
9888
|
-
var import_crypto, import_promises5, import_path5, import_child_process4, import_promises6, import_path6, import_child_process5, import_process2, import_crypto2, import_crypto3, import_fs2, import_promises7, import_path7, import_promises8, import_os3, import_path8, import_ai4, import_promises9, import_path9, import_promises10, import_promises11, import_path10, import_crypto4, CODE_RUNTIME_PROTOCOL_VERSION, CodeRuntimeReconciler, CodeRuntimeControlError, record5, invalid, RESERVED, SECRET, PATH, FORBIDDEN, ARTIFACT_PATH, PRIVATE_ARTIFACT_PART, SHA3, DIGEST3, ID3, RULE, DEFAULT_PREFIXES, DEFAULT_SUFFIXES, message, CodeRuntimeCheckpointManager, record22, SOURCE_LIMITS, RESERVED2, SECRET2, V1_SYSTEM_PROMPT, V2_SYSTEM_PROMPT, V3_SYSTEM_PROMPT, SYSTEM_PROMPT_FOR, DEFAULT_MAX_FILES, DEFAULT_MAX_RESULTS, DEFAULT_MAX_FILE_BYTES, DESTINATIONS, READ, LIST, SEARCH, GRAPH, PATCH, RECIPE, cache, shortId, GRAPH_TOOLS, MAX_MEMORY_BODY, POSITIVE, digestRuntimeValue, runtimeErrorMessage, CodePiRuntimeEngine;
|
|
9889
|
-
var
|
|
9890
|
-
"../harness/dist/chunk-
|
|
9917
|
+
var import_crypto, import_promises5, import_path5, import_child_process4, import_promises6, import_path6, import_child_process5, import_process2, import_crypto2, import_crypto3, import_fs2, import_promises7, import_path7, import_promises8, import_os3, import_path8, import_ai4, import_promises9, import_path9, import_promises10, import_promises11, import_path10, import_crypto4, CODE_RUNTIME_PROTOCOL_VERSION, CodeRuntimeReconciler, CodeRuntimeControlError, record5, invalid, RESERVED, SECRET, PATH, FORBIDDEN, ARTIFACT_PATH, PRIVATE_ARTIFACT_PART, SHA3, DIGEST3, ID3, RULE, DEFAULT_PREFIXES, DEFAULT_SUFFIXES, message, CodeRuntimeCheckpointManager, record22, SOURCE_LIMITS, RESERVED2, SECRET2, SOURCE_MAX_FILES, SOURCE_MAX_BYTES, SOURCE_SET_MAX_BYTES, V1_SYSTEM_PROMPT, V2_SYSTEM_PROMPT, V3_SYSTEM_PROMPT, SYSTEM_PROMPT_FOR, DEFAULT_MAX_FILES, DEFAULT_MAX_RESULTS, DEFAULT_MAX_FILE_BYTES, DESTINATIONS, READ, LIST, SEARCH, GRAPH, PATCH, RECIPE, cache, shortId, GRAPH_TOOLS, MAX_MEMORY_BODY, POSITIVE, digestRuntimeValue, runtimeErrorMessage, CodePiRuntimeEngine;
|
|
9918
|
+
var init_chunk_L2T3LPEF = __esm({
|
|
9919
|
+
"../harness/dist/chunk-L2T3LPEF.js"() {
|
|
9891
9920
|
"use strict";
|
|
9892
9921
|
init_cjs_shims();
|
|
9893
9922
|
init_chunk_K76I2TCQ();
|
|
@@ -10027,6 +10056,9 @@ var init_chunk_UVGZHNLW = __esm({
|
|
|
10027
10056
|
SOURCE_LIMITS = { maxFiles: 2e4, maxBytes: 512 * 1024 * 1024 };
|
|
10028
10057
|
RESERVED2 = /* @__PURE__ */ new Set([".git", ".odla", ".wrangler", "node_modules", "dist", "coverage"]);
|
|
10029
10058
|
SECRET2 = /^(?:\.env(?:\..+)?|\.dev\.vars|credentials(?:\..+)?\.json|dev-token(?:\..+)?\.json)$/i;
|
|
10059
|
+
SOURCE_MAX_FILES = 1e5;
|
|
10060
|
+
SOURCE_MAX_BYTES = 80 * 1024 * 1024;
|
|
10061
|
+
SOURCE_SET_MAX_BYTES = 480 * 1024 * 1024;
|
|
10030
10062
|
V1_SYSTEM_PROMPT = `You are Pi, the coding agent inside an odla Code harness.
|
|
10031
10063
|
Use only the odla_read, odla_apply_git_diff, and odla_run_recipe tools.
|
|
10032
10064
|
For mutations, call odla_apply_git_diff with raw git diff text. It must start
|
|
@@ -10406,7 +10438,7 @@ var init_node = __esm({
|
|
|
10406
10438
|
"../harness/dist/node.js"() {
|
|
10407
10439
|
"use strict";
|
|
10408
10440
|
init_cjs_shims();
|
|
10409
|
-
|
|
10441
|
+
init_chunk_L2T3LPEF();
|
|
10410
10442
|
init_chunk_K76I2TCQ();
|
|
10411
10443
|
MEASURED_PREMIUM = Object.freeze({
|
|
10412
10444
|
/** 3 racers vs pure depth at equal budget: 21,044 / 7,936. */
|
|
@@ -11397,13 +11429,16 @@ var init_help_usage = __esm({
|
|
|
11397
11429
|
init_cjs_shims();
|
|
11398
11430
|
AUTH_SECTION = `
|
|
11399
11431
|
Enrol this machine once, then stop asking:
|
|
11400
|
-
npx odla-ai device enroll --
|
|
11401
|
-
One browser approval
|
|
11402
|
-
own
|
|
11403
|
-
|
|
11404
|
-
|
|
11405
|
-
|
|
11406
|
-
|
|
11432
|
+
npx odla-ai device enroll --no-open --wait 600
|
|
11433
|
+
One browser approval, and no flags to remember: this covers every app you
|
|
11434
|
+
own \u2014 including apps you create later \u2014 with every capability that
|
|
11435
|
+
approval can carry. Afterwards every worktree on this machine mints its
|
|
11436
|
+
own short-lived credentials with nobody's attention. The window rolls
|
|
11437
|
+
forward each time you use it, so continuous work never interrupts anyone;
|
|
11438
|
+
only a real gap does. Give the human the printed /studio?code= URL, keep
|
|
11439
|
+
the process alive, and wait on it.
|
|
11440
|
+
Narrow it deliberately with --app <id> or --capability <c>; the CLI then
|
|
11441
|
+
says what that gave up.
|
|
11407
11442
|
|
|
11408
11443
|
npx odla-ai device enroll --platform-wide --device-ttl 6w --no-open --wait 600
|
|
11409
11444
|
The same thing across all of odla, for weeks. Needs a platform
|
|
@@ -11546,7 +11581,7 @@ Usage:
|
|
|
11546
11581
|
odla-ai security run [target] --ack-redacted-source [--env dev] [--profile odla] [--fail-on high]
|
|
11547
11582
|
odla-ai security run [target] --self --ack-redacted-source
|
|
11548
11583
|
odla-ai provision [--live] [--config odla.config.mjs] [--email <odla-account>] [--request-grant] [--no-open] [--wait <seconds>] [--dry-run] [--push-secrets] [--rotate-o11y-token] [--write-dev-vars[=path]] [--yes]
|
|
11549
|
-
odla-ai device enroll [--
|
|
11584
|
+
odla-ai device enroll [--app <id>[,<id>...]|--all-apps] [--capability all|<c>[,<c>...]] [--platform-wide]
|
|
11550
11585
|
[--name <label>] [--device-ttl <30d|6w|2y|forever>] [--email <odla-account>] [--no-open] [--wait <seconds>] [--json]
|
|
11551
11586
|
odla-ai device list [--email <odla-account>] [--json]
|
|
11552
11587
|
odla-ai device revoke <device-id> [--email <odla-account>] [--json]
|
|
@@ -11674,11 +11709,13 @@ Commands:
|
|
|
11674
11709
|
enrollment in the browser; from then on EVERY worktree on this
|
|
11675
11710
|
machine mints its own short-lived credentials with nobody's
|
|
11676
11711
|
attention, until the device is revoked or goes unused.
|
|
11677
|
-
|
|
11678
|
-
|
|
11679
|
-
|
|
11680
|
-
|
|
11681
|
-
|
|
11712
|
+
With no flags it covers every app you own, now and later, with
|
|
11713
|
+
every capability that approval can carry \u2014 so creating an app
|
|
11714
|
+
costs no new approval, and a capability nobody thought to name is
|
|
11715
|
+
not a 403 next week. "--app" or "--capability" narrow it
|
|
11716
|
+
deliberately, and the CLI says what that gave up.
|
|
11717
|
+
"--platform-wide" is the administrator's version, across all of
|
|
11718
|
+
odla.
|
|
11682
11719
|
The expiry is a GAP, not a clock: each use rolls it forward, so
|
|
11683
11720
|
only going quiet brings a human back into the loop \u2014 which is
|
|
11684
11721
|
where anything that changed can be explained.
|
|
@@ -14988,22 +15025,29 @@ function advisoryCollectingFetch(inner, sink) {
|
|
|
14988
15025
|
return response2;
|
|
14989
15026
|
});
|
|
14990
15027
|
}
|
|
15028
|
+
function supersedeAdvisory(code) {
|
|
15029
|
+
superseded.add(code);
|
|
15030
|
+
}
|
|
14991
15031
|
function renderAdvisories(out, advisories, env = process.env) {
|
|
15032
|
+
const retracted = new Set(superseded);
|
|
15033
|
+
superseded.clear();
|
|
14992
15034
|
if (env.ODLA_NO_ADVISORIES) return;
|
|
14993
15035
|
const seen = /* @__PURE__ */ new Set();
|
|
14994
15036
|
for (const advisory of advisories) {
|
|
15037
|
+
if (retracted.has(advisory.code)) continue;
|
|
14995
15038
|
const key = `${advisory.code}:${advisory.message}`;
|
|
14996
15039
|
if (seen.has(key)) continue;
|
|
14997
15040
|
seen.add(key);
|
|
14998
15041
|
out.error((0, import_apps14.formatAdvisory)(advisory));
|
|
14999
15042
|
}
|
|
15000
15043
|
}
|
|
15001
|
-
var import_apps14;
|
|
15044
|
+
var import_apps14, superseded;
|
|
15002
15045
|
var init_advisory_output = __esm({
|
|
15003
15046
|
"src/advisory-output.ts"() {
|
|
15004
15047
|
"use strict";
|
|
15005
15048
|
init_cjs_shims();
|
|
15006
15049
|
import_apps14 = require("@odla-ai/apps");
|
|
15050
|
+
superseded = /* @__PURE__ */ new Set();
|
|
15007
15051
|
}
|
|
15008
15052
|
});
|
|
15009
15053
|
|
|
@@ -15063,11 +15107,18 @@ async function deviceCommand(parsed, deps) {
|
|
|
15063
15107
|
async function enroll(parsed, deps, cfg, doFetch, out, json) {
|
|
15064
15108
|
const name = stringOpt(parsed.options.name) ?? defaultDeviceName();
|
|
15065
15109
|
const platformWide = parsed.options["platform-wide"] === true;
|
|
15066
|
-
const
|
|
15110
|
+
const narrowed = stringOpt(parsed.options.app) !== void 0 || stringOpt(parsed.options.capability) !== void 0;
|
|
15111
|
+
const apps = platformWide || parsed.options["all-apps"] === true || !narrowed ? [import_db4.ALL_OWNED_APPS] : (stringOpt(parsed.options.app) ?? cfg.app.id).split(",").map((id2) => id2.trim()).filter(Boolean);
|
|
15067
15112
|
if (apps.length === 0) throw new Error("device enroll needs --app <id>[,<id>\u2026], or --all-apps");
|
|
15068
15113
|
const deviceTtlMs = parseDeviceTtl(parsed.options["device-ttl"]);
|
|
15069
15114
|
const extended = platformWide || deviceTtlMs !== void 0 && deviceTtlMs > OWNER_DEVICE_TTL_MS;
|
|
15070
|
-
const { capabilities, scopes } = requestedEnvelope(parsed, platformWide);
|
|
15115
|
+
const { capabilities, scopes } = requestedEnvelope(parsed, platformWide, narrowed);
|
|
15116
|
+
const narrowNotice = narrowEnrollmentNotice({
|
|
15117
|
+
appIds: apps,
|
|
15118
|
+
capabilities: capabilities ?? [],
|
|
15119
|
+
scopes: scopes ?? []
|
|
15120
|
+
});
|
|
15121
|
+
if (narrowNotice) out.error(narrowNotice);
|
|
15071
15122
|
const token = await scopedToken2(
|
|
15072
15123
|
parsed,
|
|
15073
15124
|
deps,
|
|
@@ -15103,8 +15154,10 @@ async function enroll(parsed, deps, cfg, doFetch, out, json) {
|
|
|
15103
15154
|
}, null, 2));
|
|
15104
15155
|
(0, import_node_fs21.chmodSync)(path, 384);
|
|
15105
15156
|
rememberMachineIdentity(cfg.platformUrl.replace(/\/$/, ""), stringOpt(parsed.options.email));
|
|
15157
|
+
supersedeAdvisory("credential.expiring");
|
|
15106
15158
|
const reach = body.device.appIds.includes(import_db4.ALL_OWNED_APPS) ? "every app you own, now and later" : body.device.appIds.join(", ");
|
|
15107
15159
|
out.error(`device: enrolled "${name}" for ${reach}; credential written to ${path}`);
|
|
15160
|
+
if (narrowNotice) out.error(narrowNotice);
|
|
15108
15161
|
out.error(
|
|
15109
15162
|
"device: every worktree on this machine mints its own credentials from now on \u2014 no further approvals,"
|
|
15110
15163
|
);
|
|
@@ -15123,9 +15176,9 @@ async function enroll(parsed, deps, cfg, doFetch, out, json) {
|
|
|
15123
15176
|
}, null, 2));
|
|
15124
15177
|
}
|
|
15125
15178
|
}
|
|
15126
|
-
function requestedEnvelope(parsed, platformWide) {
|
|
15179
|
+
function requestedEnvelope(parsed, platformWide, narrowed) {
|
|
15127
15180
|
const raw = stringOpt(parsed.options.capability);
|
|
15128
|
-
const everything = platformWide || raw?.trim().toLowerCase() === "all";
|
|
15181
|
+
const everything = platformWide || !narrowed || raw?.trim().toLowerCase() === "all";
|
|
15129
15182
|
if (everything) {
|
|
15130
15183
|
return {
|
|
15131
15184
|
capabilities: [...import_db4.OPTIONAL_AGENT_PROJECT_CAPABILITIES],
|
|
@@ -15209,6 +15262,8 @@ var init_device_command = __esm({
|
|
|
15209
15262
|
import_db4 = require("@odla-ai/db");
|
|
15210
15263
|
init_device_ttl();
|
|
15211
15264
|
init_machine_identity();
|
|
15265
|
+
init_auth_guidance();
|
|
15266
|
+
init_advisory_output();
|
|
15212
15267
|
import_node_fs21 = require("fs");
|
|
15213
15268
|
import_node_path19 = require("path");
|
|
15214
15269
|
import_node_process19 = __toESM(require("process"), 1);
|