@odla-ai/cli 0.43.0 → 0.44.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/README.md +10 -4
- package/dist/bin.cjs +537 -396
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-WDWJ7HC7.js → chunk-7MUWCSGP.js} +517 -399
- package/dist/chunk-7MUWCSGP.js.map +1 -0
- package/dist/{cli-OITEPXW4.js → cli-ZQBZT6YF.js} +2 -2
- package/dist/index.cjs +510 -392
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/skills/odla/SKILL.md +10 -3
- package/skills/odla/references/pm-work-intake.md +33 -11
- package/skills/odla/references/pm.md +23 -12
- package/dist/chunk-WDWJ7HC7.js.map +0 -1
- /package/dist/{cli-OITEPXW4.js.map → cli-ZQBZT6YF.js.map} +0 -0
package/dist/bin.cjs
CHANGED
|
@@ -556,10 +556,10 @@ function isManagedDevVar(line2) {
|
|
|
556
556
|
const match = line2.match(/^\s*(?:export\s+)?([A-Z][A-Z0-9_]*)\s*=/);
|
|
557
557
|
return !!match?.[1] && MANAGED_DEV_VARS.has(match[1]);
|
|
558
558
|
}
|
|
559
|
-
function writePrivateText(path,
|
|
559
|
+
function writePrivateText(path, text4) {
|
|
560
560
|
(0, import_node_fs7.mkdirSync)((0, import_node_path5.dirname)(path), { recursive: true });
|
|
561
561
|
const temporary = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
562
|
-
(0, import_node_fs7.writeFileSync)(temporary,
|
|
562
|
+
(0, import_node_fs7.writeFileSync)(temporary, text4, { mode: 384 });
|
|
563
563
|
(0, import_node_fs7.chmodSync)(temporary, 384);
|
|
564
564
|
(0, import_node_fs7.renameSync)(temporary, path);
|
|
565
565
|
}
|
|
@@ -1105,12 +1105,12 @@ async function readAdminAiAudit(request3) {
|
|
|
1105
1105
|
}
|
|
1106
1106
|
}
|
|
1107
1107
|
async function responseBody(response2) {
|
|
1108
|
-
const
|
|
1109
|
-
if (!
|
|
1108
|
+
const text4 = await response2.text();
|
|
1109
|
+
if (!text4) return {};
|
|
1110
1110
|
try {
|
|
1111
|
-
return JSON.parse(
|
|
1111
|
+
return JSON.parse(text4);
|
|
1112
1112
|
} catch {
|
|
1113
|
-
return { message:
|
|
1113
|
+
return { message: text4.slice(0, 300) };
|
|
1114
1114
|
}
|
|
1115
1115
|
}
|
|
1116
1116
|
function apiError(status, body) {
|
|
@@ -1226,12 +1226,12 @@ function timestamp2(value2) {
|
|
|
1226
1226
|
return Number.isFinite(date.valueOf()) ? date.toISOString() : "";
|
|
1227
1227
|
}
|
|
1228
1228
|
async function responseBody2(res) {
|
|
1229
|
-
const
|
|
1230
|
-
if (!
|
|
1229
|
+
const text4 = await res.text();
|
|
1230
|
+
if (!text4) return {};
|
|
1231
1231
|
try {
|
|
1232
|
-
return JSON.parse(
|
|
1232
|
+
return JSON.parse(text4);
|
|
1233
1233
|
} catch {
|
|
1234
|
-
return { message:
|
|
1234
|
+
return { message: text4.slice(0, 300) };
|
|
1235
1235
|
}
|
|
1236
1236
|
}
|
|
1237
1237
|
function apiError2(action2, status, body) {
|
|
@@ -1414,12 +1414,12 @@ function catalogModels(body) {
|
|
|
1414
1414
|
return body.catalog.models.filter((value2) => isRecord3(value2) && typeof value2.id === "string" && typeof value2.provider === "string");
|
|
1415
1415
|
}
|
|
1416
1416
|
async function responseBody3(res) {
|
|
1417
|
-
const
|
|
1418
|
-
if (!
|
|
1417
|
+
const text4 = await res.text();
|
|
1418
|
+
if (!text4) return {};
|
|
1419
1419
|
try {
|
|
1420
|
-
return JSON.parse(
|
|
1420
|
+
return JSON.parse(text4);
|
|
1421
1421
|
} catch {
|
|
1422
|
-
return { message:
|
|
1422
|
+
return { message: text4.slice(0, 300) };
|
|
1423
1423
|
}
|
|
1424
1424
|
}
|
|
1425
1425
|
function apiError3(action2, status, body) {
|
|
@@ -1480,10 +1480,17 @@ function parseArgv(argv2) {
|
|
|
1480
1480
|
function assertArgs(parsed, allowedOptions2, maxPositionals) {
|
|
1481
1481
|
const allowed = new Set(allowedOptions2);
|
|
1482
1482
|
for (const name of Object.keys(parsed.options)) {
|
|
1483
|
-
if (
|
|
1483
|
+
if (allowed.has(name)) continue;
|
|
1484
|
+
const accepts = [...allowed].sort().map((option) => `--${option}`).join(" ");
|
|
1485
|
+
throw new Error(
|
|
1486
|
+
`unknown option "--${name}"` + (accepts ? ` \u2014 this command accepts: ${accepts}` : " \u2014 this command takes no options")
|
|
1487
|
+
);
|
|
1484
1488
|
}
|
|
1485
1489
|
if (parsed.positionals.length > maxPositionals) {
|
|
1486
|
-
|
|
1490
|
+
const taken = parsed.positionals.slice(0, maxPositionals).join(" ");
|
|
1491
|
+
throw new Error(
|
|
1492
|
+
`unexpected argument "${parsed.positionals[maxPositionals]}" \u2014 ` + (maxPositionals ? `"odla-ai ${taken}" takes no further arguments` : "this command takes no arguments")
|
|
1493
|
+
);
|
|
1487
1494
|
}
|
|
1488
1495
|
}
|
|
1489
1496
|
function requiredString(value2, name) {
|
|
@@ -1527,6 +1534,196 @@ var init_argv = __esm({
|
|
|
1527
1534
|
}
|
|
1528
1535
|
});
|
|
1529
1536
|
|
|
1537
|
+
// src/surface.ts
|
|
1538
|
+
function acceptedAfter(path) {
|
|
1539
|
+
let node = COMMAND_SURFACE;
|
|
1540
|
+
for (const word of path) {
|
|
1541
|
+
node = node?.[word];
|
|
1542
|
+
if (!node) return [];
|
|
1543
|
+
}
|
|
1544
|
+
return Object.keys(node).sort();
|
|
1545
|
+
}
|
|
1546
|
+
function validateInvocation(words2) {
|
|
1547
|
+
let node = COMMAND_SURFACE;
|
|
1548
|
+
const walked = [];
|
|
1549
|
+
for (const word of words2) {
|
|
1550
|
+
if (Object.keys(node).length === 0) return null;
|
|
1551
|
+
const next = node[word];
|
|
1552
|
+
if (!next) return { validPrefix: walked.join(" "), word, accepted: Object.keys(node).sort() };
|
|
1553
|
+
walked.push(word);
|
|
1554
|
+
node = next;
|
|
1555
|
+
}
|
|
1556
|
+
return null;
|
|
1557
|
+
}
|
|
1558
|
+
function describeProblem(problem) {
|
|
1559
|
+
const where = problem.validPrefix ? `after "${problem.validPrefix}"` : "as a command";
|
|
1560
|
+
if (!problem.accepted.length) return `"${problem.word}" is not accepted ${where}. Run "odla-ai help"`;
|
|
1561
|
+
if (!problem.word) return `"odla-ai ${problem.validPrefix}" needs one of: ${problem.accepted.join(", ")}`;
|
|
1562
|
+
return `"${problem.word}" is not accepted ${where} \u2014 try: ${problem.accepted.join(", ")}`;
|
|
1563
|
+
}
|
|
1564
|
+
function rejectWord(path, word, note) {
|
|
1565
|
+
const sentence = describeProblem({
|
|
1566
|
+
validPrefix: path.join(" "),
|
|
1567
|
+
word: word ?? "",
|
|
1568
|
+
accepted: acceptedAfter(path)
|
|
1569
|
+
});
|
|
1570
|
+
throw new Error(note ? `${sentence}. ${note}` : sentence);
|
|
1571
|
+
}
|
|
1572
|
+
function invocationPath(words2) {
|
|
1573
|
+
let node = COMMAND_SURFACE;
|
|
1574
|
+
const path = [];
|
|
1575
|
+
for (const word of words2) {
|
|
1576
|
+
const next = node[word];
|
|
1577
|
+
if (!next) break;
|
|
1578
|
+
path.push(word);
|
|
1579
|
+
node = next;
|
|
1580
|
+
if (Object.keys(node).length === 0) break;
|
|
1581
|
+
}
|
|
1582
|
+
return path;
|
|
1583
|
+
}
|
|
1584
|
+
var PM_ACTIONS, PM_TASK_ACTIONS, PM_ENTITIES, COMMAND_SURFACE;
|
|
1585
|
+
var init_surface = __esm({
|
|
1586
|
+
"src/surface.ts"() {
|
|
1587
|
+
"use strict";
|
|
1588
|
+
init_cjs_shims();
|
|
1589
|
+
PM_ACTIONS = {
|
|
1590
|
+
list: {},
|
|
1591
|
+
add: {},
|
|
1592
|
+
create: {},
|
|
1593
|
+
get: {},
|
|
1594
|
+
set: {},
|
|
1595
|
+
update: {},
|
|
1596
|
+
status: {},
|
|
1597
|
+
move: {},
|
|
1598
|
+
done: {},
|
|
1599
|
+
comment: {},
|
|
1600
|
+
comments: {},
|
|
1601
|
+
history: {},
|
|
1602
|
+
link: {},
|
|
1603
|
+
ref: {},
|
|
1604
|
+
rm: {},
|
|
1605
|
+
delete: {}
|
|
1606
|
+
};
|
|
1607
|
+
PM_TASK_ACTIONS = {
|
|
1608
|
+
...PM_ACTIONS,
|
|
1609
|
+
ready: {},
|
|
1610
|
+
claim: {},
|
|
1611
|
+
release: {}
|
|
1612
|
+
};
|
|
1613
|
+
PM_ENTITIES = {
|
|
1614
|
+
...Object.fromEntries(
|
|
1615
|
+
["goal", "conformance", "decision", "bug"].map((entity) => [entity, PM_ACTIONS])
|
|
1616
|
+
),
|
|
1617
|
+
task: PM_TASK_ACTIONS,
|
|
1618
|
+
kanban: PM_TASK_ACTIONS
|
|
1619
|
+
};
|
|
1620
|
+
COMMAND_SURFACE = {
|
|
1621
|
+
agent: { jobs: {}, retry: {} },
|
|
1622
|
+
ai: { models: {} },
|
|
1623
|
+
admin: {
|
|
1624
|
+
ai: {
|
|
1625
|
+
show: {},
|
|
1626
|
+
set: {},
|
|
1627
|
+
credentials: {},
|
|
1628
|
+
models: {},
|
|
1629
|
+
usage: {},
|
|
1630
|
+
audit: {},
|
|
1631
|
+
credential: { set: {} }
|
|
1632
|
+
},
|
|
1633
|
+
spend: { show: {}, reset: {} }
|
|
1634
|
+
},
|
|
1635
|
+
app: {
|
|
1636
|
+
archive: {},
|
|
1637
|
+
restore: {},
|
|
1638
|
+
export: {},
|
|
1639
|
+
import: {},
|
|
1640
|
+
rename: {},
|
|
1641
|
+
"refresh-sandbox": {},
|
|
1642
|
+
"go-live": {},
|
|
1643
|
+
promote: {},
|
|
1644
|
+
owners: { list: {}, add: {}, remove: {} }
|
|
1645
|
+
},
|
|
1646
|
+
auth: { login: {} },
|
|
1647
|
+
brand: { design: { unpack: {} } },
|
|
1648
|
+
bug: { create: {}, list: {}, report: {} },
|
|
1649
|
+
calendar: { status: {}, calendars: {}, connect: {}, disconnect: {} },
|
|
1650
|
+
capabilities: {},
|
|
1651
|
+
code: {
|
|
1652
|
+
connect: {},
|
|
1653
|
+
grant: { request: {}, list: {}, approve: {}, revoke: {} },
|
|
1654
|
+
repository: { show: {}, list: {}, bind: {} }
|
|
1655
|
+
},
|
|
1656
|
+
config: { diff: {}, plan: {}, apply: {} },
|
|
1657
|
+
context: { show: {}, list: {}, save: {}, remove: {} },
|
|
1658
|
+
credentials: { list: {}, revoke: {} },
|
|
1659
|
+
device: { enroll: {}, list: {}, revoke: {} },
|
|
1660
|
+
// `watch`, `read`, `reply`, and `resolve` take a topic id from there on.
|
|
1661
|
+
discuss: {
|
|
1662
|
+
groups: {},
|
|
1663
|
+
list: {},
|
|
1664
|
+
topics: {},
|
|
1665
|
+
read: {},
|
|
1666
|
+
post: {},
|
|
1667
|
+
reply: {},
|
|
1668
|
+
resolve: {},
|
|
1669
|
+
who: {},
|
|
1670
|
+
watch: {}
|
|
1671
|
+
},
|
|
1672
|
+
doctor: {},
|
|
1673
|
+
help: {},
|
|
1674
|
+
init: {},
|
|
1675
|
+
monitor: { plan: {}, apply: {}, run: {}, status: {}, incidents: {}, report: {} },
|
|
1676
|
+
o11y: { status: {} },
|
|
1677
|
+
operations: { get: {}, wait: {} },
|
|
1678
|
+
platform: {
|
|
1679
|
+
status: {}
|
|
1680
|
+
},
|
|
1681
|
+
pm: {
|
|
1682
|
+
...PM_ENTITIES,
|
|
1683
|
+
project: { list: {}, add: {}, create: {}, use: {} },
|
|
1684
|
+
handoff: {},
|
|
1685
|
+
next: {},
|
|
1686
|
+
start: {},
|
|
1687
|
+
watch: {}
|
|
1688
|
+
},
|
|
1689
|
+
provision: {},
|
|
1690
|
+
runbook: {
|
|
1691
|
+
ask: {},
|
|
1692
|
+
search: {},
|
|
1693
|
+
impact: {},
|
|
1694
|
+
list: {},
|
|
1695
|
+
get: {},
|
|
1696
|
+
cat: {},
|
|
1697
|
+
new: {},
|
|
1698
|
+
edit: {},
|
|
1699
|
+
comment: {},
|
|
1700
|
+
import: {},
|
|
1701
|
+
visibility: {},
|
|
1702
|
+
publish: {},
|
|
1703
|
+
archive: {},
|
|
1704
|
+
history: {},
|
|
1705
|
+
revert: {},
|
|
1706
|
+
rm: {},
|
|
1707
|
+
lint: {}
|
|
1708
|
+
},
|
|
1709
|
+
secrets: { push: {}, status: {}, set: {}, "set-clerk-key": {} },
|
|
1710
|
+
security: {
|
|
1711
|
+
plan: {},
|
|
1712
|
+
sources: {},
|
|
1713
|
+
run: {},
|
|
1714
|
+
status: {},
|
|
1715
|
+
report: {},
|
|
1716
|
+
github: { connect: {}, disconnect: {} }
|
|
1717
|
+
},
|
|
1718
|
+
setup: {},
|
|
1719
|
+
skill: { install: {} },
|
|
1720
|
+
smoke: {},
|
|
1721
|
+
version: {},
|
|
1722
|
+
whoami: {}
|
|
1723
|
+
};
|
|
1724
|
+
}
|
|
1725
|
+
});
|
|
1726
|
+
|
|
1530
1727
|
// src/admin-spend.ts
|
|
1531
1728
|
async function call(ctx, method, scope) {
|
|
1532
1729
|
const url = `${ctx.platformUrl.replace(/\/$/, "")}/registry/platform/spend?scope=${encodeURIComponent(scope)}`;
|
|
@@ -1575,9 +1772,7 @@ async function spendReset(ctx, scope) {
|
|
|
1575
1772
|
async function adminSpend(parsed, ctx) {
|
|
1576
1773
|
const action2 = parsed.positionals[2];
|
|
1577
1774
|
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
|
-
}
|
|
1775
|
+
if (action2 !== "show" && action2 !== "reset") rejectWord(["admin", "spend"], action2);
|
|
1581
1776
|
if (!scope) {
|
|
1582
1777
|
throw new Error(
|
|
1583
1778
|
`"admin spend ${action2}" needs a scope, e.g. odla-ai admin spend ${action2} app:my-app:<incarnation>`
|
|
@@ -1591,6 +1786,7 @@ var init_admin_spend = __esm({
|
|
|
1591
1786
|
"use strict";
|
|
1592
1787
|
init_cjs_shims();
|
|
1593
1788
|
init_argv();
|
|
1789
|
+
init_surface();
|
|
1594
1790
|
money = (value2) => `$${value2.toFixed(2)}`;
|
|
1595
1791
|
}
|
|
1596
1792
|
});
|
|
@@ -2426,6 +2622,11 @@ var init_operator_context = __esm({
|
|
|
2426
2622
|
async function adminCommand(parsed, deps = {}) {
|
|
2427
2623
|
const area = parsed.positionals[1];
|
|
2428
2624
|
const action2 = parsed.positionals[2];
|
|
2625
|
+
if (area !== "ai" && area !== "spend") rejectWord(["admin"], area);
|
|
2626
|
+
if (!acceptedAfter(["admin", area]).includes(action2 ?? "")) rejectWord(["admin", area], action2);
|
|
2627
|
+
if (action2 === "credential" && !acceptedAfter(["admin", "ai", "credential"]).includes(parsed.positionals[3] ?? "")) {
|
|
2628
|
+
rejectWord(["admin", "ai", "credential"], parsed.positionals[3]);
|
|
2629
|
+
}
|
|
2429
2630
|
if (area === "spend") {
|
|
2430
2631
|
assertArgs(parsed, JSON_OPTIONS, 4);
|
|
2431
2632
|
const context2 = await resolveOperatorContext(parsed, { allowMissingConfig: true });
|
|
@@ -2451,14 +2652,11 @@ async function adminCommand(parsed, deps = {}) {
|
|
|
2451
2652
|
out
|
|
2452
2653
|
});
|
|
2453
2654
|
}
|
|
2454
|
-
const credentialSet = action2 === "credential"
|
|
2655
|
+
const credentialSet = action2 === "credential";
|
|
2455
2656
|
const credentials = action2 === "credentials";
|
|
2456
2657
|
const models = action2 === "models";
|
|
2457
2658
|
const usage = action2 === "usage";
|
|
2458
2659
|
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
2660
|
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
2661
|
assertArgs(parsed, allowed, credentialSet ? 5 : action2 === "set" ? 4 : 3);
|
|
2464
2662
|
const context = await resolveOperatorContext(parsed, { allowMissingConfig: true });
|
|
@@ -2504,6 +2702,7 @@ var init_admin_command = __esm({
|
|
|
2504
2702
|
init_token();
|
|
2505
2703
|
init_argv();
|
|
2506
2704
|
init_operator_context();
|
|
2705
|
+
init_surface();
|
|
2507
2706
|
CONTEXT_OPTIONS = ["platform", "config", "context", "token", "open", "email"];
|
|
2508
2707
|
JSON_OPTIONS = [...CONTEXT_OPTIONS, "json"];
|
|
2509
2708
|
SET_OPTIONS = [
|
|
@@ -2708,9 +2907,7 @@ async function authCommand(parsed, deps = {}) {
|
|
|
2708
2907
|
"json"
|
|
2709
2908
|
], 2);
|
|
2710
2909
|
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
|
-
}
|
|
2910
|
+
if (action2 !== "login") rejectWord(["auth"], action2);
|
|
2714
2911
|
const context = await resolveOperatorContext(parsed, {
|
|
2715
2912
|
allowMissingConfig: true,
|
|
2716
2913
|
requireApp: true
|
|
@@ -2768,6 +2965,7 @@ var init_auth_command = __esm({
|
|
|
2768
2965
|
init_token();
|
|
2769
2966
|
init_auth_guidance();
|
|
2770
2967
|
init_whoami_command();
|
|
2968
|
+
init_surface();
|
|
2771
2969
|
}
|
|
2772
2970
|
});
|
|
2773
2971
|
|
|
@@ -2803,9 +3001,7 @@ var init_tenant = __esm({
|
|
|
2803
3001
|
// src/agent-command.ts
|
|
2804
3002
|
async function agentCommand(parsed, deps = {}) {
|
|
2805
3003
|
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
|
-
}
|
|
3004
|
+
if (action2 !== "jobs" && action2 !== "retry") rejectWord(["agent"], action2);
|
|
2809
3005
|
assertArgs(parsed, ["config", "env", "state", "limit", "json", "token"], action2 === "jobs" ? 2 : 3);
|
|
2810
3006
|
if (action2 === "retry" && (parsed.options.state !== void 0 || parsed.options.limit !== void 0)) {
|
|
2811
3007
|
throw new Error('--state and --limit are supported only by "agent jobs"');
|
|
@@ -2887,6 +3083,7 @@ var init_agent_command = __esm({
|
|
|
2887
3083
|
init_config();
|
|
2888
3084
|
init_tenant();
|
|
2889
3085
|
init_local();
|
|
3086
|
+
init_surface();
|
|
2890
3087
|
}
|
|
2891
3088
|
});
|
|
2892
3089
|
|
|
@@ -2936,8 +3133,8 @@ async function appImport(options) {
|
|
|
2936
3133
|
const out = options.stdout ?? console;
|
|
2937
3134
|
const say = options.json ? (line2) => out.error(line2) : (line2) => out.log(line2);
|
|
2938
3135
|
const { tenant } = resolveTenant(cfg, options.env);
|
|
2939
|
-
const
|
|
2940
|
-
const { format, sources } = (0, import_import.parseImport)(
|
|
3136
|
+
const text4 = options.file === "-" ? (options.readStdin ?? (() => (0, import_node_fs12.readFileSync)(0, "utf8")))() : (0, import_node_fs12.readFileSync)(options.file, "utf8");
|
|
3137
|
+
const { format, sources } = (0, import_import.parseImport)(text4, options.ns);
|
|
2941
3138
|
if (format === "namespace-map" && options.ns) {
|
|
2942
3139
|
throw new Error("--ns cannot be combined with a {namespace: rows} file \u2014 the file already names each namespace");
|
|
2943
3140
|
}
|
|
@@ -3010,9 +3207,7 @@ async function appOwnersCommand(parsed, dependencies = {}) {
|
|
|
3010
3207
|
await (sub === "add" ? ownersAdd(email, options) : ownersRemove(email, options));
|
|
3011
3208
|
return;
|
|
3012
3209
|
}
|
|
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
|
-
);
|
|
3210
|
+
rejectWord(["app", "owners"], sub);
|
|
3016
3211
|
}
|
|
3017
3212
|
var init_app_owners = __esm({
|
|
3018
3213
|
"src/app-owners.ts"() {
|
|
@@ -3020,6 +3215,7 @@ var init_app_owners = __esm({
|
|
|
3020
3215
|
init_cjs_shims();
|
|
3021
3216
|
init_argv();
|
|
3022
3217
|
init_human_session();
|
|
3218
|
+
init_surface();
|
|
3023
3219
|
}
|
|
3024
3220
|
});
|
|
3025
3221
|
|
|
@@ -3143,8 +3339,10 @@ async function appCommand(parsed, dependencies = {}) {
|
|
|
3143
3339
|
return;
|
|
3144
3340
|
}
|
|
3145
3341
|
if (sub !== "archive" && sub !== "restore") {
|
|
3146
|
-
|
|
3147
|
-
|
|
3342
|
+
rejectWord(
|
|
3343
|
+
["app"],
|
|
3344
|
+
sub,
|
|
3345
|
+
"Permanent deletion has no CLI: it requires a signed-in owner in Studio."
|
|
3148
3346
|
);
|
|
3149
3347
|
}
|
|
3150
3348
|
assertArgs(parsed, ["config", "token", "email", "yes", "json"], 2);
|
|
@@ -3171,6 +3369,7 @@ var init_app_lifecycle = __esm({
|
|
|
3171
3369
|
init_app_transfer();
|
|
3172
3370
|
init_argv();
|
|
3173
3371
|
init_human_session();
|
|
3372
|
+
init_surface();
|
|
3174
3373
|
}
|
|
3175
3374
|
});
|
|
3176
3375
|
|
|
@@ -3274,7 +3473,7 @@ var init_brand_design_unpack = __esm({
|
|
|
3274
3473
|
"text/html": "html",
|
|
3275
3474
|
"application/json": "json"
|
|
3276
3475
|
};
|
|
3277
|
-
encode = (
|
|
3476
|
+
encode = (text4) => new TextEncoder().encode(text4);
|
|
3278
3477
|
}
|
|
3279
3478
|
});
|
|
3280
3479
|
|
|
@@ -3320,7 +3519,8 @@ async function brandCommand(parsed, deps) {
|
|
|
3320
3519
|
await designUnpack(parsed, deps);
|
|
3321
3520
|
return;
|
|
3322
3521
|
}
|
|
3323
|
-
|
|
3522
|
+
if (subject !== "design") rejectWord(["brand"], subject);
|
|
3523
|
+
rejectWord(["brand", "design"], action2, USAGE);
|
|
3324
3524
|
}
|
|
3325
3525
|
var import_promises, import_node_path10, USAGE;
|
|
3326
3526
|
var init_brand_command = __esm({
|
|
@@ -3331,6 +3531,7 @@ var init_brand_command = __esm({
|
|
|
3331
3531
|
import_node_path10 = require("path");
|
|
3332
3532
|
init_argv();
|
|
3333
3533
|
init_brand_design_unpack();
|
|
3534
|
+
init_surface();
|
|
3334
3535
|
USAGE = "usage: odla-ai brand design unpack <bundle.html|-> [--out <dir>] [--json]";
|
|
3335
3536
|
}
|
|
3336
3537
|
});
|
|
@@ -4130,9 +4331,9 @@ async function assertTenantAdminAccess(doFetch, cfg, env, token) {
|
|
|
4130
4331
|
}
|
|
4131
4332
|
throw new Error(`${env}: tenant access preflight (${tenantId}) failed: ${res.status} ${await safeText5(res)}`);
|
|
4132
4333
|
}
|
|
4133
|
-
function errorCode(
|
|
4334
|
+
function errorCode(text4) {
|
|
4134
4335
|
try {
|
|
4135
|
-
const body = JSON.parse(
|
|
4336
|
+
const body = JSON.parse(text4);
|
|
4136
4337
|
return typeof body.error?.code === "string" ? body.error.code : null;
|
|
4137
4338
|
} catch {
|
|
4138
4339
|
return null;
|
|
@@ -4918,15 +5119,15 @@ function readWranglerConfig(path) {
|
|
|
4918
5119
|
return null;
|
|
4919
5120
|
}
|
|
4920
5121
|
}
|
|
4921
|
-
function stripJsonComments(
|
|
5122
|
+
function stripJsonComments(text4) {
|
|
4922
5123
|
let result = "";
|
|
4923
5124
|
let inString = false;
|
|
4924
|
-
for (let i = 0; i <
|
|
4925
|
-
const ch =
|
|
5125
|
+
for (let i = 0; i < text4.length; i++) {
|
|
5126
|
+
const ch = text4[i];
|
|
4926
5127
|
if (inString) {
|
|
4927
5128
|
result += ch;
|
|
4928
5129
|
if (ch === "\\") {
|
|
4929
|
-
result +=
|
|
5130
|
+
result += text4[i + 1] ?? "";
|
|
4930
5131
|
i++;
|
|
4931
5132
|
} else if (ch === '"') {
|
|
4932
5133
|
inString = false;
|
|
@@ -4938,14 +5139,14 @@ function stripJsonComments(text3) {
|
|
|
4938
5139
|
result += ch;
|
|
4939
5140
|
continue;
|
|
4940
5141
|
}
|
|
4941
|
-
if (ch === "/" &&
|
|
4942
|
-
while (i <
|
|
5142
|
+
if (ch === "/" && text4[i + 1] === "/") {
|
|
5143
|
+
while (i < text4.length && text4[i] !== "\n") i++;
|
|
4943
5144
|
result += "\n";
|
|
4944
5145
|
continue;
|
|
4945
5146
|
}
|
|
4946
|
-
if (ch === "/" &&
|
|
5147
|
+
if (ch === "/" && text4[i + 1] === "*") {
|
|
4947
5148
|
i += 2;
|
|
4948
|
-
while (i <
|
|
5149
|
+
while (i < text4.length && !(text4[i] === "*" && text4[i + 1] === "/")) i++;
|
|
4949
5150
|
i++;
|
|
4950
5151
|
continue;
|
|
4951
5152
|
}
|
|
@@ -5529,9 +5730,9 @@ function initProject(options) {
|
|
|
5529
5730
|
out.log("created src/odla/schema.mjs and src/odla/rules.mjs");
|
|
5530
5731
|
out.log("updated .gitignore for local odla credentials");
|
|
5531
5732
|
}
|
|
5532
|
-
function writeIfMissing(path,
|
|
5733
|
+
function writeIfMissing(path, text4) {
|
|
5533
5734
|
if ((0, import_node_fs16.existsSync)(path)) return;
|
|
5534
|
-
(0, import_node_fs16.writeFileSync)(path,
|
|
5735
|
+
(0, import_node_fs16.writeFileSync)(path, text4);
|
|
5535
5736
|
}
|
|
5536
5737
|
function configTemplate(input) {
|
|
5537
5738
|
const calendar = input.services.includes("calendar") ? ` calendar: {
|
|
@@ -5763,13 +5964,13 @@ async function secretsSetClerkKey(options) {
|
|
|
5763
5964
|
body: JSON.stringify({ value: value2 })
|
|
5764
5965
|
});
|
|
5765
5966
|
if (!res.ok) {
|
|
5766
|
-
const
|
|
5767
|
-
throw new Error(`store Clerk secret key failed (${res.status}): ${
|
|
5967
|
+
const text4 = scrubValue((await res.text().catch(() => "")).slice(0, 300), value2);
|
|
5968
|
+
throw new Error(`store Clerk secret key failed (${res.status}): ${text4 || "request failed"}`);
|
|
5768
5969
|
}
|
|
5769
5970
|
out.log(`Clerk secret key stored for ${tenantId} ($clerk_secret, reserved + write-only; the value was never echoed)`);
|
|
5770
5971
|
}
|
|
5771
|
-
function scrubValue(
|
|
5772
|
-
return redactSecrets(
|
|
5972
|
+
function scrubValue(text4, value2) {
|
|
5973
|
+
return redactSecrets(text4).split(value2).join("[value redacted]");
|
|
5773
5974
|
}
|
|
5774
5975
|
async function resolveVaultWrite(options) {
|
|
5775
5976
|
const out = options.stdout ?? console;
|
|
@@ -6086,8 +6287,8 @@ ${conflicts.map((f) => ` - ${f}`).join("\n")}`
|
|
|
6086
6287
|
harnesses: installations
|
|
6087
6288
|
};
|
|
6088
6289
|
}
|
|
6089
|
-
function pathsUnder(root,
|
|
6090
|
-
return [...
|
|
6290
|
+
function pathsUnder(root, paths2) {
|
|
6291
|
+
return [...paths2].map((path) => (0, import_node_path16.relative)(root, path)).filter((path) => path !== ".." && !path.startsWith(`..${import_node_path16.sep}`) && !(0, import_node_path16.isAbsolute)(path)).sort();
|
|
6091
6292
|
}
|
|
6092
6293
|
function normalizeHarnesses(values, global) {
|
|
6093
6294
|
const requested = values?.length ? values : ["claude"];
|
|
@@ -6392,9 +6593,7 @@ async function secretsCommand(parsed, deps) {
|
|
|
6392
6593
|
return;
|
|
6393
6594
|
}
|
|
6394
6595
|
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
|
-
);
|
|
6596
|
+
rejectWord(["secrets"], sub);
|
|
6398
6597
|
}
|
|
6399
6598
|
assertArgs(parsed, ["config", "env", "dry-run", "yes"], 2);
|
|
6400
6599
|
await secretsPush({
|
|
@@ -6407,7 +6606,7 @@ async function secretsCommand(parsed, deps) {
|
|
|
6407
6606
|
async function projectCommand(command, parsed, deps) {
|
|
6408
6607
|
if (command === "ai") {
|
|
6409
6608
|
const sub = parsed.positionals[1];
|
|
6410
|
-
if (sub !== "models")
|
|
6609
|
+
if (sub !== "models") rejectWord(["ai"], sub);
|
|
6411
6610
|
assertArgs(parsed, ["config", "env", "provider", "json"], 2);
|
|
6412
6611
|
await aiModels({
|
|
6413
6612
|
configPath: stringOpt(parsed.options.config) ?? "odla.config.mjs",
|
|
@@ -6421,9 +6620,7 @@ async function projectCommand(command, parsed, deps) {
|
|
|
6421
6620
|
}
|
|
6422
6621
|
if (command === "config") {
|
|
6423
6622
|
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
|
-
}
|
|
6623
|
+
if (sub !== "diff" && sub !== "plan" && sub !== "apply") rejectWord(["config"], sub);
|
|
6427
6624
|
assertArgs(
|
|
6428
6625
|
parsed,
|
|
6429
6626
|
sub === "apply" ? ["config", "plan", "idempotency-key", "token", "email", "open", "json"] : ["config", "token", "email", "open", "json"],
|
|
@@ -6451,7 +6648,7 @@ async function projectCommand(command, parsed, deps) {
|
|
|
6451
6648
|
if (command === "operations") {
|
|
6452
6649
|
const sub = parsed.positionals[1];
|
|
6453
6650
|
if (sub !== "get" && sub !== "wait") {
|
|
6454
|
-
|
|
6651
|
+
rejectWord(["operations"], sub);
|
|
6455
6652
|
}
|
|
6456
6653
|
assertArgs(
|
|
6457
6654
|
parsed,
|
|
@@ -6525,7 +6722,7 @@ async function projectCommand(command, parsed, deps) {
|
|
|
6525
6722
|
}
|
|
6526
6723
|
if (command === "skill") {
|
|
6527
6724
|
const sub = parsed.positionals[1];
|
|
6528
|
-
if (sub !== "install")
|
|
6725
|
+
if (sub !== "install") rejectWord(["skill"], sub);
|
|
6529
6726
|
install(parsed, 2, deps);
|
|
6530
6727
|
return true;
|
|
6531
6728
|
}
|
|
@@ -6553,21 +6750,22 @@ var init_cli_project = __esm({
|
|
|
6553
6750
|
init_secrets_status();
|
|
6554
6751
|
init_skill();
|
|
6555
6752
|
init_smoke();
|
|
6753
|
+
init_surface();
|
|
6556
6754
|
SKILL_OPTS = ["dir", "global", "force", "agent", "harness"];
|
|
6557
6755
|
}
|
|
6558
6756
|
});
|
|
6559
6757
|
|
|
6560
|
-
// ../harness/dist/chunk-
|
|
6758
|
+
// ../harness/dist/chunk-RXNHCGWE.js
|
|
6561
6759
|
var HARNESS_PROTOCOL_VERSION;
|
|
6562
|
-
var
|
|
6563
|
-
"../harness/dist/chunk-
|
|
6760
|
+
var init_chunk_RXNHCGWE = __esm({
|
|
6761
|
+
"../harness/dist/chunk-RXNHCGWE.js"() {
|
|
6564
6762
|
"use strict";
|
|
6565
6763
|
init_cjs_shims();
|
|
6566
6764
|
HARNESS_PROTOCOL_VERSION = 1;
|
|
6567
6765
|
}
|
|
6568
6766
|
});
|
|
6569
6767
|
|
|
6570
|
-
// ../harness/dist/chunk-
|
|
6768
|
+
// ../harness/dist/chunk-CR6RE3A2.js
|
|
6571
6769
|
function assertPinnedImage(image) {
|
|
6572
6770
|
if (!DIGEST_IMAGE.test(image)) throw new TypeError("container image must be pinned by sha256 digest");
|
|
6573
6771
|
}
|
|
@@ -6795,12 +6993,12 @@ async function gitSourceFiles(sourceDir, maxFiles, maxBytes) {
|
|
|
6795
6993
|
});
|
|
6796
6994
|
if (outputBytes > 8 * 1024 * 1024) throw new Error("git file inventory exceeds 8 MiB");
|
|
6797
6995
|
if (code !== 0) throw new Error(`git file inventory failed: ${Buffer.concat(stderr2).toString("utf8").slice(0, 1e3)}`);
|
|
6798
|
-
const
|
|
6799
|
-
if (
|
|
6996
|
+
const paths2 = Buffer.concat(stdout).toString("utf8").split("\0").filter(Boolean).sort();
|
|
6997
|
+
if (paths2.length > maxFiles) throw new Error(`workspace exceeds ${maxFiles} files`);
|
|
6800
6998
|
const root = (0, import_path4.resolve)(sourceDir);
|
|
6801
6999
|
const files = [];
|
|
6802
7000
|
let bytes = 0;
|
|
6803
|
-
for (const relativePath of
|
|
7001
|
+
for (const relativePath of paths2) {
|
|
6804
7002
|
if (!allowedWorkspacePath(relativePath)) continue;
|
|
6805
7003
|
const source = (0, import_path4.resolve)(root, relativePath);
|
|
6806
7004
|
if (!source.startsWith(`${root}${import_path4.sep}`)) throw new TypeError("git file path escapes workspace");
|
|
@@ -6916,8 +7114,8 @@ async function stageWorkspacePair(baselineSource, workspaceSource, options = {})
|
|
|
6916
7114
|
}
|
|
6917
7115
|
}
|
|
6918
7116
|
var import_child_process, import_fs, import_promises2, import_path, import_process, import_promises3, import_os, import_path2, import_child_process2, import_path3, import_promises4, import_os2, import_path4, import_child_process3, DIGEST_IMAGE, SKIP_WORKSPACE_DIRS, SECRET_WORKSPACE_FILE;
|
|
6919
|
-
var
|
|
6920
|
-
"../harness/dist/chunk-
|
|
7117
|
+
var init_chunk_CR6RE3A2 = __esm({
|
|
7118
|
+
"../harness/dist/chunk-CR6RE3A2.js"() {
|
|
6921
7119
|
"use strict";
|
|
6922
7120
|
init_cjs_shims();
|
|
6923
7121
|
import_child_process = require("child_process");
|
|
@@ -7276,13 +7474,13 @@ function validateSnapshot(snapshot, limits) {
|
|
|
7276
7474
|
if (!Number.isSafeInteger(limits.maximumFiles) || limits.maximumFiles < 1 || !Number.isSafeInteger(limits.maximumBytes) || limits.maximumBytes < 1 || snapshot.files.length > limits.maximumFiles) {
|
|
7277
7475
|
throw new CamelError("limit_exceeded", "Code snapshot exceeds its registered limits.");
|
|
7278
7476
|
}
|
|
7279
|
-
const
|
|
7477
|
+
const paths2 = /* @__PURE__ */ new Set();
|
|
7280
7478
|
let bytes = 0;
|
|
7281
7479
|
for (const file of snapshot.files) {
|
|
7282
|
-
if (!file.path || file.path.startsWith("/") || file.path.includes("\\") || file.path.split("/").some((part) => !part || part === "." || part === "..") ||
|
|
7480
|
+
if (!file.path || file.path.startsWith("/") || file.path.includes("\\") || file.path.split("/").some((part) => !part || part === "." || part === "..") || paths2.has(file.path) || typeof file.content !== "string") {
|
|
7283
7481
|
throw new CamelError("state_conflict", "Code snapshot contains an invalid or duplicate path.");
|
|
7284
7482
|
}
|
|
7285
|
-
|
|
7483
|
+
paths2.add(file.path);
|
|
7286
7484
|
bytes += utf8Length(file.path) + utf8Length(file.content);
|
|
7287
7485
|
}
|
|
7288
7486
|
if (bytes > limits.maximumBytes) {
|
|
@@ -7433,8 +7631,8 @@ function boundedInteger(value2, spec) {
|
|
|
7433
7631
|
}
|
|
7434
7632
|
function boundedNumber(value2, spec) {
|
|
7435
7633
|
if (spec.kind !== "finite_number" || typeof value2 !== "number" || !Number.isFinite(value2) || value2 < spec.minimum || value2 > spec.maximum) throw new CamelError("conversion_rejected", "Finite-number conversion rejected the structured value.");
|
|
7436
|
-
const
|
|
7437
|
-
if (/e/i.test(
|
|
7634
|
+
const text4 = String(value2);
|
|
7635
|
+
if (/e/i.test(text4) || (text4.split(".")[1]?.length ?? 0) > spec.maximumDecimalPlaces) throw new CamelError("conversion_rejected", "Finite-number conversion rejected a non-canonical decimal.");
|
|
7438
7636
|
return value2;
|
|
7439
7637
|
}
|
|
7440
7638
|
function enumMember(value2, spec) {
|
|
@@ -7617,8 +7815,8 @@ function validateUnsafeSelector(path, value2, tool) {
|
|
|
7617
7815
|
return void 0;
|
|
7618
7816
|
}
|
|
7619
7817
|
function looksLikeDestination(value2) {
|
|
7620
|
-
const
|
|
7621
|
-
return /^(?:[a-z][a-z0-9+.-]*:\/\/|\/|\\\\)/i.test(
|
|
7818
|
+
const text4 = value2.trim();
|
|
7819
|
+
return /^(?:[a-z][a-z0-9+.-]*:\/\/|\/|\\\\)/i.test(text4) || /^[\w.-]+\.[a-z]{2,}(?:[/:]|$)/i.test(text4);
|
|
7622
7820
|
}
|
|
7623
7821
|
var init_policy = __esm({
|
|
7624
7822
|
"../camel/dist/policy.js"() {
|
|
@@ -7792,9 +7990,9 @@ async function extractImports(builder, input) {
|
|
|
7792
7990
|
const sources = input.paths.filter(isSourcePath);
|
|
7793
7991
|
const known = new Set(sources);
|
|
7794
7992
|
for (const path of sources) {
|
|
7795
|
-
let
|
|
7993
|
+
let text4;
|
|
7796
7994
|
try {
|
|
7797
|
-
|
|
7995
|
+
text4 = await input.read(path);
|
|
7798
7996
|
} catch {
|
|
7799
7997
|
continue;
|
|
7800
7998
|
}
|
|
@@ -7802,13 +8000,13 @@ async function extractImports(builder, input) {
|
|
|
7802
8000
|
const file = builder.node(FILE, path, pkg ? { pkg } : void 0);
|
|
7803
8001
|
if (pkg) builder.edge(builder.node(PACKAGE, pkg), CONTAINS, file);
|
|
7804
8002
|
const specifiers = /* @__PURE__ */ new Set();
|
|
7805
|
-
for (const match of
|
|
7806
|
-
for (const match of
|
|
8003
|
+
for (const match of text4.matchAll(IMPORT_FROM)) specifiers.add(match[1]);
|
|
8004
|
+
for (const match of text4.matchAll(BARE_IMPORT)) specifiers.add(match[1]);
|
|
7807
8005
|
for (const specifier of specifiers) {
|
|
7808
8006
|
const resolved = resolveImport(path, specifier, known);
|
|
7809
8007
|
if (resolved) builder.edge(file, IMPORTS, nodeId(FILE, resolved));
|
|
7810
8008
|
}
|
|
7811
|
-
for (const name of exportedNames(
|
|
8009
|
+
for (const name of exportedNames(text4)) {
|
|
7812
8010
|
builder.edge(file, EXPORTS, builder.node(SYMBOL, name));
|
|
7813
8011
|
}
|
|
7814
8012
|
}
|
|
@@ -7821,16 +8019,16 @@ async function extractData(builder, input) {
|
|
|
7821
8019
|
};
|
|
7822
8020
|
for (const path of input.paths) {
|
|
7823
8021
|
if (!SOURCE_FILE.test(path) || input.ignore?.(path)) continue;
|
|
7824
|
-
let
|
|
8022
|
+
let text4;
|
|
7825
8023
|
try {
|
|
7826
|
-
|
|
8024
|
+
text4 = await input.read(path);
|
|
7827
8025
|
} catch {
|
|
7828
8026
|
continue;
|
|
7829
8027
|
}
|
|
7830
|
-
for (const statement of
|
|
8028
|
+
for (const statement of text4.matchAll(STATEMENT)) {
|
|
7831
8029
|
const verb = statement[1].toUpperCase().replace(/\s+/g, " ");
|
|
7832
8030
|
const start = statement.index ?? 0;
|
|
7833
|
-
const rest =
|
|
8031
|
+
const rest = text4.slice(start + statement[0].length, start + STATEMENT_WINDOW);
|
|
7834
8032
|
if (verb === "SELECT") {
|
|
7835
8033
|
for (const read3 of rest.matchAll(READ_TABLES)) touch(path, read3[1].toLowerCase(), TABLE, READS);
|
|
7836
8034
|
continue;
|
|
@@ -7846,16 +8044,16 @@ async function extractData(builder, input) {
|
|
|
7846
8044
|
for (const read3 of rest.matchAll(READ_TABLES)) touch(path, read3[1].toLowerCase(), TABLE, READS);
|
|
7847
8045
|
}
|
|
7848
8046
|
}
|
|
7849
|
-
for (const match of
|
|
7850
|
-
touch(path, `${match[1]}.${match[2]}`, NAMESPACE, accessFor(
|
|
8047
|
+
for (const match of text4.matchAll(NS_CONST)) {
|
|
8048
|
+
touch(path, `${match[1]}.${match[2]}`, NAMESPACE, accessFor(text4, match.index ?? 0));
|
|
7851
8049
|
}
|
|
7852
|
-
for (const match of
|
|
7853
|
-
touch(path, match[1], NAMESPACE, accessFor(
|
|
8050
|
+
for (const match of text4.matchAll(NS_LITERAL)) {
|
|
8051
|
+
touch(path, match[1], NAMESPACE, accessFor(text4, match.index ?? 0));
|
|
7854
8052
|
}
|
|
7855
8053
|
}
|
|
7856
8054
|
}
|
|
7857
|
-
function accessFor(
|
|
7858
|
-
const window =
|
|
8055
|
+
function accessFor(text4, index) {
|
|
8056
|
+
const window = text4.slice(Math.max(0, index - 160), index + 40);
|
|
7859
8057
|
return /\b(?:transact|update|delete|create|insert|Ops)\b/.test(window) ? WRITES : READS;
|
|
7860
8058
|
}
|
|
7861
8059
|
async function buildCodeGraph(input) {
|
|
@@ -7915,7 +8113,7 @@ var init_code2 = __esm({
|
|
|
7915
8113
|
}
|
|
7916
8114
|
});
|
|
7917
8115
|
|
|
7918
|
-
// ../harness/dist/chunk-
|
|
8116
|
+
// ../harness/dist/chunk-ISR434K7.js
|
|
7919
8117
|
async function digestStagedWorkspace(root, limits) {
|
|
7920
8118
|
const files = [];
|
|
7921
8119
|
const walk = async (directory) => {
|
|
@@ -8195,7 +8393,7 @@ function validateCodePatch(rawPatch, maxBytes) {
|
|
|
8195
8393
|
if (FORBIDDEN.test(patch2) || /(?:old|new)(?: file)? mode 120000/.test(patch2)) {
|
|
8196
8394
|
throw new TypeError("patch uses a forbidden binary, link, mode, rename, or copy operation");
|
|
8197
8395
|
}
|
|
8198
|
-
const
|
|
8396
|
+
const paths2 = [];
|
|
8199
8397
|
const lines = patch2.split("\n");
|
|
8200
8398
|
for (let index = 0; index < lines.length; index += 1) {
|
|
8201
8399
|
const line2 = lines[index];
|
|
@@ -8211,10 +8409,10 @@ function validateCodePatch(rawPatch, maxBytes) {
|
|
|
8211
8409
|
if (!validHeaderPath(oldPath, path, "a") || !validHeaderPath(newPath, path, "b")) {
|
|
8212
8410
|
throw new TypeError("patch file headers do not match the declared path");
|
|
8213
8411
|
}
|
|
8214
|
-
|
|
8412
|
+
paths2.push(path);
|
|
8215
8413
|
}
|
|
8216
|
-
if (!
|
|
8217
|
-
return
|
|
8414
|
+
if (!paths2.length || new Set(paths2).size !== paths2.length) throw new TypeError("patch has no diffs or repeats a path");
|
|
8415
|
+
return paths2;
|
|
8218
8416
|
}
|
|
8219
8417
|
function validHeaderPath(value2, path, prefix) {
|
|
8220
8418
|
return value2 === "/dev/null" || value2 === `${prefix}/${path}`;
|
|
@@ -8239,11 +8437,11 @@ function describePatchFailure(patch2, detail) {
|
|
|
8239
8437
|
const hint = hunks.length > 0 && contextless ? " A hunk has no context lines; include at least one unchanged line above or below each change." : "";
|
|
8240
8438
|
return `patch did not apply: ${detail}${hint}`;
|
|
8241
8439
|
}
|
|
8242
|
-
async function applyCodePatch(workspaceDir, rawPatch,
|
|
8440
|
+
async function applyCodePatch(workspaceDir, rawPatch, paths2) {
|
|
8243
8441
|
const patch2 = stripPatchEnvelope(rawPatch);
|
|
8244
8442
|
await gitApply(workspaceDir, patch2, true);
|
|
8245
8443
|
await gitApply(workspaceDir, patch2, false);
|
|
8246
|
-
for (const path of
|
|
8444
|
+
for (const path of paths2) {
|
|
8247
8445
|
try {
|
|
8248
8446
|
const info = await (0, import_promises6.lstat)(resolveCodePath(workspaceDir, path));
|
|
8249
8447
|
if (info.isSymbolicLink() || !info.isFile() && !info.isDirectory()) {
|
|
@@ -8265,8 +8463,8 @@ function gitApply(cwd, patch2, check) {
|
|
|
8265
8463
|
});
|
|
8266
8464
|
let stderr2 = "";
|
|
8267
8465
|
child.stderr.setEncoding("utf8");
|
|
8268
|
-
child.stderr.on("data", (
|
|
8269
|
-
if (stderr2.length < 4e3) stderr2 +=
|
|
8466
|
+
child.stderr.on("data", (text22) => {
|
|
8467
|
+
if (stderr2.length < 4e3) stderr2 += text22.slice(0, 4e3);
|
|
8270
8468
|
});
|
|
8271
8469
|
child.once("error", reject);
|
|
8272
8470
|
child.once("exit", (code) => code === 0 ? accept() : reject(new TypeError(describePatchFailure(patch2, stderr2.trim().slice(0, 500)))));
|
|
@@ -8290,8 +8488,8 @@ async function restoreCodeWorkspaceCheckpoint(input) {
|
|
|
8290
8488
|
const workspace = await stageWorkspace(input.trustedBaseDir, input.stage);
|
|
8291
8489
|
try {
|
|
8292
8490
|
if (checkpoint.patch) {
|
|
8293
|
-
const
|
|
8294
|
-
await applyCodePatch(workspace.workspaceDir, checkpoint.patch,
|
|
8491
|
+
const paths2 = validateCodePatch(checkpoint.patch, 256 * 1024);
|
|
8492
|
+
await applyCodePatch(workspace.workspaceDir, checkpoint.patch, paths2);
|
|
8295
8493
|
}
|
|
8296
8494
|
return { workspace, checkpoint };
|
|
8297
8495
|
} catch (error) {
|
|
@@ -8432,8 +8630,8 @@ async function verifyCodeCandidate(input) {
|
|
|
8432
8630
|
try {
|
|
8433
8631
|
const baseDigest = await digestStagedWorkspace(staged.workspaceDir, limits);
|
|
8434
8632
|
if (baseDigest !== input.trustedBaseDigest) throw new TypeError("trusted base does not match its registered digest");
|
|
8435
|
-
const
|
|
8436
|
-
await applyCodePatch(staged.workspaceDir, input.candidatePatch,
|
|
8633
|
+
const paths2 = validateCodePatch(input.candidatePatch, policy.maximumPatchBytes);
|
|
8634
|
+
await applyCodePatch(staged.workspaceDir, input.candidatePatch, paths2);
|
|
8437
8635
|
const sourceDigest = await digestStagedWorkspace(staged.workspaceDir, limits);
|
|
8438
8636
|
const policyDigest = digestPolicy(policy);
|
|
8439
8637
|
const patchDigest = digestBytes(input.candidatePatch);
|
|
@@ -8442,7 +8640,7 @@ async function verifyCodeCandidate(input) {
|
|
|
8442
8640
|
trustedBaseDigest: input.trustedBaseDigest,
|
|
8443
8641
|
patchDigest
|
|
8444
8642
|
});
|
|
8445
|
-
const changedTests = changedTestPaths(
|
|
8643
|
+
const changedTests = changedTestPaths(paths2, policy);
|
|
8446
8644
|
if (changedTests.length > policy.maximumChangedTests) throw new TypeError("candidate changes too many test files");
|
|
8447
8645
|
const recipes = [];
|
|
8448
8646
|
const logs = [];
|
|
@@ -8509,8 +8707,8 @@ function validate2(input) {
|
|
|
8509
8707
|
}
|
|
8510
8708
|
return result;
|
|
8511
8709
|
}
|
|
8512
|
-
function changedTestPaths(
|
|
8513
|
-
return
|
|
8710
|
+
function changedTestPaths(paths2, policy) {
|
|
8711
|
+
return paths2.filter((path) => policy.testPathSuffixes.some((suffix) => path.endsWith(suffix)) || policy.testPathPrefixes.some((prefix) => path.startsWith(prefix) || path.includes(`/${prefix}`))).sort();
|
|
8514
8712
|
}
|
|
8515
8713
|
function recipeReceipt(recipe2, result, artifacts) {
|
|
8516
8714
|
const status = result.timedOut ? "timed_out" : result.outputLimitExceeded ? "output_limited" : result.exitCode === 0 && artifacts.every((item) => item.status === "verified") ? "passed" : "failed";
|
|
@@ -9143,7 +9341,7 @@ function createWorkspaceFileRegistry(limit = DEFAULT_MAX_FILES, enumerate = regi
|
|
|
9143
9341
|
files(root) {
|
|
9144
9342
|
const existing = cache2.get(root);
|
|
9145
9343
|
if (existing) return existing;
|
|
9146
|
-
const pending = enumerate(root, limit).then((
|
|
9344
|
+
const pending = enumerate(root, limit).then((paths2) => Object.freeze(paths2));
|
|
9147
9345
|
cache2.set(root, pending);
|
|
9148
9346
|
void pending.catch(() => {
|
|
9149
9347
|
if (cache2.get(root) === pending) cache2.delete(root);
|
|
@@ -9156,7 +9354,7 @@ function createWorkspaceFileRegistry(limit = DEFAULT_MAX_FILES, enumerate = regi
|
|
|
9156
9354
|
};
|
|
9157
9355
|
}
|
|
9158
9356
|
async function registeredFiles(root, limit = DEFAULT_MAX_FILES) {
|
|
9159
|
-
const
|
|
9357
|
+
const paths2 = [];
|
|
9160
9358
|
const walk = async (directory) => {
|
|
9161
9359
|
for (const entry of await (0, import_promises9.readdir)(directory, { withFileTypes: true })) {
|
|
9162
9360
|
if (SKIP_WORKSPACE_DIRS.has(entry.name)) continue;
|
|
@@ -9170,26 +9368,26 @@ async function registeredFiles(root, limit = DEFAULT_MAX_FILES) {
|
|
|
9170
9368
|
} catch {
|
|
9171
9369
|
continue;
|
|
9172
9370
|
}
|
|
9173
|
-
|
|
9174
|
-
if (
|
|
9371
|
+
paths2.push(path);
|
|
9372
|
+
if (paths2.length > limit) throw new TypeError("workspace file registry exceeds its bound");
|
|
9175
9373
|
}
|
|
9176
9374
|
}
|
|
9177
9375
|
};
|
|
9178
9376
|
await walk((0, import_path9.resolve)(root));
|
|
9179
|
-
return
|
|
9377
|
+
return paths2.sort();
|
|
9180
9378
|
}
|
|
9181
|
-
function listWorkspace(
|
|
9379
|
+
function listWorkspace(paths2, options = {}) {
|
|
9182
9380
|
const max = options.maxEntries ?? 1e3;
|
|
9183
9381
|
const prefix = options.prefix?.replace(/\/+$/, "");
|
|
9184
|
-
const scoped = prefix ?
|
|
9382
|
+
const scoped = prefix ? paths2.filter((path) => path === prefix || path.startsWith(`${prefix}/`)) : [...paths2];
|
|
9185
9383
|
return scoped.slice(0, max);
|
|
9186
9384
|
}
|
|
9187
|
-
async function searchWorkspace(root,
|
|
9385
|
+
async function searchWorkspace(root, paths2, options) {
|
|
9188
9386
|
options.signal?.throwIfAborted();
|
|
9189
9387
|
if (!options.query) throw new TypeError("search query must be a non-empty string");
|
|
9190
9388
|
const maxResults = options.maxResults ?? DEFAULT_MAX_RESULTS;
|
|
9191
9389
|
const maxFileBytes = options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES;
|
|
9192
|
-
const scoped = listWorkspace(
|
|
9390
|
+
const scoped = listWorkspace(paths2, { ...options.prefix ? { prefix: options.prefix } : {}, maxEntries: paths2.length });
|
|
9193
9391
|
if (scoped.length === 0) return [];
|
|
9194
9392
|
try {
|
|
9195
9393
|
return await nativeSearch(root, scoped, { ...options, maxResults, maxFileBytes });
|
|
@@ -9198,11 +9396,11 @@ async function searchWorkspace(root, paths, options) {
|
|
|
9198
9396
|
return fallbackSearch(root, scoped, { ...options, maxResults, maxFileBytes });
|
|
9199
9397
|
}
|
|
9200
9398
|
}
|
|
9201
|
-
async function nativeSearch(root,
|
|
9399
|
+
async function nativeSearch(root, paths2, options) {
|
|
9202
9400
|
const batches = [];
|
|
9203
9401
|
let batch = [];
|
|
9204
9402
|
let bytes = 0;
|
|
9205
|
-
for (const path of
|
|
9403
|
+
for (const path of paths2) {
|
|
9206
9404
|
const size = Buffer.byteLength(path) + 1;
|
|
9207
9405
|
if (batch.length > 0 && bytes + size > MAX_NATIVE_ARG_BYTES) {
|
|
9208
9406
|
batches.push(batch);
|
|
@@ -9221,7 +9419,7 @@ async function nativeSearch(root, paths, options) {
|
|
|
9221
9419
|
}
|
|
9222
9420
|
return matches;
|
|
9223
9421
|
}
|
|
9224
|
-
function nativeSearchBatch(root,
|
|
9422
|
+
function nativeSearchBatch(root, paths2, options, remaining) {
|
|
9225
9423
|
return new Promise((resolveMatches, reject) => {
|
|
9226
9424
|
const args = [
|
|
9227
9425
|
"--fixed-strings",
|
|
@@ -9234,7 +9432,7 @@ function nativeSearchBatch(root, paths, options, remaining) {
|
|
|
9234
9432
|
options.caseSensitive === false ? "--ignore-case" : "--case-sensitive",
|
|
9235
9433
|
"--",
|
|
9236
9434
|
options.query,
|
|
9237
|
-
...
|
|
9435
|
+
...paths2
|
|
9238
9436
|
];
|
|
9239
9437
|
const child = (0, import_child_process6.spawn)("rg", args, {
|
|
9240
9438
|
cwd: root,
|
|
@@ -9380,16 +9578,16 @@ function createCodePolicyGate(options) {
|
|
|
9380
9578
|
}
|
|
9381
9579
|
};
|
|
9382
9580
|
}
|
|
9383
|
-
function directoryPrefixes(
|
|
9581
|
+
function directoryPrefixes(paths2) {
|
|
9384
9582
|
const prefixes = /* @__PURE__ */ new Set(["."]);
|
|
9385
|
-
for (const path of
|
|
9583
|
+
for (const path of paths2) {
|
|
9386
9584
|
const parts = path.split("/");
|
|
9387
9585
|
for (let index = 1; index < parts.length; index += 1) prefixes.add(parts.slice(0, index).join("/"));
|
|
9388
9586
|
}
|
|
9389
9587
|
return [...prefixes].sort();
|
|
9390
9588
|
}
|
|
9391
|
-
async function safePrefix(base,
|
|
9392
|
-
const prefixes = directoryPrefixes(
|
|
9589
|
+
async function safePrefix(base, paths2, prefix) {
|
|
9590
|
+
const prefixes = directoryPrefixes(paths2);
|
|
9393
9591
|
const conversions = await conversionRegistry(
|
|
9394
9592
|
[await registeredPolicy("code.prefix.v1", "code.prefixes.v1", prefixes)],
|
|
9395
9593
|
{ "code.prefixes.v1": prefixes }
|
|
@@ -9500,7 +9698,7 @@ function optionalInteger(value2) {
|
|
|
9500
9698
|
function response(request3, ok, content2, details) {
|
|
9501
9699
|
return { requestId: request3.requestId, ok, content: content2, ...details ? { details } : {} };
|
|
9502
9700
|
}
|
|
9503
|
-
function workspaceGraphs(workspaceDir,
|
|
9701
|
+
function workspaceGraphs(workspaceDir, paths2) {
|
|
9504
9702
|
const existing = cache.get(workspaceDir);
|
|
9505
9703
|
if (existing) return existing;
|
|
9506
9704
|
const read22 = (path) => (0, import_promises11.readFile)((0, import_path10.join)(workspaceDir, path), "utf8");
|
|
@@ -9508,7 +9706,7 @@ function workspaceGraphs(workspaceDir, paths) {
|
|
|
9508
9706
|
// No knownTables: a staged workspace may not carry migrations, and a filter
|
|
9509
9707
|
// that silently drops every table is worse than an unfiltered one. Callers
|
|
9510
9708
|
// with ground truth should build the graph themselves.
|
|
9511
|
-
graph: await buildCodeGraph({ paths, read: read22, data: { ignore: (path) => path.includes(".generated.") } })
|
|
9709
|
+
graph: await buildCodeGraph({ paths: paths2, read: read22, data: { ignore: (path) => path.includes(".generated.") } })
|
|
9512
9710
|
}))();
|
|
9513
9711
|
cache.set(workspaceDir, built);
|
|
9514
9712
|
return built;
|
|
@@ -9561,11 +9759,11 @@ async function read(context, request3, options, policy, registry) {
|
|
|
9561
9759
|
if (endLine < startLine || endLine - startLine + 1 > (options.maxReadLines ?? 2e3)) {
|
|
9562
9760
|
throw new TypeError("requested line range exceeds its bound");
|
|
9563
9761
|
}
|
|
9564
|
-
const
|
|
9565
|
-
if (!
|
|
9762
|
+
const paths2 = await registry.files(context.workspaceDir);
|
|
9763
|
+
if (!paths2.includes(path)) {
|
|
9566
9764
|
throw new TypeError(`no such file in the staged workspace: "${path}". Use sandbox.overview, sandbox.where_is or sandbox.search to find the correct path.`);
|
|
9567
9765
|
}
|
|
9568
|
-
const allowed = await policy.read(policyContext(context, request3, options, { paths, path, startLine, endLine }));
|
|
9766
|
+
const allowed = await policy.read(policyContext(context, request3, options, { paths: paths2, path, startLine, endLine }));
|
|
9569
9767
|
if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
|
|
9570
9768
|
const target = resolveCodePath(context.workspaceDir, path);
|
|
9571
9769
|
const info = await (0, import_promises10.stat)(target);
|
|
@@ -9587,16 +9785,16 @@ async function list(context, request3, options, policy, registry) {
|
|
|
9587
9785
|
const prefix = typeof raw === "string" && raw.length > 0 ? raw : void 0;
|
|
9588
9786
|
const maxEntries = optionalInteger(request3.input.maxEntries) ?? 1e3;
|
|
9589
9787
|
if (maxEntries > 5e3) throw new TypeError("maxEntries exceeds its bound");
|
|
9590
|
-
const
|
|
9591
|
-
const allowed = await policy.list(policyContext(context, request3, options, { paths, ...prefix ? { prefix } : {} }));
|
|
9788
|
+
const paths2 = await registry.files(context.workspaceDir);
|
|
9789
|
+
const allowed = await policy.list(policyContext(context, request3, options, { paths: paths2, ...prefix ? { prefix } : {} }));
|
|
9592
9790
|
if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
|
|
9593
|
-
const entries = listWorkspace(
|
|
9791
|
+
const entries = listWorkspace(paths2, { ...prefix ? { prefix } : {}, maxEntries });
|
|
9594
9792
|
if (!entries.length) {
|
|
9595
9793
|
return response(request3, true, prefix ? `No files under "${prefix}".` : "Workspace is empty.", { count: 0 });
|
|
9596
9794
|
}
|
|
9597
|
-
const truncated = entries.length <
|
|
9598
|
-
const hint = !prefix &&
|
|
9599
|
-
\u2026 ${
|
|
9795
|
+
const truncated = entries.length < paths2.length && entries.length === maxEntries;
|
|
9796
|
+
const hint = !prefix && paths2.length > 500 ? `
|
|
9797
|
+
\u2026 ${paths2.length} files total. sandbox.overview is far cheaper for orientation; use a prefix here once you know the area.` : "";
|
|
9600
9798
|
return response(
|
|
9601
9799
|
request3,
|
|
9602
9800
|
true,
|
|
@@ -9614,10 +9812,10 @@ async function search(context, request3, options, policy, registry) {
|
|
|
9614
9812
|
const maxResults = optionalInteger(request3.input.maxResults) ?? 100;
|
|
9615
9813
|
if (maxResults > 500) throw new TypeError("maxResults exceeds its bound");
|
|
9616
9814
|
const caseSensitive = request3.input.caseSensitive === void 0 ? true : request3.input.caseSensitive === true;
|
|
9617
|
-
const
|
|
9618
|
-
const allowed = await policy.search(policyContext(context, request3, options, { paths, query, ...prefix ? { prefix } : {} }));
|
|
9815
|
+
const paths2 = await registry.files(context.workspaceDir);
|
|
9816
|
+
const allowed = await policy.search(policyContext(context, request3, options, { paths: paths2, query, ...prefix ? { prefix } : {} }));
|
|
9619
9817
|
if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
|
|
9620
|
-
const matches = await searchWorkspace(context.workspaceDir,
|
|
9818
|
+
const matches = await searchWorkspace(context.workspaceDir, paths2, {
|
|
9621
9819
|
query,
|
|
9622
9820
|
maxResults,
|
|
9623
9821
|
caseSensitive,
|
|
@@ -9639,8 +9837,8 @@ async function graphQuery(context, request3, options, policy, registry) {
|
|
|
9639
9837
|
selector: query
|
|
9640
9838
|
}));
|
|
9641
9839
|
if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
|
|
9642
|
-
const
|
|
9643
|
-
const graphs = await workspaceGraphs(context.workspaceDir,
|
|
9840
|
+
const paths2 = await registry.files(context.workspaceDir);
|
|
9841
|
+
const graphs = await workspaceGraphs(context.workspaceDir, paths2);
|
|
9644
9842
|
if (request3.tool === "sandbox.overview") {
|
|
9645
9843
|
return response(request3, true, renderOverview(graphs, query || void 0));
|
|
9646
9844
|
}
|
|
@@ -9702,16 +9900,16 @@ function toolFailureMessage(reason) {
|
|
|
9702
9900
|
async function patch(context, request3, options, policy, registry) {
|
|
9703
9901
|
exactKeys(request3.input, ["patch"]);
|
|
9704
9902
|
const value2 = stringField(request3.input, "patch");
|
|
9705
|
-
const
|
|
9706
|
-
if (
|
|
9903
|
+
const paths2 = validateCodePatch(value2, options.maxPatchBytes ?? 256 * 1024);
|
|
9904
|
+
if (paths2.some((path) => options.readOnlyPrefixes?.some((prefix) => path === prefix || path.startsWith(`${prefix}/`)))) {
|
|
9707
9905
|
throw new TypeError("patch targets a read-only reference source");
|
|
9708
9906
|
}
|
|
9709
9907
|
const allowed = await policy.patch(policyContext(context, request3, options, { patch: value2 }));
|
|
9710
9908
|
if (!allowed) return response(request3, false, "tool denied by CaMeL policy");
|
|
9711
|
-
await applyCodePatch(context.workspaceDir, value2,
|
|
9909
|
+
await applyCodePatch(context.workspaceDir, value2, paths2);
|
|
9712
9910
|
registry.invalidate(context.workspaceDir);
|
|
9713
9911
|
forgetWorkspaceGraphs(context.workspaceDir);
|
|
9714
|
-
return response(request3, true, `Applied patch to ${
|
|
9912
|
+
return response(request3, true, `Applied patch to ${paths2.length} file(s).`, { paths: paths2 });
|
|
9715
9913
|
}
|
|
9716
9914
|
async function recipe(context, request3, options, recipes, policy) {
|
|
9717
9915
|
exactKeys(request3.input, ["recipeId"]);
|
|
@@ -10058,16 +10256,107 @@ async function startGoalPursuit(input) {
|
|
|
10058
10256
|
async function appendCodeRuntimeEvent(control, command, event, refs) {
|
|
10059
10257
|
const eventId = `${command.commandId.slice(0, 45)}:${refs.length + 1}`;
|
|
10060
10258
|
refs.push(eventId);
|
|
10061
|
-
const
|
|
10259
|
+
const attributed = { ...event, interactionId: command.commandId };
|
|
10260
|
+
const bounded = attributed.type === "message" ? { ...attributed, body: attributed.body.trim().slice(0, 2e4) || `${attributed.actor} event` } : attributed;
|
|
10062
10261
|
await control.appendSessionEvent(command.sessionId, eventId, bounded);
|
|
10063
10262
|
}
|
|
10064
|
-
|
|
10065
|
-
|
|
10066
|
-
|
|
10263
|
+
function patchStats(value2) {
|
|
10264
|
+
if (typeof value2 !== "string") return {};
|
|
10265
|
+
let additions = 0;
|
|
10266
|
+
let deletions = 0;
|
|
10267
|
+
for (const line2 of value2.slice(0, 262144).split("\n")) {
|
|
10268
|
+
if (line2.startsWith("+++") || line2.startsWith("---")) continue;
|
|
10269
|
+
if (line2.startsWith("+")) additions += 1;
|
|
10270
|
+
else if (line2.startsWith("-")) deletions += 1;
|
|
10271
|
+
}
|
|
10272
|
+
return { ...additions ? { additions } : {}, ...deletions ? { deletions } : {} };
|
|
10273
|
+
}
|
|
10274
|
+
function searchResults(value2) {
|
|
10275
|
+
if (typeof value2 !== "string") return void 0;
|
|
10276
|
+
const results = value2.split("\n").flatMap((line2) => {
|
|
10277
|
+
const match = /^([^:\n]{1,1024}):(\d+):\s?(.*)$/.exec(line2);
|
|
10278
|
+
if (!match) return [];
|
|
10279
|
+
const lineNumber = Number(match[2]);
|
|
10280
|
+
const itemText = text3(match[3], 240);
|
|
10281
|
+
if (!Number.isSafeInteger(lineNumber) || lineNumber < 1) return [];
|
|
10282
|
+
return [{ path: match[1], line: lineNumber, ...itemText ? { text: itemText } : {} }];
|
|
10283
|
+
}).slice(0, 5);
|
|
10284
|
+
return results.length ? results : void 0;
|
|
10285
|
+
}
|
|
10286
|
+
function codeToolRequestPresentation(request3) {
|
|
10287
|
+
const input = request3.input;
|
|
10288
|
+
if (request3.tool === "sandbox.read") {
|
|
10289
|
+
const path = text3(input.path, 1024);
|
|
10290
|
+
if (!path) return void 0;
|
|
10291
|
+
const startLine = integer2(input.startLine);
|
|
10292
|
+
const endLine = integer2(input.endLine);
|
|
10293
|
+
return { kind: "read", path, ...startLine ? { startLine } : {}, ...endLine ? { endLine } : {} };
|
|
10294
|
+
}
|
|
10295
|
+
if (request3.tool === "sandbox.list") {
|
|
10296
|
+
const scope = text3(input.prefix, 1024);
|
|
10297
|
+
return { kind: "list", ...scope ? { scope } : {} };
|
|
10298
|
+
}
|
|
10299
|
+
if (request3.tool === "sandbox.search" || request3.tool === "sandbox.overview" || request3.tool === "sandbox.where_is" || request3.tool === "sandbox.who_imports" || request3.tool === "sandbox.who_touches") {
|
|
10300
|
+
const query = text3(input.query, 512);
|
|
10301
|
+
const scope = request3.tool === "sandbox.search" ? text3(input.prefix, 1024) : void 0;
|
|
10302
|
+
if (request3.tool === "sandbox.search" && !query) return void 0;
|
|
10303
|
+
return { kind: "query", ...query ? { query } : {}, ...scope ? { scope } : {} };
|
|
10304
|
+
}
|
|
10305
|
+
if (request3.tool === "sandbox.apply_patch") {
|
|
10306
|
+
return { kind: "patch", ...patchStats(input.patch) };
|
|
10307
|
+
}
|
|
10308
|
+
const recipeId = text3(input.recipeId, 120);
|
|
10309
|
+
return recipeId ? { kind: "recipe", recipeId } : void 0;
|
|
10310
|
+
}
|
|
10311
|
+
function codeToolResultPresentation(request3, response2) {
|
|
10312
|
+
const started = codeToolRequestPresentation(request3);
|
|
10313
|
+
if (!started || !response2.ok) return started;
|
|
10314
|
+
const details = record32(response2.details);
|
|
10315
|
+
if (started.kind === "read") {
|
|
10316
|
+
return {
|
|
10317
|
+
...started,
|
|
10318
|
+
...integer2(details?.startLine) ? { startLine: integer2(details?.startLine) } : {},
|
|
10319
|
+
...integer2(details?.endLine) ? { endLine: integer2(details?.endLine) } : {},
|
|
10320
|
+
...excerpt(response2.content) ? { excerpt: excerpt(response2.content) } : {}
|
|
10321
|
+
};
|
|
10322
|
+
}
|
|
10323
|
+
if (started.kind === "list") {
|
|
10324
|
+
const listed = response2.content.split("\n").filter((line2) => line2 && !line2.startsWith("\u2026") && !line2.startsWith("Workspace ")).map((line2) => text3(line2, 1024)).filter((line2) => Boolean(line2)).slice(0, 8);
|
|
10325
|
+
return {
|
|
10326
|
+
...started,
|
|
10327
|
+
...integer2(details?.count) !== void 0 ? { count: integer2(details?.count) } : {},
|
|
10328
|
+
...listed.length ? { paths: listed } : {}
|
|
10329
|
+
};
|
|
10330
|
+
}
|
|
10331
|
+
if (started.kind === "query") {
|
|
10332
|
+
const results = request3.tool === "sandbox.search" ? searchResults(response2.content) : void 0;
|
|
10333
|
+
const resultExcerpt = request3.tool === "sandbox.search" ? void 0 : excerpt(response2.content);
|
|
10334
|
+
return {
|
|
10335
|
+
...started,
|
|
10336
|
+
...integer2(details?.count) !== void 0 ? { count: integer2(details?.count) } : {},
|
|
10337
|
+
...results ? { results } : {},
|
|
10338
|
+
...resultExcerpt ? { excerpt: resultExcerpt } : {}
|
|
10339
|
+
};
|
|
10340
|
+
}
|
|
10341
|
+
if (started.kind === "patch") {
|
|
10342
|
+
return { ...started, ...paths(details?.paths) ? { paths: paths(details?.paths) } : {} };
|
|
10343
|
+
}
|
|
10344
|
+
const output = response2.content.replace(/^Recipe [^\n]*\.?\s*/u, "");
|
|
10345
|
+
return {
|
|
10346
|
+
...started,
|
|
10347
|
+
...integer2(details?.exitCode) !== void 0 ? { exitCode: integer2(details?.exitCode) } : {},
|
|
10348
|
+
...typeof details?.timedOut === "boolean" ? { timedOut: details.timedOut } : {},
|
|
10349
|
+
...typeof details?.outputLimitExceeded === "boolean" ? { outputLimitExceeded: details.outputLimitExceeded } : {},
|
|
10350
|
+
...excerpt(output, true) ? { excerpt: excerpt(output, true) } : {}
|
|
10351
|
+
};
|
|
10352
|
+
}
|
|
10353
|
+
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_ai5, import_child_process6, 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, MAX_NATIVE_ARG_BYTES, DESTINATIONS, READ, LIST, SEARCH, GRAPH, PATCH, RECIPE, cache, shortId, GRAPH_TOOLS, MAX_MEMORY_BODY, POSITIVE, digestRuntimeValue, runtimeErrorMessage, text3, integer2, record32, excerpt, paths, TheseusRuntimeEngine;
|
|
10354
|
+
var init_chunk_ISR434K7 = __esm({
|
|
10355
|
+
"../harness/dist/chunk-ISR434K7.js"() {
|
|
10067
10356
|
"use strict";
|
|
10068
10357
|
init_cjs_shims();
|
|
10069
|
-
|
|
10070
|
-
|
|
10358
|
+
init_chunk_CR6RE3A2();
|
|
10359
|
+
init_chunk_RXNHCGWE();
|
|
10071
10360
|
import_crypto = require("crypto");
|
|
10072
10361
|
import_promises5 = require("fs/promises");
|
|
10073
10362
|
import_path5 = require("path");
|
|
@@ -10306,6 +10595,30 @@ Never claim a build or test passed unless odla_run_recipe returned that result.`
|
|
|
10306
10595
|
POSITIVE = (value2) => Number.isFinite(value2) && Number(value2) > 0 ? Number(value2) : void 0;
|
|
10307
10596
|
digestRuntimeValue = (value2) => `sha256:${(0, import_crypto4.createHash)("sha256").update(value2).digest("hex")}`;
|
|
10308
10597
|
runtimeErrorMessage = (value2) => value2 instanceof Error ? value2.message : String(value2);
|
|
10598
|
+
text3 = (value2, maximum) => {
|
|
10599
|
+
if (typeof value2 !== "string") return void 0;
|
|
10600
|
+
const bounded = value2.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ").trim();
|
|
10601
|
+
return bounded ? bounded.slice(0, maximum) : void 0;
|
|
10602
|
+
};
|
|
10603
|
+
integer2 = (value2) => Number.isSafeInteger(value2) && Number(value2) >= 0 ? Number(value2) : void 0;
|
|
10604
|
+
record32 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : void 0;
|
|
10605
|
+
excerpt = (value2, tail = false) => {
|
|
10606
|
+
if (typeof value2 !== "string") return void 0;
|
|
10607
|
+
const safe = value2.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ");
|
|
10608
|
+
const source = (tail ? safe.slice(-1e4) : safe.slice(0, 1e4)).trim();
|
|
10609
|
+
if (!source) return void 0;
|
|
10610
|
+
const lines = source.split("\n").filter((line2) => line2.trim()).map((line2) => line2.slice(0, 240));
|
|
10611
|
+
const selected = tail ? lines.slice(-10) : lines.slice(0, 10);
|
|
10612
|
+
return text3(selected.join("\n"), 2400);
|
|
10613
|
+
};
|
|
10614
|
+
paths = (value2) => {
|
|
10615
|
+
if (!Array.isArray(value2)) return void 0;
|
|
10616
|
+
const items = value2.flatMap((item) => {
|
|
10617
|
+
const path = text3(item, 1024);
|
|
10618
|
+
return path ? [path] : [];
|
|
10619
|
+
}).slice(0, 12);
|
|
10620
|
+
return items.length ? items : void 0;
|
|
10621
|
+
};
|
|
10309
10622
|
TheseusRuntimeEngine = class {
|
|
10310
10623
|
constructor(options) {
|
|
10311
10624
|
this.options = options;
|
|
@@ -10539,18 +10852,29 @@ Never claim a build or test passed unless odla_run_recipe returned that result.`
|
|
|
10539
10852
|
return {
|
|
10540
10853
|
execute: async (context, request3) => {
|
|
10541
10854
|
const startedAt = Date.now();
|
|
10855
|
+
const operationId = digestRuntimeValue(`${command.commandId}:${request3.requestId}`);
|
|
10856
|
+
const startedPresentation = codeToolRequestPresentation(request3);
|
|
10542
10857
|
await this.#event(
|
|
10543
10858
|
command,
|
|
10544
|
-
{
|
|
10859
|
+
{
|
|
10860
|
+
type: "tool",
|
|
10861
|
+
phase: "started",
|
|
10862
|
+
tool: request3.tool,
|
|
10863
|
+
operationId,
|
|
10864
|
+
...startedPresentation ? { presentation: startedPresentation } : {}
|
|
10865
|
+
},
|
|
10545
10866
|
active.conversationRefs
|
|
10546
10867
|
).catch(() => void 0);
|
|
10547
10868
|
const response2 = await broker.execute(context, request3);
|
|
10869
|
+
const completedPresentation = codeToolResultPresentation(request3, response2);
|
|
10548
10870
|
await this.#event(command, {
|
|
10549
10871
|
type: "tool",
|
|
10550
10872
|
phase: "completed",
|
|
10551
10873
|
tool: request3.tool,
|
|
10552
10874
|
ok: response2.ok,
|
|
10553
|
-
durationMs: Date.now() - startedAt
|
|
10875
|
+
durationMs: Date.now() - startedAt,
|
|
10876
|
+
operationId,
|
|
10877
|
+
...completedPresentation ? { presentation: completedPresentation } : {}
|
|
10554
10878
|
}, active.conversationRefs).catch(() => void 0);
|
|
10555
10879
|
return response2;
|
|
10556
10880
|
}
|
|
@@ -10591,8 +10915,8 @@ var init_node = __esm({
|
|
|
10591
10915
|
"../harness/dist/node.js"() {
|
|
10592
10916
|
"use strict";
|
|
10593
10917
|
init_cjs_shims();
|
|
10594
|
-
|
|
10595
|
-
|
|
10918
|
+
init_chunk_ISR434K7();
|
|
10919
|
+
init_chunk_CR6RE3A2();
|
|
10596
10920
|
MEASURED_PREMIUM = Object.freeze({
|
|
10597
10921
|
/** 3 racers vs pure depth at equal budget: 21,044 / 7,936. */
|
|
10598
10922
|
racePerRacer: 0.55,
|
|
@@ -11072,9 +11396,7 @@ function grantsUrl(cfg, suffix = "") {
|
|
|
11072
11396
|
async function codeGrantCommand(parsed, deps = {}) {
|
|
11073
11397
|
const action2 = parsed.positionals[2];
|
|
11074
11398
|
if (!isAction(action2)) {
|
|
11075
|
-
|
|
11076
|
-
`unknown code grant action "${action2 ?? ""}". Try "odla-ai code grant list --env dev".`
|
|
11077
|
-
);
|
|
11399
|
+
rejectWord(["code", "grant"], action2);
|
|
11078
11400
|
}
|
|
11079
11401
|
const decides = action2 === "approve" || action2 === "revoke";
|
|
11080
11402
|
assertArgs(parsed, ["config", "env", "json", "token", "email", "open"], decides ? 4 : 3);
|
|
@@ -11141,6 +11463,7 @@ var init_code_grant_command = __esm({
|
|
|
11141
11463
|
init_config();
|
|
11142
11464
|
init_redact();
|
|
11143
11465
|
init_token();
|
|
11466
|
+
init_surface();
|
|
11144
11467
|
ACTIONS = ["request", "list", "approve", "revoke"];
|
|
11145
11468
|
isAction = (value2) => ACTIONS.includes(value2 ?? "");
|
|
11146
11469
|
}
|
|
@@ -11205,9 +11528,7 @@ function repositoryUrl(cfg, suffix = "") {
|
|
|
11205
11528
|
async function codeRepositoryCommand(parsed, deps = {}) {
|
|
11206
11529
|
const action2 = parsed.positionals[2];
|
|
11207
11530
|
if (!isAction2(action2)) {
|
|
11208
|
-
|
|
11209
|
-
`unknown code repository action "${action2 ?? ""}". Try "odla-ai code repository show --env dev".`
|
|
11210
|
-
);
|
|
11531
|
+
rejectWord(["code", "repository"], action2);
|
|
11211
11532
|
}
|
|
11212
11533
|
assertArgs(parsed, ["config", "env", "repo", "json", "token", "email", "open"], 3);
|
|
11213
11534
|
const cfg = await loadProjectConfig(stringOpt(parsed.options.config) ?? "odla.config.mjs");
|
|
@@ -11272,6 +11593,7 @@ var init_code_repository_command = __esm({
|
|
|
11272
11593
|
init_config();
|
|
11273
11594
|
init_redact();
|
|
11274
11595
|
init_token();
|
|
11596
|
+
init_surface();
|
|
11275
11597
|
ACTIONS2 = ["show", "list", "bind"];
|
|
11276
11598
|
isAction2 = (value2) => ACTIONS2.includes(value2 ?? "");
|
|
11277
11599
|
}
|
|
@@ -11295,9 +11617,7 @@ async function codeCommand(parsed, dependencies) {
|
|
|
11295
11617
|
});
|
|
11296
11618
|
}
|
|
11297
11619
|
if (sub !== "connect") {
|
|
11298
|
-
|
|
11299
|
-
`unknown code subcommand "${sub ?? ""}". Try "odla-ai code connect --env dev" or "odla-ai code grant list --env dev".`
|
|
11300
|
-
);
|
|
11620
|
+
rejectWord(["code"], sub);
|
|
11301
11621
|
}
|
|
11302
11622
|
assertArgs(parsed, [
|
|
11303
11623
|
"config",
|
|
@@ -11342,6 +11662,7 @@ var init_code_command = __esm({
|
|
|
11342
11662
|
init_code_connect();
|
|
11343
11663
|
init_code_grant_command();
|
|
11344
11664
|
init_code_repository_command();
|
|
11665
|
+
init_surface();
|
|
11345
11666
|
}
|
|
11346
11667
|
});
|
|
11347
11668
|
|
|
@@ -11453,9 +11774,7 @@ async function contextCommand(parsed, deps = {}) {
|
|
|
11453
11774
|
return;
|
|
11454
11775
|
}
|
|
11455
11776
|
if (action2 !== "show") {
|
|
11456
|
-
|
|
11457
|
-
`unknown context action "${action2 ?? ""}". Try show|list|save|remove.`
|
|
11458
|
-
);
|
|
11777
|
+
rejectWord(["context"], action2);
|
|
11459
11778
|
}
|
|
11460
11779
|
const context = await resolveOperatorContext(parsed, {
|
|
11461
11780
|
allowMissingConfig: true,
|
|
@@ -11512,6 +11831,7 @@ var init_context_command = __esm({
|
|
|
11512
11831
|
init_operator_credentials();
|
|
11513
11832
|
init_operator_context();
|
|
11514
11833
|
init_operator_profiles();
|
|
11834
|
+
init_surface();
|
|
11515
11835
|
}
|
|
11516
11836
|
});
|
|
11517
11837
|
|
|
@@ -11521,9 +11841,7 @@ async function responseError(response2) {
|
|
|
11521
11841
|
}
|
|
11522
11842
|
async function credentialCommand(parsed, deps = {}) {
|
|
11523
11843
|
const action2 = parsed.positionals[1] ?? "list";
|
|
11524
|
-
if (action2 !== "list" && action2 !== "revoke")
|
|
11525
|
-
throw new Error(`unknown credentials action "${action2}". Try "odla-ai credentials list".`);
|
|
11526
|
-
}
|
|
11844
|
+
if (action2 !== "list" && action2 !== "revoke") rejectWord(["credentials"], action2);
|
|
11527
11845
|
assertArgs(parsed, ["config", "env", "all", "json", "token", "email", "open"], action2 === "revoke" ? 3 : 2);
|
|
11528
11846
|
const cfg = await loadProjectConfig(stringOpt(parsed.options.config) ?? "odla.config.mjs");
|
|
11529
11847
|
const doFetch = deps.fetch ?? fetch;
|
|
@@ -11571,6 +11889,7 @@ var init_credential_command = __esm({
|
|
|
11571
11889
|
init_config();
|
|
11572
11890
|
init_redact();
|
|
11573
11891
|
init_token();
|
|
11892
|
+
init_surface();
|
|
11574
11893
|
}
|
|
11575
11894
|
});
|
|
11576
11895
|
|
|
@@ -12571,7 +12890,7 @@ async function discussCommand(parsed, deps = {}) {
|
|
|
12571
12890
|
assertArgs(parsed, ALLOWED, 3);
|
|
12572
12891
|
const action2 = parsed.positionals[1];
|
|
12573
12892
|
const id2 = parsed.positionals[2];
|
|
12574
|
-
if (!
|
|
12893
|
+
if (!acceptedAfter(["discuss"]).includes(action2 ?? "")) rejectWord(["discuss"], action2);
|
|
12575
12894
|
const ctx = await buildContext(parsed, deps);
|
|
12576
12895
|
switch (action2) {
|
|
12577
12896
|
case "groups":
|
|
@@ -12595,7 +12914,7 @@ async function discussCommand(parsed, deps = {}) {
|
|
|
12595
12914
|
return;
|
|
12596
12915
|
}
|
|
12597
12916
|
default:
|
|
12598
|
-
|
|
12917
|
+
rejectWord(["discuss"], action2);
|
|
12599
12918
|
}
|
|
12600
12919
|
}
|
|
12601
12920
|
var ALLOWED;
|
|
@@ -12608,6 +12927,7 @@ var init_discuss_command = __esm({
|
|
|
12608
12927
|
init_discuss_actions();
|
|
12609
12928
|
init_discuss_watch();
|
|
12610
12929
|
init_token();
|
|
12930
|
+
init_surface();
|
|
12611
12931
|
ALLOWED = [
|
|
12612
12932
|
"config",
|
|
12613
12933
|
"token",
|
|
@@ -12675,8 +12995,8 @@ function collectFields(parsed, allowClear) {
|
|
|
12675
12995
|
if (allowClear) out[spec.key] = null;
|
|
12676
12996
|
continue;
|
|
12677
12997
|
}
|
|
12678
|
-
const
|
|
12679
|
-
out[spec.key] = spec.num ? Number(
|
|
12998
|
+
const text4 = stringOpt(value2);
|
|
12999
|
+
out[spec.key] = spec.num ? Number(text4) : text4;
|
|
12680
13000
|
}
|
|
12681
13001
|
return out;
|
|
12682
13002
|
}
|
|
@@ -13596,7 +13916,7 @@ async function pmCommand(parsed, deps = {}) {
|
|
|
13596
13916
|
assertArgs(parsed, COMMON_OPTIONS, 4);
|
|
13597
13917
|
return pmProjectUse(await buildContext2(parsed, deps), requireId2(parsed.positionals[3], action3));
|
|
13598
13918
|
}
|
|
13599
|
-
|
|
13919
|
+
rejectWord(["pm", "project"], action3);
|
|
13600
13920
|
}
|
|
13601
13921
|
if (word === "next") {
|
|
13602
13922
|
assertArgs(parsed, [...COMMON_OPTIONS, "app", "project", "verbose"], 2);
|
|
@@ -13627,10 +13947,10 @@ async function pmCommand(parsed, deps = {}) {
|
|
|
13627
13947
|
return pmHandoff(await buildContext2(parsed, deps), parsed);
|
|
13628
13948
|
}
|
|
13629
13949
|
const entity = ALIASES[word];
|
|
13630
|
-
if (!entity)
|
|
13950
|
+
if (!entity) rejectWord(["pm"], word);
|
|
13631
13951
|
const requestedAction = parsed.positionals[2] ?? "list";
|
|
13632
13952
|
const action2 = canonicalAction(requestedAction);
|
|
13633
|
-
if (!action2)
|
|
13953
|
+
if (!action2) rejectWord(["pm", word], requestedAction);
|
|
13634
13954
|
assertArgs(parsed, allowedOptions(entity, action2), 4);
|
|
13635
13955
|
if ((action2 === "ready" || action2 === "claim" || action2 === "release") && entity !== "task") {
|
|
13636
13956
|
throw new Error(`pm ${action2} is only valid for tasks`);
|
|
@@ -13683,6 +14003,7 @@ var init_pm_command = __esm({
|
|
|
13683
14003
|
init_pm_watch();
|
|
13684
14004
|
init_pm_project_actions();
|
|
13685
14005
|
init_pm_project_context();
|
|
14006
|
+
init_surface();
|
|
13686
14007
|
ALIASES = {
|
|
13687
14008
|
goal: "goal",
|
|
13688
14009
|
conformance: "goal",
|
|
@@ -13792,12 +14113,7 @@ async function platformCommand(parsed, deps = {}) {
|
|
|
13792
14113
|
if (action2 === "status") {
|
|
13793
14114
|
return platformStatus(parsed, deps);
|
|
13794
14115
|
}
|
|
13795
|
-
|
|
13796
|
-
`unknown platform action "${[
|
|
13797
|
-
action2,
|
|
13798
|
-
parsed.positionals[2]
|
|
13799
|
-
].filter(Boolean).join(" ")}". Try "odla-ai platform status --json".`
|
|
13800
|
-
);
|
|
14116
|
+
rejectWord(["platform"], action2);
|
|
13801
14117
|
}
|
|
13802
14118
|
async function platformStatus(parsed, deps) {
|
|
13803
14119
|
assertArgs(
|
|
@@ -13863,6 +14179,7 @@ var init_platform_command = __esm({
|
|
|
13863
14179
|
init_argv();
|
|
13864
14180
|
init_operator_context();
|
|
13865
14181
|
init_platform_output();
|
|
14182
|
+
init_surface();
|
|
13866
14183
|
}
|
|
13867
14184
|
});
|
|
13868
14185
|
|
|
@@ -14156,9 +14473,7 @@ async function o11yCommand(parsed, deps = {}) {
|
|
|
14156
14473
|
);
|
|
14157
14474
|
const action2 = parsed.positionals[1];
|
|
14158
14475
|
if (action2 !== "status") {
|
|
14159
|
-
|
|
14160
|
-
`unknown o11y action "${action2 ?? ""}". Try "odla-ai o11y status --json".`
|
|
14161
|
-
);
|
|
14476
|
+
rejectWord(["o11y"], action2);
|
|
14162
14477
|
}
|
|
14163
14478
|
const minutes = statusMinutes(
|
|
14164
14479
|
numberOpt(parsed.options.minutes, "--minutes") ?? 60
|
|
@@ -14273,14 +14588,14 @@ function statusMinutes(value2) {
|
|
|
14273
14588
|
}
|
|
14274
14589
|
async function read2(url, headers, doFetch) {
|
|
14275
14590
|
const response2 = await doFetch(url, { headers });
|
|
14276
|
-
const
|
|
14591
|
+
const text4 = await response2.text();
|
|
14277
14592
|
let body = {};
|
|
14278
|
-
if (
|
|
14593
|
+
if (text4) {
|
|
14279
14594
|
try {
|
|
14280
|
-
const value2 = JSON.parse(
|
|
14595
|
+
const value2 = JSON.parse(text4);
|
|
14281
14596
|
body = value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : { value: value2 };
|
|
14282
14597
|
} catch {
|
|
14283
|
-
body = { message:
|
|
14598
|
+
body = { message: text4.slice(0, 300) };
|
|
14284
14599
|
}
|
|
14285
14600
|
}
|
|
14286
14601
|
return { httpStatus: response2.status, body };
|
|
@@ -14294,6 +14609,7 @@ var init_o11y_command = __esm({
|
|
|
14294
14609
|
init_o11y_verdict();
|
|
14295
14610
|
init_o11y_output();
|
|
14296
14611
|
init_token();
|
|
14612
|
+
init_surface();
|
|
14297
14613
|
}
|
|
14298
14614
|
});
|
|
14299
14615
|
|
|
@@ -14414,9 +14730,7 @@ var init_monitoring_config = __esm({
|
|
|
14414
14730
|
async function monitorCommand(parsed, deps = {}) {
|
|
14415
14731
|
assertArgs(parsed, OPTIONS, 3);
|
|
14416
14732
|
const action2 = parsed.positionals[1] ?? "status";
|
|
14417
|
-
if (!["
|
|
14418
|
-
throw new Error(`unknown monitor action "${action2}". Try "odla-ai monitor status --json".`);
|
|
14419
|
-
}
|
|
14733
|
+
if (!acceptedAfter(["monitor"]).includes(action2)) rejectWord(["monitor"], action2);
|
|
14420
14734
|
const context = await resolveOperatorContext(parsed, {
|
|
14421
14735
|
allowMissingConfig: action2 !== "plan" && action2 !== "apply",
|
|
14422
14736
|
requireApp: true
|
|
@@ -14513,13 +14827,13 @@ async function monitorCommand(parsed, deps = {}) {
|
|
|
14513
14827
|
}
|
|
14514
14828
|
async function request2(url, init, doFetch) {
|
|
14515
14829
|
const response2 = await doFetch(url, init);
|
|
14516
|
-
const
|
|
14830
|
+
const text4 = await response2.text();
|
|
14517
14831
|
let body = {};
|
|
14518
14832
|
try {
|
|
14519
|
-
const parsed =
|
|
14833
|
+
const parsed = text4 ? JSON.parse(text4) : {};
|
|
14520
14834
|
body = record10(parsed) ? parsed : { value: parsed };
|
|
14521
14835
|
} catch {
|
|
14522
|
-
body = { message:
|
|
14836
|
+
body = { message: text4.slice(0, 500) };
|
|
14523
14837
|
}
|
|
14524
14838
|
if (!response2.ok) {
|
|
14525
14839
|
const error = record10(body.error) ? body.error : body;
|
|
@@ -14570,6 +14884,7 @@ var init_monitor_command = __esm({
|
|
|
14570
14884
|
init_monitoring_config();
|
|
14571
14885
|
init_operator_context();
|
|
14572
14886
|
init_token();
|
|
14887
|
+
init_surface();
|
|
14573
14888
|
OPTIONS = [
|
|
14574
14889
|
"config",
|
|
14575
14890
|
"context",
|
|
@@ -14759,8 +15074,8 @@ function runtimeUrl(cfg, suffix = "") {
|
|
|
14759
15074
|
return `${cfg.platformUrl}/registry/apps/${encodeURIComponent(cfg.app.id)}/runtime-credentials${suffix}`;
|
|
14760
15075
|
}
|
|
14761
15076
|
async function safeError(response2) {
|
|
14762
|
-
const
|
|
14763
|
-
return redactSecrets(
|
|
15077
|
+
const text4 = await response2.text();
|
|
15078
|
+
return redactSecrets(text4.slice(0, 1e3));
|
|
14764
15079
|
}
|
|
14765
15080
|
async function finish(doFetch, cfg, token, sessionId, method) {
|
|
14766
15081
|
return doFetch(runtimeUrl(cfg, `/${encodeURIComponent(sessionId)}`), {
|
|
@@ -15119,182 +15434,6 @@ var init_provision = __esm({
|
|
|
15119
15434
|
}
|
|
15120
15435
|
});
|
|
15121
15436
|
|
|
15122
|
-
// src/surface.ts
|
|
15123
|
-
function acceptedAfter(path) {
|
|
15124
|
-
let node = COMMAND_SURFACE;
|
|
15125
|
-
for (const word of path) {
|
|
15126
|
-
node = node?.[word];
|
|
15127
|
-
if (!node) return [];
|
|
15128
|
-
}
|
|
15129
|
-
return Object.keys(node).sort();
|
|
15130
|
-
}
|
|
15131
|
-
function validateInvocation(words2) {
|
|
15132
|
-
let node = COMMAND_SURFACE;
|
|
15133
|
-
const walked = [];
|
|
15134
|
-
for (const word of words2) {
|
|
15135
|
-
if (Object.keys(node).length === 0) return null;
|
|
15136
|
-
const next = node[word];
|
|
15137
|
-
if (!next) return { validPrefix: walked.join(" "), word, accepted: Object.keys(node).sort() };
|
|
15138
|
-
walked.push(word);
|
|
15139
|
-
node = next;
|
|
15140
|
-
}
|
|
15141
|
-
return null;
|
|
15142
|
-
}
|
|
15143
|
-
function describeProblem(problem) {
|
|
15144
|
-
const where = problem.validPrefix ? `after "${problem.validPrefix}"` : "as a command";
|
|
15145
|
-
return `"${problem.word}" is not accepted ${where} \u2014 try: ${problem.accepted.join(", ")}`;
|
|
15146
|
-
}
|
|
15147
|
-
function invocationPath(words2) {
|
|
15148
|
-
let node = COMMAND_SURFACE;
|
|
15149
|
-
const path = [];
|
|
15150
|
-
for (const word of words2) {
|
|
15151
|
-
const next = node[word];
|
|
15152
|
-
if (!next) break;
|
|
15153
|
-
path.push(word);
|
|
15154
|
-
node = next;
|
|
15155
|
-
if (Object.keys(node).length === 0) break;
|
|
15156
|
-
}
|
|
15157
|
-
return path;
|
|
15158
|
-
}
|
|
15159
|
-
var PM_ACTIONS, PM_TASK_ACTIONS, PM_ENTITIES, COMMAND_SURFACE;
|
|
15160
|
-
var init_surface = __esm({
|
|
15161
|
-
"src/surface.ts"() {
|
|
15162
|
-
"use strict";
|
|
15163
|
-
init_cjs_shims();
|
|
15164
|
-
PM_ACTIONS = {
|
|
15165
|
-
list: {},
|
|
15166
|
-
add: {},
|
|
15167
|
-
create: {},
|
|
15168
|
-
get: {},
|
|
15169
|
-
set: {},
|
|
15170
|
-
update: {},
|
|
15171
|
-
status: {},
|
|
15172
|
-
move: {},
|
|
15173
|
-
done: {},
|
|
15174
|
-
comment: {},
|
|
15175
|
-
comments: {},
|
|
15176
|
-
ref: {},
|
|
15177
|
-
rm: {},
|
|
15178
|
-
delete: {}
|
|
15179
|
-
};
|
|
15180
|
-
PM_TASK_ACTIONS = {
|
|
15181
|
-
...PM_ACTIONS,
|
|
15182
|
-
ready: {},
|
|
15183
|
-
claim: {},
|
|
15184
|
-
release: {}
|
|
15185
|
-
};
|
|
15186
|
-
PM_ENTITIES = {
|
|
15187
|
-
...Object.fromEntries(
|
|
15188
|
-
["goal", "conformance", "decision", "bug"].map((entity) => [entity, PM_ACTIONS])
|
|
15189
|
-
),
|
|
15190
|
-
task: PM_TASK_ACTIONS,
|
|
15191
|
-
kanban: PM_TASK_ACTIONS
|
|
15192
|
-
};
|
|
15193
|
-
COMMAND_SURFACE = {
|
|
15194
|
-
agent: { jobs: {}, retry: {} },
|
|
15195
|
-
ai: { models: {} },
|
|
15196
|
-
admin: {
|
|
15197
|
-
ai: {
|
|
15198
|
-
show: {},
|
|
15199
|
-
set: {},
|
|
15200
|
-
credentials: {},
|
|
15201
|
-
models: {},
|
|
15202
|
-
usage: {},
|
|
15203
|
-
audit: {},
|
|
15204
|
-
credential: { set: {} }
|
|
15205
|
-
}
|
|
15206
|
-
},
|
|
15207
|
-
app: {
|
|
15208
|
-
archive: {},
|
|
15209
|
-
restore: {},
|
|
15210
|
-
export: {},
|
|
15211
|
-
import: {},
|
|
15212
|
-
rename: {},
|
|
15213
|
-
"refresh-sandbox": {},
|
|
15214
|
-
"go-live": {},
|
|
15215
|
-
promote: {},
|
|
15216
|
-
owners: { list: {}, add: {}, remove: {} }
|
|
15217
|
-
},
|
|
15218
|
-
auth: { login: {} },
|
|
15219
|
-
brand: { design: { unpack: {} } },
|
|
15220
|
-
bug: { create: {}, list: {}, report: {} },
|
|
15221
|
-
calendar: { status: {}, calendars: {}, connect: {}, disconnect: {} },
|
|
15222
|
-
capabilities: {},
|
|
15223
|
-
code: {
|
|
15224
|
-
connect: {},
|
|
15225
|
-
grant: { request: {}, list: {}, approve: {}, revoke: {} },
|
|
15226
|
-
repository: { show: {}, list: {}, bind: {} }
|
|
15227
|
-
},
|
|
15228
|
-
config: { diff: {}, plan: {}, apply: {} },
|
|
15229
|
-
context: { show: {}, list: {}, save: {}, remove: {} },
|
|
15230
|
-
credentials: { list: {}, revoke: {} },
|
|
15231
|
-
device: { enroll: {}, list: {}, revoke: {} },
|
|
15232
|
-
// `watch`, `read`, `reply`, and `resolve` take a topic id from there on.
|
|
15233
|
-
discuss: {
|
|
15234
|
-
groups: {},
|
|
15235
|
-
list: {},
|
|
15236
|
-
topics: {},
|
|
15237
|
-
read: {},
|
|
15238
|
-
post: {},
|
|
15239
|
-
reply: {},
|
|
15240
|
-
resolve: {},
|
|
15241
|
-
who: {},
|
|
15242
|
-
watch: {}
|
|
15243
|
-
},
|
|
15244
|
-
doctor: {},
|
|
15245
|
-
help: {},
|
|
15246
|
-
init: {},
|
|
15247
|
-
monitor: { plan: {}, apply: {}, run: {}, status: {}, incidents: {}, report: {} },
|
|
15248
|
-
o11y: { status: {} },
|
|
15249
|
-
operations: { get: {}, wait: {} },
|
|
15250
|
-
platform: {
|
|
15251
|
-
status: {}
|
|
15252
|
-
},
|
|
15253
|
-
pm: {
|
|
15254
|
-
...PM_ENTITIES,
|
|
15255
|
-
project: { list: {}, add: {}, create: {}, use: {} },
|
|
15256
|
-
handoff: {},
|
|
15257
|
-
next: {},
|
|
15258
|
-
watch: {}
|
|
15259
|
-
},
|
|
15260
|
-
provision: {},
|
|
15261
|
-
runbook: {
|
|
15262
|
-
ask: {},
|
|
15263
|
-
search: {},
|
|
15264
|
-
impact: {},
|
|
15265
|
-
list: {},
|
|
15266
|
-
get: {},
|
|
15267
|
-
cat: {},
|
|
15268
|
-
new: {},
|
|
15269
|
-
edit: {},
|
|
15270
|
-
comment: {},
|
|
15271
|
-
import: {},
|
|
15272
|
-
visibility: {},
|
|
15273
|
-
publish: {},
|
|
15274
|
-
archive: {},
|
|
15275
|
-
history: {},
|
|
15276
|
-
revert: {},
|
|
15277
|
-
rm: {},
|
|
15278
|
-
lint: {}
|
|
15279
|
-
},
|
|
15280
|
-
secrets: { push: {}, status: {}, set: {}, "set-clerk-key": {} },
|
|
15281
|
-
security: {
|
|
15282
|
-
plan: {},
|
|
15283
|
-
sources: {},
|
|
15284
|
-
run: {},
|
|
15285
|
-
status: {},
|
|
15286
|
-
report: {},
|
|
15287
|
-
github: { connect: {}, disconnect: {} }
|
|
15288
|
-
},
|
|
15289
|
-
setup: {},
|
|
15290
|
-
skill: { install: {} },
|
|
15291
|
-
smoke: {},
|
|
15292
|
-
version: {},
|
|
15293
|
-
whoami: {}
|
|
15294
|
-
};
|
|
15295
|
-
}
|
|
15296
|
-
});
|
|
15297
|
-
|
|
15298
15437
|
// src/record.ts
|
|
15299
15438
|
function recordInvocation(parsed) {
|
|
15300
15439
|
const file = import_node_process18.default.env.ODLA_CLI_RECORD;
|
|
@@ -15361,10 +15500,10 @@ var init_advisory_output = __esm({
|
|
|
15361
15500
|
// src/device-ttl.ts
|
|
15362
15501
|
function parseDeviceTtl(raw) {
|
|
15363
15502
|
if (raw === void 0 || raw === true) return void 0;
|
|
15364
|
-
const
|
|
15365
|
-
if (!
|
|
15366
|
-
if (
|
|
15367
|
-
const match = /^(\d+)\s*([dwy])$/.exec(
|
|
15503
|
+
const text4 = String(raw).trim().toLowerCase();
|
|
15504
|
+
if (!text4) return void 0;
|
|
15505
|
+
if (text4 === "forever" || text4 === "never") return 100 * 365 * DAY_MS;
|
|
15506
|
+
const match = /^(\d+)\s*([dwy])$/.exec(text4);
|
|
15368
15507
|
if (!match) {
|
|
15369
15508
|
throw new Error(
|
|
15370
15509
|
`--device-ttl expects a duration like 30d, 6w, 2y, or "forever" (got "${raw}")`
|
|
@@ -15402,6 +15541,7 @@ async function deviceCommand(parsed, deps) {
|
|
|
15402
15541
|
"wait"
|
|
15403
15542
|
], 3);
|
|
15404
15543
|
const action2 = parsed.positionals[1] ?? "";
|
|
15544
|
+
if (!acceptedAfter(["device"]).includes(action2)) rejectWord(["device"], action2);
|
|
15405
15545
|
const out = deps.stdout ?? console;
|
|
15406
15546
|
const doFetch = deps.fetch ?? fetch;
|
|
15407
15547
|
const cfg = await loadProjectConfig(stringOpt(parsed.options.config));
|
|
@@ -15409,7 +15549,7 @@ async function deviceCommand(parsed, deps) {
|
|
|
15409
15549
|
if (action2 === "enroll") return enroll(parsed, deps, cfg, doFetch, out, json);
|
|
15410
15550
|
if (action2 === "list") return list2(parsed, deps, cfg, doFetch, out, json);
|
|
15411
15551
|
if (action2 === "revoke") return revoke(parsed, deps, cfg, doFetch, out, json);
|
|
15412
|
-
|
|
15552
|
+
rejectWord(["device"], action2);
|
|
15413
15553
|
}
|
|
15414
15554
|
async function enroll(parsed, deps, cfg, doFetch, out, json) {
|
|
15415
15555
|
const name = stringOpt(parsed.options.name) ?? defaultDeviceName();
|
|
@@ -15579,6 +15719,7 @@ var init_device_command = __esm({
|
|
|
15579
15719
|
init_device_session();
|
|
15580
15720
|
init_config();
|
|
15581
15721
|
init_operator_context();
|
|
15722
|
+
init_surface();
|
|
15582
15723
|
}
|
|
15583
15724
|
});
|
|
15584
15725
|
|
|
@@ -15731,12 +15872,12 @@ var init_runbook_actions = __esm({
|
|
|
15731
15872
|
});
|
|
15732
15873
|
|
|
15733
15874
|
// src/runbook-import.ts
|
|
15734
|
-
function parseRunbook(
|
|
15735
|
-
let rest =
|
|
15875
|
+
function parseRunbook(text4, slug) {
|
|
15876
|
+
let rest = text4;
|
|
15736
15877
|
const meta = {};
|
|
15737
|
-
const fm = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(
|
|
15878
|
+
const fm = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(text4);
|
|
15738
15879
|
if (fm) {
|
|
15739
|
-
rest =
|
|
15880
|
+
rest = text4.slice(fm[0].length);
|
|
15740
15881
|
for (const line2 of fm[1].split(/\r?\n/)) {
|
|
15741
15882
|
const pair = /^(\w+)\s*:\s*(.+)$/.exec(line2.trim());
|
|
15742
15883
|
if (!pair) continue;
|
|
@@ -16367,6 +16508,7 @@ async function buildContext3(parsed, deps, action2) {
|
|
|
16367
16508
|
async function runbookCommand(parsed, deps = {}) {
|
|
16368
16509
|
const action2 = parsed.positionals[1] ?? "list";
|
|
16369
16510
|
assertArgs(parsed, ALLOWED2, action2 === "ask" || action2 === "search" ? 64 : 4);
|
|
16511
|
+
if (!acceptedAfter(["runbook"]).includes(action2)) rejectWord(["runbook"], action2);
|
|
16370
16512
|
const ctx = await buildContext3(parsed, deps, action2);
|
|
16371
16513
|
const slug = parsed.positionals[2];
|
|
16372
16514
|
switch (action2) {
|
|
@@ -16456,7 +16598,7 @@ async function runbookCommand(parsed, deps = {}) {
|
|
|
16456
16598
|
case "rm":
|
|
16457
16599
|
return runbookRemove(ctx, requireSlug(slug, "rm"));
|
|
16458
16600
|
default:
|
|
16459
|
-
|
|
16601
|
+
rejectWord(["runbook"], action2);
|
|
16460
16602
|
}
|
|
16461
16603
|
}
|
|
16462
16604
|
var ALLOWED2, WRITES2;
|
|
@@ -17165,9 +17307,7 @@ async function securityCommand(parsed, dependencies) {
|
|
|
17165
17307
|
else printHostedReport(context.stdout, report5);
|
|
17166
17308
|
return;
|
|
17167
17309
|
}
|
|
17168
|
-
if (sub !== "run")
|
|
17169
|
-
throw new Error('unknown security command. Try "odla-ai security plan", "security sources", or "security run".');
|
|
17170
|
-
}
|
|
17310
|
+
if (sub !== "run") rejectWord(["security"], sub);
|
|
17171
17311
|
const sourceId = stringOpt(parsed.options.source);
|
|
17172
17312
|
if (sourceId) await runSourceSecurityCommand(parsed, dependencies, sourceId);
|
|
17173
17313
|
else await runLocalSecurityCommand(parsed, dependencies);
|
|
@@ -17184,9 +17324,7 @@ async function githubSecurityCommand(parsed, dependencies) {
|
|
|
17184
17324
|
stringOpt(parsed.options.env)
|
|
17185
17325
|
);
|
|
17186
17326
|
}
|
|
17187
|
-
if (action2 !== "connect")
|
|
17188
|
-
throw new Error('unknown security github command. Try "odla-ai security github connect".');
|
|
17189
|
-
}
|
|
17327
|
+
if (action2 !== "connect") rejectWord(["security", "github"], action2);
|
|
17190
17328
|
assertArgs(parsed, ["config", "env", "platform", "repo", "email", "open"], 3);
|
|
17191
17329
|
await requireStudioHuman(
|
|
17192
17330
|
stringOpt(parsed.options.config) ?? "odla.config.mjs",
|
|
@@ -17242,6 +17380,7 @@ var init_security_command = __esm({
|
|
|
17242
17380
|
init_security_run_command();
|
|
17243
17381
|
init_security_hosted();
|
|
17244
17382
|
init_human_session();
|
|
17383
|
+
init_surface();
|
|
17245
17384
|
}
|
|
17246
17385
|
});
|
|
17247
17386
|
|
|
@@ -17346,6 +17485,7 @@ async function dispatchCli(argv2, dependencies) {
|
|
|
17346
17485
|
}
|
|
17347
17486
|
if (command === "bug") {
|
|
17348
17487
|
const action2 = parsed.positionals[1] ?? "list";
|
|
17488
|
+
if (!acceptedAfter(["bug"]).includes(action2)) rejectWord(["bug"], action2);
|
|
17349
17489
|
const canonical2 = action2 === "report" || action2 === "create" ? "add" : action2;
|
|
17350
17490
|
await pmCommand({
|
|
17351
17491
|
...parsed,
|
|
@@ -17374,7 +17514,7 @@ async function dispatchCli(argv2, dependencies) {
|
|
|
17374
17514
|
return;
|
|
17375
17515
|
}
|
|
17376
17516
|
if (await projectCommand(command, parsed, runtime)) return;
|
|
17377
|
-
|
|
17517
|
+
rejectWord([], command);
|
|
17378
17518
|
}
|
|
17379
17519
|
async function provisionCommand(parsed, dependencies) {
|
|
17380
17520
|
assertArgs(parsed, [
|
|
@@ -17418,7 +17558,7 @@ async function provisionCommand(parsed, dependencies) {
|
|
|
17418
17558
|
async function calendarCommand(parsed, dependencies) {
|
|
17419
17559
|
const sub = parsed.positionals[1];
|
|
17420
17560
|
if (sub !== "status" && sub !== "calendars" && sub !== "connect" && sub !== "disconnect") {
|
|
17421
|
-
|
|
17561
|
+
rejectWord(["calendar"], sub);
|
|
17422
17562
|
}
|
|
17423
17563
|
assertArgs(parsed, ["config", "env", "json", "token", "email", "open", "yes"], 2);
|
|
17424
17564
|
if (sub !== "status" && sub !== "calendars" && parsed.options.json !== void 0) throw new Error(`--json is supported only by calendar status/calendars`);
|
|
@@ -17472,6 +17612,7 @@ var init_cli = __esm({
|
|
|
17472
17612
|
init_runbook_command();
|
|
17473
17613
|
init_security_command();
|
|
17474
17614
|
init_whoami_command();
|
|
17615
|
+
init_surface();
|
|
17475
17616
|
init_exit_code();
|
|
17476
17617
|
}
|
|
17477
17618
|
});
|