@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/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-BGSX5Z4C.js")).runCli()).catch((err) => {
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((resolve13, reject) => {
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
- resolve13();
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((resolve13, reject) => {
2474
- const timer = setTimeout(resolve13, milliseconds);
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((resolve13) => setTimeout(resolve13, ms)));
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((resolve13, reject) => {
8030
- const timer = setTimeout(resolve13, milliseconds);
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 goal list [--app <id>] [--status <s>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
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) shared across the apps you
8937
- co-own: conformance goals, kanban tasks, decisions, and bugs. With
8938
- no --app, "list" spans every co-owned project (the cross-project
8939
- view); with --app it scopes to one. Same device-grant auth as
8940
- "app". Entities: goal (alias conformance), task (alias kanban),
8941
- decision, bug. Status changes and comments post to each item's
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((resolve13) => setTimeout(resolve13, ms)));
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((resolve13) => setTimeout(resolve13, ms)));
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 : 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 resolve12, sep as sep4 } from "path";
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 = resolve12(options.target ?? cfg?.rootDir ?? ".");
12496
- const output = resolve12(options.out ?? resolve12(target, ".odla/security/hosted"));
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(resolve12(output, "state")),
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: ${resolve12(output, "REPORT.md")}`);
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-3HFNKDZV.js.map
13323
+ //# sourceMappingURL=chunk-Y3W7YKWI.js.map