@odla-ai/cli 0.30.3 → 0.31.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/README.md +4 -1
- package/dist/bin.cjs +154 -52
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-3HFNKDZV.js → chunk-Y3W7YKWI.js} +120 -37
- package/dist/chunk-Y3W7YKWI.js.map +1 -0
- package/dist/{cli-BGSX5Z4C.js → cli-Q2U7TCMV.js} +2 -2
- package/dist/index.cjs +131 -48
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-3HFNKDZV.js.map +0 -1
- /package/dist/{cli-BGSX5Z4C.js.map → cli-Q2U7TCMV.js.map} +0 -0
package/dist/bin.js
CHANGED
|
@@ -174,7 +174,7 @@ function absoluteEntryPath(entryPath) {
|
|
|
174
174
|
|
|
175
175
|
// src/bin.ts
|
|
176
176
|
var argv = process.argv.slice(2);
|
|
177
|
-
requireCurrentCliForProvision(argv).then(() => requireCoherentProvisionRuntime(argv)).then(async () => (await import("./cli-
|
|
177
|
+
requireCurrentCliForProvision(argv).then(() => requireCoherentProvisionRuntime(argv)).then(async () => (await import("./cli-Q2U7TCMV.js")).runCli()).catch((err) => {
|
|
178
178
|
console.error(redactSecrets(`odla-ai: ${err instanceof Error ? err.message : String(err)}`));
|
|
179
179
|
process.exitCode = exitCodeFor(err);
|
|
180
180
|
});
|
|
@@ -62,7 +62,7 @@ import process2 from "process";
|
|
|
62
62
|
async function openUrl(url, options = {}) {
|
|
63
63
|
const command = openerFor(options.platform ?? process2.platform);
|
|
64
64
|
const doSpawn = options.spawnImpl ?? spawn;
|
|
65
|
-
await new Promise((
|
|
65
|
+
await new Promise((resolve14, reject) => {
|
|
66
66
|
const child = doSpawn(command.cmd, [...command.args, url], {
|
|
67
67
|
stdio: "ignore",
|
|
68
68
|
detached: true
|
|
@@ -70,7 +70,7 @@ async function openUrl(url, options = {}) {
|
|
|
70
70
|
child.once("error", reject);
|
|
71
71
|
child.once("spawn", () => {
|
|
72
72
|
child.unref();
|
|
73
|
-
|
|
73
|
+
resolve14();
|
|
74
74
|
});
|
|
75
75
|
});
|
|
76
76
|
}
|
|
@@ -365,7 +365,7 @@ async function freshHandshake(ctx, waitMs) {
|
|
|
365
365
|
} catch (err) {
|
|
366
366
|
const code = err instanceof OdlaError ? err.code : void 0;
|
|
367
367
|
if (code === "handshake_pending" && started) throw stillPending(started, ctx.email);
|
|
368
|
-
if (code === "handshake_denied" || code === "handshake_expired" || code === "handshake_timeout") {
|
|
368
|
+
if (code === "handshake_duplicate" || code === "handshake_denied" || code === "handshake_expired" || code === "handshake_timeout") {
|
|
369
369
|
clearPendingHandshake(ctx.pendingFile);
|
|
370
370
|
}
|
|
371
371
|
throw err;
|
|
@@ -2470,8 +2470,8 @@ function credential(value2) {
|
|
|
2470
2470
|
// src/calendar-poll.ts
|
|
2471
2471
|
async function waitForCalendarPoll(milliseconds, signal) {
|
|
2472
2472
|
if (signal?.aborted) throw signal.reason ?? new Error("calendar connection aborted");
|
|
2473
|
-
await new Promise((
|
|
2474
|
-
const timer = setTimeout(
|
|
2473
|
+
await new Promise((resolve14, reject) => {
|
|
2474
|
+
const timer = setTimeout(resolve14, milliseconds);
|
|
2475
2475
|
signal?.addEventListener("abort", () => {
|
|
2476
2476
|
clearTimeout(timer);
|
|
2477
2477
|
reject(signal.reason ?? new Error("calendar connection aborted"));
|
|
@@ -3175,7 +3175,7 @@ async function configOperationWait(options) {
|
|
|
3175
3175
|
assertOperationId(options.operationId);
|
|
3176
3176
|
const cfg = await loadProjectConfig(options.configPath);
|
|
3177
3177
|
const client = await operationClient(cfg, options, "wait");
|
|
3178
|
-
const wait2 = options.pollWait ?? ((ms) => new Promise((
|
|
3178
|
+
const wait2 = options.pollWait ?? ((ms) => new Promise((resolve14) => setTimeout(resolve14, ms)));
|
|
3179
3179
|
const now = () => (options.now?.() ?? /* @__PURE__ */ new Date()).getTime();
|
|
3180
3180
|
const deadline = now() + (options.timeoutSeconds ?? DEFAULT_WAIT_SECONDS) * 1e3;
|
|
3181
3181
|
const interval = (options.intervalSeconds ?? DEFAULT_INTERVAL_SECONDS) * 1e3;
|
|
@@ -8026,8 +8026,8 @@ function hostedPollTimeout(value2 = 10 * 6e4) {
|
|
|
8026
8026
|
}
|
|
8027
8027
|
async function waitForHostedPoll(milliseconds, signal) {
|
|
8028
8028
|
if (signal?.aborted) throw signal.reason ?? new DOMException("aborted", "AbortError");
|
|
8029
|
-
await new Promise((
|
|
8030
|
-
const timer = setTimeout(
|
|
8029
|
+
await new Promise((resolve14, reject) => {
|
|
8030
|
+
const timer = setTimeout(resolve14, milliseconds);
|
|
8031
8031
|
signal?.addEventListener("abort", () => {
|
|
8032
8032
|
clearTimeout(timer);
|
|
8033
8033
|
reject(signal.reason ?? new DOMException("aborted", "AbortError"));
|
|
@@ -8774,13 +8774,16 @@ Usage:
|
|
|
8774
8774
|
odla-ai app rename <name> [continue in Studio; human session required]
|
|
8775
8775
|
odla-ai app owners <list|add|remove> [...] [continue in Studio; human session required]
|
|
8776
8776
|
odla-ai brand design unpack <bundle.html|-> [--out <dir>] [--json]
|
|
8777
|
-
odla-ai pm
|
|
8777
|
+
odla-ai pm project list [--app <product-id>] [--status <s>] [--json]
|
|
8778
|
+
odla-ai pm project add --app <product-id> --name <name> [--description <text>] [--json]
|
|
8779
|
+
odla-ai pm project use <project-id> [--json] [saved locally in this worktree]
|
|
8780
|
+
odla-ai pm goal list [--app <id>] [--project <id>] [--status <s>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
|
|
8778
8781
|
odla-ai pm task list [--app <id>] [--column <backlog|ready|doing|review|done>] [--goal <id>] [--assignee <id>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
|
|
8779
8782
|
odla-ai pm decision list [--app <id>] [--status <s>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
|
|
8780
8783
|
odla-ai pm bug list [--app <id>] [--status <s>] [--severity <s>] [--goal <id>] [--assignee <id>] [--decision <id>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
|
|
8781
8784
|
odla-ai pm goal add --app <id> --title <t> [--status <s>] [--proof <text>] [--target <pct>] [--mutation-id <id>] [--json]
|
|
8782
8785
|
odla-ai pm task add --app <id> --title <t> [--column <backlog|ready|doing|review|done>] [--goal <id>|--alignment-decision <id>] [--assignee <id>] [--description <text>|--body <text>] [--acceptance <text>] [--execution <human|agent|either>] [--due <epoch-ms>] [--mutation-id <id>] [--json]
|
|
8783
|
-
odla-ai pm next --app <id> [--json]
|
|
8786
|
+
odla-ai pm next --app <id> [--project <id>] [--json]
|
|
8784
8787
|
odla-ai pm watch --app <id> [--cursor <cursor>] [--entity goal|task|decision|bug] [--action created|updated|deleted|comment.created|comment.updated] [--state <state>] [--by <principalId>] [--self <principalId>] [--interval <s>] [--timeout <s>] [--json|--jsonl]
|
|
8785
8788
|
odla-ai pm task ready <id> --expected-revision <n> [--goal <id>|--alignment-decision <id>] [--description <text>|--body <text>] [--acceptance <text>] [--execution <human|agent|either>] [--mutation-id <id>] [--json]
|
|
8786
8789
|
odla-ai pm task claim <id> --expected-revision <n> [--mutation-id <id>] [--json]
|
|
@@ -8800,7 +8803,7 @@ Usage:
|
|
|
8800
8803
|
odla-ai pm <goal|task|decision|bug> comment <id> --body "..." [--mutation-id <id>]
|
|
8801
8804
|
odla-ai pm <goal|task|decision|bug> comments <id> [--json]
|
|
8802
8805
|
odla-ai pm <goal|task|decision|bug> rm <id>
|
|
8803
|
-
odla-ai pm handoff --app <id> [--json]
|
|
8806
|
+
odla-ai pm handoff --app <id> [--project <id>] [--json]
|
|
8804
8807
|
odla-ai discuss groups [--json]
|
|
8805
8808
|
odla-ai discuss list [--app <id>] [--q <text>] [--state open|resolved|all] [--json]
|
|
8806
8809
|
odla-ai discuss read <topic> [--limit <n> --offset <n>] [--json]
|
|
@@ -8933,13 +8936,12 @@ Commands:
|
|
|
8933
8936
|
code Enroll this Mac/Linux host for the current Studio-connected repository and run Pi.
|
|
8934
8937
|
admin Manage platform-funded AI routing/credentials/usage with narrow device grants.
|
|
8935
8938
|
security Connect GitHub sources and run commit-pinned hosted reviews, or scan a local snapshot.
|
|
8936
|
-
pm Project management (via @odla-ai/pm)
|
|
8937
|
-
|
|
8938
|
-
|
|
8939
|
-
|
|
8940
|
-
|
|
8941
|
-
|
|
8942
|
-
@odla-ai/chat discussion thread.
|
|
8939
|
+
pm Project management (via @odla-ai/pm): Products contain Projects;
|
|
8940
|
+
projects contain goals, kanban tasks, decisions, and bugs. Use
|
|
8941
|
+
"pm project list|add|use" to select worktree-local context, or
|
|
8942
|
+
pass --app/--project explicitly. Same device-grant auth as "app".
|
|
8943
|
+
Status changes and comments post to each item's @odla-ai/chat
|
|
8944
|
+
discussion thread.
|
|
8943
8945
|
bug Intent-first alias for PM bugs. "bug report" writes to
|
|
8944
8946
|
odla PM; odla product defects do not belong in GitHub Issues.
|
|
8945
8947
|
discuss Group discussions (via @odla-ai/chat) for the apps you co-own:
|
|
@@ -9346,7 +9348,7 @@ function jsonl(ctx, parsed, value2) {
|
|
|
9346
9348
|
}
|
|
9347
9349
|
async function discussWatch(ctx, topicId, parsed) {
|
|
9348
9350
|
if (ctx.json && parsed.options.jsonl === true) throw new Error("--json and --jsonl cannot be combined");
|
|
9349
|
-
const sleep = ctx.sleep ?? ((ms) => new Promise((
|
|
9351
|
+
const sleep = ctx.sleep ?? ((ms) => new Promise((resolve14) => setTimeout(resolve14, ms)));
|
|
9350
9352
|
const now = ctx.now ?? Date.now;
|
|
9351
9353
|
const intervalMs = (numberOpt2(parsed, "interval", DEFAULT_INTERVAL_MS / 1e3) ?? DEFAULT_INTERVAL_MS / 1e3) * 1e3;
|
|
9352
9354
|
const timeoutSeconds = numberOpt2(parsed, "timeout");
|
|
@@ -9694,6 +9696,8 @@ async function pmList(ctx, entity, parsed) {
|
|
|
9694
9696
|
};
|
|
9695
9697
|
const app = stringOpt(parsed.options.app) ?? ctx.appId;
|
|
9696
9698
|
if (app) q.set("app", app);
|
|
9699
|
+
const project = stringOpt(parsed.options.project) ?? ctx.projectId;
|
|
9700
|
+
if (project) q.set("project", project);
|
|
9697
9701
|
for (const [flag, param] of Object.entries(filters)) {
|
|
9698
9702
|
const raw = stringOpt(parsed.options[flag]);
|
|
9699
9703
|
const v = entity === "task" && flag === "column" && raw === "ready" ? "todo" : raw;
|
|
@@ -9713,6 +9717,7 @@ async function pmList(ctx, entity, parsed) {
|
|
|
9713
9717
|
}
|
|
9714
9718
|
async function pmAdd(ctx, entity, parsed) {
|
|
9715
9719
|
const appId = stringOpt(parsed.options.app) ?? ctx.appId;
|
|
9720
|
+
const projectId = stringOpt(parsed.options.project) ?? ctx.projectId;
|
|
9716
9721
|
if (!appId) throw new Error("pm add needs --app <appId>");
|
|
9717
9722
|
const input = collectEntityFields(entity, parsed, false);
|
|
9718
9723
|
if (!input.title) throw new Error("pm add needs --title <title>");
|
|
@@ -9720,6 +9725,7 @@ async function pmAdd(ctx, entity, parsed) {
|
|
|
9720
9725
|
throw new Error("pm bug add needs --description <context> (or --body <context>)");
|
|
9721
9726
|
const res = await pmRequest(ctx, "POST", `/${entity}`, {
|
|
9722
9727
|
appId,
|
|
9728
|
+
...projectId ? { projectId } : {},
|
|
9723
9729
|
input,
|
|
9724
9730
|
mutationId: writeMutationId2(parsed)
|
|
9725
9731
|
});
|
|
@@ -9799,7 +9805,7 @@ async function pmTaskLifecycle(ctx, id, action2, parsed) {
|
|
|
9799
9805
|
ctx.out.log(`task: ${label} \u2192 ${state2}`);
|
|
9800
9806
|
});
|
|
9801
9807
|
}
|
|
9802
|
-
async function allRecords(ctx, entity, appId) {
|
|
9808
|
+
async function allRecords(ctx, entity, appId, projectId) {
|
|
9803
9809
|
const records = [];
|
|
9804
9810
|
for (; ; ) {
|
|
9805
9811
|
const q = new URLSearchParams({
|
|
@@ -9807,6 +9813,7 @@ async function allRecords(ctx, entity, appId) {
|
|
|
9807
9813
|
limit: "100",
|
|
9808
9814
|
offset: String(records.length)
|
|
9809
9815
|
});
|
|
9816
|
+
if (projectId) q.set("project", projectId);
|
|
9810
9817
|
const page2 = await pmRequest(ctx, "GET", `/${entity}?${q}`);
|
|
9811
9818
|
records.push(...page2.records);
|
|
9812
9819
|
if (records.length >= page2.total || page2.records.length === 0) return records;
|
|
@@ -9814,13 +9821,15 @@ async function allRecords(ctx, entity, appId) {
|
|
|
9814
9821
|
}
|
|
9815
9822
|
async function pmNext(ctx, parsed) {
|
|
9816
9823
|
const appId = stringOpt(parsed.options.app) ?? ctx.appId;
|
|
9824
|
+
const projectId = stringOpt(parsed.options.project) ?? ctx.projectId;
|
|
9817
9825
|
if (!appId) throw new Error("pm next needs --app <appId>");
|
|
9818
9826
|
const [goals, tasks] = await Promise.all([
|
|
9819
|
-
allRecords(ctx, "goal", appId),
|
|
9820
|
-
allRecords(ctx, "task", appId)
|
|
9827
|
+
allRecords(ctx, "goal", appId, projectId),
|
|
9828
|
+
allRecords(ctx, "task", appId, projectId)
|
|
9821
9829
|
]);
|
|
9822
9830
|
const result = {
|
|
9823
9831
|
appId,
|
|
9832
|
+
projectId,
|
|
9824
9833
|
openGoals: goals.filter((record10) => record10.status === "open"),
|
|
9825
9834
|
doing: tasks.filter((record10) => record10.column === "doing"),
|
|
9826
9835
|
ready: tasks.filter((record10) => record10.column === "todo")
|
|
@@ -9851,14 +9860,16 @@ async function pmNext(ctx, parsed) {
|
|
|
9851
9860
|
}
|
|
9852
9861
|
async function pmHandoff(ctx, parsed) {
|
|
9853
9862
|
const appId = stringOpt(parsed.options.app) ?? ctx.appId;
|
|
9863
|
+
const projectId = stringOpt(parsed.options.project) ?? ctx.projectId;
|
|
9854
9864
|
if (!appId) throw new Error("pm handoff needs --app <appId>");
|
|
9855
9865
|
const [goals, tasks, bugs] = await Promise.all([
|
|
9856
|
-
allRecords(ctx, "goal", appId),
|
|
9857
|
-
allRecords(ctx, "task", appId),
|
|
9858
|
-
allRecords(ctx, "bug", appId)
|
|
9866
|
+
allRecords(ctx, "goal", appId, projectId),
|
|
9867
|
+
allRecords(ctx, "task", appId, projectId),
|
|
9868
|
+
allRecords(ctx, "bug", appId, projectId)
|
|
9859
9869
|
]);
|
|
9860
9870
|
const handoff = {
|
|
9861
9871
|
appId,
|
|
9872
|
+
projectId,
|
|
9862
9873
|
unmetGoals: goals.filter((record10) => record10.status !== "met"),
|
|
9863
9874
|
activeTasks: tasks.filter((record10) => record10.column !== "done"),
|
|
9864
9875
|
openBugs: bugs.filter((record10) => record10.status !== "fixed" && record10.status !== "wontfix")
|
|
@@ -10023,7 +10034,7 @@ async function pmWatch(ctx, parsed) {
|
|
|
10023
10034
|
}
|
|
10024
10035
|
const appId = stringOpt(parsed.options.app) ?? ctx.appId;
|
|
10025
10036
|
if (!appId) throw new Error("pm watch needs --app <appId>");
|
|
10026
|
-
const sleep = ctx.sleep ?? ((ms) => new Promise((
|
|
10037
|
+
const sleep = ctx.sleep ?? ((ms) => new Promise((resolve14) => setTimeout(resolve14, ms)));
|
|
10027
10038
|
const now = ctx.now ?? Date.now;
|
|
10028
10039
|
const intervalMs = (positiveNumber(parsed, "interval", DEFAULT_INTERVAL_MS2 / 1e3) ?? DEFAULT_INTERVAL_MS2 / 1e3) * 1e3;
|
|
10029
10040
|
const timeoutSeconds = positiveNumber(parsed, "timeout");
|
|
@@ -10132,6 +10143,56 @@ async function pmWatch(ctx, parsed) {
|
|
|
10132
10143
|
}
|
|
10133
10144
|
}
|
|
10134
10145
|
|
|
10146
|
+
// src/pm-project-context.ts
|
|
10147
|
+
import { resolve as resolve12 } from "path";
|
|
10148
|
+
var pmProjectContextFile = (rootDir) => resolve12(rootDir, ".odla", "pm-project.local.json");
|
|
10149
|
+
function readPmProjectContext(rootDir) {
|
|
10150
|
+
const value2 = readJsonFile(pmProjectContextFile(rootDir));
|
|
10151
|
+
return value2 && typeof value2.appId === "string" && typeof value2.projectId === "string" ? value2 : null;
|
|
10152
|
+
}
|
|
10153
|
+
function writePmProjectContext(rootDir, value2) {
|
|
10154
|
+
writePrivateJson(pmProjectContextFile(rootDir), { ...value2, selectedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
10155
|
+
}
|
|
10156
|
+
|
|
10157
|
+
// src/pm-project-actions.ts
|
|
10158
|
+
async function pmProjectList(ctx, parsed) {
|
|
10159
|
+
const q = new URLSearchParams();
|
|
10160
|
+
const app = stringOpt(parsed.options.app) ?? ctx.appId;
|
|
10161
|
+
if (app) q.set("app", app);
|
|
10162
|
+
for (const key of ["status", "limit", "offset"]) {
|
|
10163
|
+
const value2 = stringOpt(parsed.options[key]);
|
|
10164
|
+
if (value2) q.set(key, value2);
|
|
10165
|
+
}
|
|
10166
|
+
const page2 = await pmRequest(ctx, "GET", `/project?${q}`);
|
|
10167
|
+
emit2(ctx, page2, () => {
|
|
10168
|
+
ctx.out.log(`projects \u2014 ${page2.records.length} of ${page2.total}`);
|
|
10169
|
+
ctx.out.log("id status product name");
|
|
10170
|
+
for (const project of page2.records) {
|
|
10171
|
+
ctx.out.log(`${project.id} ${project.status} ${project.appId} ${project.name}${project.isDefault ? " (default)" : ""}`);
|
|
10172
|
+
}
|
|
10173
|
+
});
|
|
10174
|
+
}
|
|
10175
|
+
async function pmProjectAdd(ctx, parsed) {
|
|
10176
|
+
const appId = stringOpt(parsed.options.app) ?? ctx.appId;
|
|
10177
|
+
const name = stringOpt(parsed.options.name);
|
|
10178
|
+
if (!appId) throw new Error("pm project add needs --app <productId>");
|
|
10179
|
+
if (!name) throw new Error("pm project add needs --name <name>");
|
|
10180
|
+
const result = await pmRequest(ctx, "POST", "/project", {
|
|
10181
|
+
appId,
|
|
10182
|
+
name,
|
|
10183
|
+
description: stringOpt(parsed.options.description),
|
|
10184
|
+
mutationId: writeMutationId2(parsed)
|
|
10185
|
+
});
|
|
10186
|
+
emit2(ctx, result, () => ctx.out.log(`created project: ${result.project.name} (${result.project.id})`));
|
|
10187
|
+
}
|
|
10188
|
+
async function pmProjectUse(ctx, id) {
|
|
10189
|
+
if (!ctx.rootDir) throw new Error("pm project use needs a local project directory");
|
|
10190
|
+
const { project } = await pmRequest(ctx, "GET", `/project/${encodeURIComponent(id)}`);
|
|
10191
|
+
if (project.status !== "active") throw new Error(`project ${project.name} is ${project.status}, not active`);
|
|
10192
|
+
writePmProjectContext(ctx.rootDir, { appId: project.appId, projectId: project.id });
|
|
10193
|
+
emit2(ctx, project, () => ctx.out.log(`using ${project.appId} / ${project.name} (${project.id}) in this worktree`));
|
|
10194
|
+
}
|
|
10195
|
+
|
|
10135
10196
|
// src/pm-command.ts
|
|
10136
10197
|
var ALIASES = {
|
|
10137
10198
|
goal: "goal",
|
|
@@ -10143,8 +10204,8 @@ var ALIASES = {
|
|
|
10143
10204
|
};
|
|
10144
10205
|
var COMMON_OPTIONS = ["config", "token", "email", "json", "platform", "context", "open"];
|
|
10145
10206
|
var ACTION_OPTIONS = {
|
|
10146
|
-
list: ["app", "q", "limit", "offset"],
|
|
10147
|
-
add: ["app", "title", "mutation-id"],
|
|
10207
|
+
list: ["app", "project", "q", "limit", "offset"],
|
|
10208
|
+
add: ["app", "project", "title", "mutation-id"],
|
|
10148
10209
|
get: [],
|
|
10149
10210
|
set: ["mutation-id"],
|
|
10150
10211
|
done: ["mutation-id"],
|
|
@@ -10216,6 +10277,9 @@ async function buildContext2(parsed, deps) {
|
|
|
10216
10277
|
doFetch,
|
|
10217
10278
|
out
|
|
10218
10279
|
);
|
|
10280
|
+
const selectedProject = readPmProjectContext(cfg.rootDir);
|
|
10281
|
+
const requestedApp = stringOpt(parsed.options.app) ?? (context.app.source === "environment" || context.app.source === "profile" ? context.app.value ?? void 0 : void 0);
|
|
10282
|
+
const compatibleProject = selectedProject && (!requestedApp || selectedProject.appId === requestedApp) ? selectedProject : null;
|
|
10219
10283
|
return {
|
|
10220
10284
|
platformUrl: cfg.platformUrl,
|
|
10221
10285
|
token,
|
|
@@ -10224,15 +10288,33 @@ async function buildContext2(parsed, deps) {
|
|
|
10224
10288
|
json: parsed.options.json === true,
|
|
10225
10289
|
// Preserve PM's existing cross-project default when a config is present;
|
|
10226
10290
|
// only an explicit remote-agent environment or profile selects an app.
|
|
10227
|
-
appId: context.app.source === "environment" || context.app.source === "profile" ? context.app.value ?? void 0 :
|
|
10291
|
+
appId: context.app.source === "environment" || context.app.source === "profile" ? context.app.value ?? void 0 : compatibleProject?.appId,
|
|
10292
|
+
projectId: compatibleProject?.projectId,
|
|
10293
|
+
rootDir: cfg.rootDir,
|
|
10228
10294
|
...deps.sleep ? { sleep: deps.sleep } : {},
|
|
10229
10295
|
...deps.now ? { now: deps.now } : {}
|
|
10230
10296
|
};
|
|
10231
10297
|
}
|
|
10232
10298
|
async function pmCommand(parsed, deps = {}) {
|
|
10233
10299
|
const word = parsed.positionals[1] ?? "";
|
|
10300
|
+
if (word === "project") {
|
|
10301
|
+
const action3 = parsed.positionals[2] ?? "list";
|
|
10302
|
+
if (action3 === "list") {
|
|
10303
|
+
assertArgs(parsed, [...COMMON_OPTIONS, "app", "status", "limit", "offset"], 3);
|
|
10304
|
+
return pmProjectList(await buildContext2(parsed, deps), parsed);
|
|
10305
|
+
}
|
|
10306
|
+
if (action3 === "add" || action3 === "create") {
|
|
10307
|
+
assertArgs(parsed, [...COMMON_OPTIONS, "app", "name", "description", "mutation-id"], 3);
|
|
10308
|
+
return pmProjectAdd(await buildContext2(parsed, deps), parsed);
|
|
10309
|
+
}
|
|
10310
|
+
if (action3 === "use") {
|
|
10311
|
+
assertArgs(parsed, COMMON_OPTIONS, 4);
|
|
10312
|
+
return pmProjectUse(await buildContext2(parsed, deps), requireId2(parsed.positionals[3], action3));
|
|
10313
|
+
}
|
|
10314
|
+
throw new Error(`unknown pm project action "${action3}". Try list|add|use.`);
|
|
10315
|
+
}
|
|
10234
10316
|
if (word === "next") {
|
|
10235
|
-
assertArgs(parsed, [...COMMON_OPTIONS, "app"], 2);
|
|
10317
|
+
assertArgs(parsed, [...COMMON_OPTIONS, "app", "project"], 2);
|
|
10236
10318
|
return pmNext(await buildContext2(parsed, deps), parsed);
|
|
10237
10319
|
}
|
|
10238
10320
|
if (word === "watch") {
|
|
@@ -10252,7 +10334,7 @@ async function pmCommand(parsed, deps = {}) {
|
|
|
10252
10334
|
return pmWatch(await buildContext2(parsed, deps), parsed).then(() => void 0);
|
|
10253
10335
|
}
|
|
10254
10336
|
if (word === "handoff") {
|
|
10255
|
-
assertArgs(parsed, [...COMMON_OPTIONS, "app"], 2);
|
|
10337
|
+
assertArgs(parsed, [...COMMON_OPTIONS, "app", "project"], 2);
|
|
10256
10338
|
return pmHandoff(await buildContext2(parsed, deps), parsed);
|
|
10257
10339
|
}
|
|
10258
10340
|
const entity = ALIASES[word];
|
|
@@ -11384,6 +11466,7 @@ var COMMAND_SURFACE = {
|
|
|
11384
11466
|
},
|
|
11385
11467
|
pm: {
|
|
11386
11468
|
...PM_ENTITIES,
|
|
11469
|
+
project: { list: {}, add: {}, create: {}, use: {} },
|
|
11387
11470
|
handoff: {},
|
|
11388
11471
|
next: {},
|
|
11389
11472
|
watch: {}
|
|
@@ -12473,7 +12556,7 @@ function hostedSeverity(value2, flag) {
|
|
|
12473
12556
|
import { findingsAtOrAbove } from "@odla-ai/security";
|
|
12474
12557
|
|
|
12475
12558
|
// src/security.ts
|
|
12476
|
-
import { isAbsolute as isAbsolute5, relative as relative5, resolve as
|
|
12559
|
+
import { isAbsolute as isAbsolute5, relative as relative5, resolve as resolve13, sep as sep4 } from "path";
|
|
12477
12560
|
import {
|
|
12478
12561
|
cloudflareAppProfile,
|
|
12479
12562
|
createPlatformSecurityReasoners,
|
|
@@ -12492,8 +12575,8 @@ async function runHostedSecurity(options) {
|
|
|
12492
12575
|
const appId = selfAudit ? "odla-ai" : cfg.app.id;
|
|
12493
12576
|
const env = selfAudit ? "prod" : selectEnv(options.env, cfg.envs, cfg.configPath, cfg.rootDir);
|
|
12494
12577
|
const platform = options.platform ?? cfg?.platformUrl ?? "https://odla.ai";
|
|
12495
|
-
const target =
|
|
12496
|
-
const output =
|
|
12578
|
+
const target = resolve13(options.target ?? cfg?.rootDir ?? ".");
|
|
12579
|
+
const output = resolve13(options.out ?? resolve13(target, ".odla/security/hosted"));
|
|
12497
12580
|
const outputRelative = relative5(target, output).split(sep4).join("/");
|
|
12498
12581
|
if (!outputRelative) throw new Error("Hosted security output cannot be the repository root");
|
|
12499
12582
|
const profile = profileFor(options.profile ?? "odla", options.maxHuntTasks ?? 12);
|
|
@@ -12524,7 +12607,7 @@ async function runHostedSecurity(options) {
|
|
|
12524
12607
|
});
|
|
12525
12608
|
const harness = createSecurityHarness({
|
|
12526
12609
|
profile,
|
|
12527
|
-
store: new FileRunStore(
|
|
12610
|
+
store: new FileRunStore(resolve13(output, "state")),
|
|
12528
12611
|
discoveryReasoner: hosted.discoveryReasoner,
|
|
12529
12612
|
validationReasoner: hosted.validationReasoner,
|
|
12530
12613
|
policy: {
|
|
@@ -12577,7 +12660,7 @@ function printSummary(out, appId, env, run, report4, output) {
|
|
|
12577
12660
|
out.log(` coverage: ${report4.coverageStatus} ${complete}/${report4.coverage.length} blocked=${report4.metrics.blockedCells} shallow=${report4.metrics.shallowCells} unscheduled=${report4.metrics.unscheduledCells} budget_exhausted=${report4.metrics.budgetExhaustedCells}`);
|
|
12578
12661
|
if (report4.callBudget) out.log(` calls: discovery=${formatBudget(report4.callBudget.discovery)} validation=${formatBudget(report4.callBudget.validation)}`);
|
|
12579
12662
|
out.log(` findings: confirmed=${report4.metrics.confirmed} needs_reproduction=${report4.metrics.needsReproduction} candidates=${report4.metrics.candidates}`);
|
|
12580
|
-
out.log(` report: ${
|
|
12663
|
+
out.log(` report: ${resolve13(output, "REPORT.md")}`);
|
|
12581
12664
|
}
|
|
12582
12665
|
function formatBudget(usage) {
|
|
12583
12666
|
return usage ? `${usage.usedCalls}/${usage.maxCalls} skipped=${usage.skippedCalls}` : "caller-managed";
|
|
@@ -13237,4 +13320,4 @@ export {
|
|
|
13237
13320
|
isTerminalHostedSecurityStatus,
|
|
13238
13321
|
runCli
|
|
13239
13322
|
};
|
|
13240
|
-
//# sourceMappingURL=chunk-
|
|
13323
|
+
//# sourceMappingURL=chunk-Y3W7YKWI.js.map
|