@odla-ai/cli 0.46.6 → 0.46.8

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 CHANGED
@@ -103,6 +103,8 @@ npx --yes @odla-ai/cli@latest pm next --app <appId> --project <projectId>
103
103
  npx --yes @odla-ai/cli@latest pm handoff --app <appId>
104
104
  npx --yes @odla-ai/cli@latest pm watch --app <appId> --entity task --jsonl
105
105
  npx --yes @odla-ai/cli@latest pm bug list --app <appId> --status open
106
+ npx --yes @odla-ai/cli@latest pm bug list --platform-wide --status open
107
+ npx --yes @odla-ai/cli@latest pm bug get <uuid-or-unique-prefix> --platform-wide
106
108
  npx --yes @odla-ai/cli@latest pm goal list --app <appId> --status open
107
109
  npx --yes @odla-ai/cli@latest pm decision list --app <appId> --limit 20
108
110
  ```
@@ -116,7 +118,12 @@ it with `pm bug done <id> --decision <decision-id>` or
116
118
 
117
119
  Read the active task, linked goal, and comments before changing code. Without
118
120
  `--app`, list commands span every project the account co-owns, which is the
119
- right first view when coordinating several efforts; scope every write to the
121
+ right first view when coordinating several efforts. A platform administrator
122
+ can approve the dedicated `platform:pm:read` capability used by
123
+ `pm <goal|task|decision|bug> list|get --platform-wide`; it reads core records
124
+ across current app lifetimes but cannot read comments/history or perform any PM
125
+ mutation. `get` accepts a unique UUID prefix and refuses missing or ambiguous
126
+ matches. Scope every write to the
120
127
  exact `appId` from that project's config. PM requires a registered app. Before
121
128
  the first provision, use a focused commit/checkpoint, then initialize PM and
122
129
  backfill that evidence immediately after registration. Never use a parallel
package/dist/bin.cjs CHANGED
@@ -1134,6 +1134,7 @@ var init_admin_ai_auth = __esm({
1134
1134
  init_odla_home();
1135
1135
  SCOPE_PURPOSE = {
1136
1136
  "platform:status:read": "read the platform fleet health and deployment snapshot",
1137
+ "platform:pm:read": "read the core PM inventory across all current odla projects",
1137
1138
  "app:config:read": "compare checked-in intent with an exact-id app Registry configuration",
1138
1139
  "app:config:write": "apply or inspect one revision-bound configuration operation for an app you own",
1139
1140
  "platform:runbook:write": "read and edit all of odla's operational runbooks, including admin-visible content",
@@ -8235,7 +8236,7 @@ var init_code2 = __esm({
8235
8236
  }
8236
8237
  });
8237
8238
 
8238
- // ../harness/dist/chunk-ISR434K7.js
8239
+ // ../harness/dist/chunk-IWVGSWY6.js
8239
8240
  async function digestStagedWorkspace(root, limits) {
8240
8241
  const files = [];
8241
8242
  const walk = async (directory) => {
@@ -9369,6 +9370,7 @@ async function runCodeAgentAttempt(options) {
9369
9370
  model: "brokered",
9370
9371
  surface,
9371
9372
  ...options.recipeIds ? { recipeIds: options.recipeIds } : {},
9373
+ ...options.extraSkills ? { extraSkills: options.extraSkills } : {},
9372
9374
  ...options.maxSteps === void 0 ? {} : { maxSteps: options.maxSteps },
9373
9375
  ...options.budget ? { budget: options.budget } : {},
9374
9376
  ...options.signal ? { signal: options.signal } : {},
@@ -10209,6 +10211,16 @@ function assertBudget(budget) {
10209
10211
  throw new TypeError("goal budget deadline must be epoch milliseconds");
10210
10212
  }
10211
10213
  }
10214
+ async function sessionSkillsFor(options, command) {
10215
+ try {
10216
+ return await options.sessionSkills?.(command) ?? [];
10217
+ } catch (cause) {
10218
+ options.onDiagnostic?.(
10219
+ `session skills unavailable, continuing with code tools only: ${cause instanceof Error ? cause.message : String(cause)}`
10220
+ );
10221
+ return [];
10222
+ }
10223
+ }
10212
10224
  function createCodeRuntimeToolBroker(input, lease, role) {
10213
10225
  const broker = createCodeToolBroker({
10214
10226
  recipes: input.recipes,
@@ -10473,8 +10485,8 @@ function codeToolResultPresentation(request3, response2) {
10473
10485
  };
10474
10486
  }
10475
10487
  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;
10476
- var init_chunk_ISR434K7 = __esm({
10477
- "../harness/dist/chunk-ISR434K7.js"() {
10488
+ var init_chunk_IWVGSWY6 = __esm({
10489
+ "../harness/dist/chunk-IWVGSWY6.js"() {
10478
10490
  "use strict";
10479
10491
  init_cjs_shims();
10480
10492
  init_chunk_CR6RE3A2();
@@ -10934,6 +10946,7 @@ Never claim a build or test passed unless odla_run_recipe returned that result.`
10934
10946
  event: (event) => this.#event(command, event, active.conversationRefs)
10935
10947
  });
10936
10948
  await this.#event(command, { type: "status", status: "running" }, active.conversationRefs);
10949
+ const extraSkills = await sessionSkillsFor(this.options, command);
10937
10950
  const result = await this.#attempt({
10938
10951
  inference,
10939
10952
  broker,
@@ -10941,7 +10954,8 @@ Never claim a build or test passed unless odla_run_recipe returned that result.`
10941
10954
  workspaceDir: active.workspace.workspaceDir,
10942
10955
  prompt: metadata2.prompt,
10943
10956
  signal: active.abort.signal,
10944
- recipeIds: this.options.recipes.map((recipe2) => recipe2.id)
10957
+ recipeIds: this.options.recipes.map((recipe2) => recipe2.id),
10958
+ ...extraSkills.length ? { extraSkills } : {}
10945
10959
  });
10946
10960
  const closing = result.finalText.trim();
10947
10961
  const completed = result.status === "completed" && Boolean(closing);
@@ -11037,7 +11051,7 @@ var init_node = __esm({
11037
11051
  "../harness/dist/node.js"() {
11038
11052
  "use strict";
11039
11053
  init_cjs_shims();
11040
- init_chunk_ISR434K7();
11054
+ init_chunk_IWVGSWY6();
11041
11055
  init_chunk_CR6RE3A2();
11042
11056
  MEASURED_PREMIUM = Object.freeze({
11043
11057
  /** 3 racers vs pure depth at equal budget: 21,044 / 7,936. */
@@ -12085,10 +12099,10 @@ Usage:
12085
12099
  odla-ai pm project add --app <product-id> --name <name> [--description <text>] [--json]
12086
12100
  odla-ai pm project use <project-id> [--json] [saved for this app, on this machine]
12087
12101
  odla-ai pm project set <project-id> [--name <n>|--description <text>|--status <active|completed|archived>] [--mutation-id <id>] [--json]
12088
- odla-ai pm goal list [--app <id>] [--project <id>] [--status <s>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
12089
- odla-ai pm task list [--app <id>] [--column <backlog|ready|doing|review|done>] [--goal <id>] [--assignee <id>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
12090
- odla-ai pm decision list [--app <id>] [--status <s>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
12091
- odla-ai pm bug list [--app <id>] [--status <s>] [--severity <s>] [--goal <id>] [--assignee <id>] [--decision <id>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
12102
+ odla-ai pm goal list [--app <id>] [--project <id>] [--platform-wide] [--status <s>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
12103
+ odla-ai pm task list [--app <id>] [--platform-wide] [--column <backlog|ready|doing|review|done>] [--goal <id>] [--assignee <id>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
12104
+ odla-ai pm decision list [--app <id>] [--platform-wide] [--status <s>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
12105
+ odla-ai pm bug list [--app <id>|--platform-wide] [--status <s>] [--severity <s>] [--goal <id>] [--assignee <id>] [--decision <id>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
12092
12106
  odla-ai pm goal add --app <id> --title <t> [--status <s>] [--proof <text>] [--target <pct>] [--mutation-id <id>] [--json]
12093
12107
  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]
12094
12108
  odla-ai pm next --app <id> [--project <id>] [--verbose] [--json]
@@ -12100,7 +12114,7 @@ Usage:
12100
12114
  odla-ai pm decision add --app <id> --title <t> --body <text> [--status <s>] [--mutation-id <id>] [--json]
12101
12115
  odla-ai pm bug add --app <id> --title <t> (--description <text>|--body <text>) [--status <s>] [--severity <s>] [--goal <id>] [--assignee <id>] [--decision <id>] [--mutation-id <id>] [--json]
12102
12116
  odla-ai bug report --app <id> --title <t> (--description <text>|--body <text>) [--severity <s>] [--json]
12103
- odla-ai pm <goal|task|decision|bug> get <id> [--json]
12117
+ odla-ai pm <goal|task|decision|bug> get <id-or-uuid-prefix> [--platform-wide] [--json]
12104
12118
  odla-ai pm <goal|task|decision|bug> link <id> [--json]
12105
12119
  odla-ai pm <goal|task|decision|bug> ref <id> [--json]
12106
12120
  odla-ai pm goal set <id> [--title <t>|--status <s>|--proof <text>|--no-proof|--target <pct>|--no-target] [--mutation-id <id>] [--json]
@@ -13272,8 +13286,37 @@ async function pmAdd(ctx, entity, parsed) {
13272
13286
  const record11 = { id: res.id, appId, title: String(input.title) };
13273
13287
  emit2(ctx, res, () => ctx.out.log(`created ${entity}: ${studioRecordLink(ctx, entity, record11)}`));
13274
13288
  }
13289
+ function looksLikeUuidPrefix(value2) {
13290
+ if (!UUID_PREFIX.test(value2) || !/[0-9a-f]/i.test(value2)) return false;
13291
+ return "00000000-0000-0000-0000-000000000000".slice(0, value2.length).split("").every((expected, index) => expected === "-" ? value2[index] === "-" : value2[index] !== "-");
13292
+ }
13293
+ async function resolvePmId(ctx, entity, supplied) {
13294
+ if (UUID.test(supplied) || !looksLikeUuidPrefix(supplied)) return supplied;
13295
+ const prefix = supplied.toLowerCase();
13296
+ const matches = [];
13297
+ const limit = 200;
13298
+ let offset = 0;
13299
+ for (; ; ) {
13300
+ const page2 = await pmRequest(
13301
+ ctx,
13302
+ "GET",
13303
+ `/${entity}?limit=${limit}&offset=${offset}`
13304
+ );
13305
+ matches.push(...page2.records.map((record11) => record11.id).filter((id2) => id2.toLowerCase().startsWith(prefix)));
13306
+ offset += page2.records.length;
13307
+ if (matches.length > 1 || page2.records.length === 0 || offset >= page2.total) break;
13308
+ }
13309
+ if (matches.length === 0) {
13310
+ throw new Error(`no ${entity} id matches prefix "${supplied}"`);
13311
+ }
13312
+ if (matches.length > 1) {
13313
+ throw new Error(`ambiguous ${entity} id prefix "${supplied}"`);
13314
+ }
13315
+ return matches[0];
13316
+ }
13275
13317
  async function pmGet(ctx, entity, id2) {
13276
- const { record: record11 } = await pmRequest(ctx, "GET", `/${entity}/${encodeURIComponent(id2)}`);
13318
+ const resolved = await resolvePmId(ctx, entity, id2);
13319
+ const { record: record11 } = await pmRequest(ctx, "GET", `/${entity}/${encodeURIComponent(resolved)}`);
13277
13320
  emit2(ctx, record11, () => printRecord(ctx, entity, record11));
13278
13321
  }
13279
13322
  async function pmReference(ctx, entity, id2) {
@@ -13349,12 +13392,15 @@ async function pmRemove(ctx, entity, id2) {
13349
13392
  await pmRequest(ctx, "DELETE", `/${entity}/${encodeURIComponent(id2)}`);
13350
13393
  ctx.out.log(`deleted ${entity} ${id2}`);
13351
13394
  }
13395
+ var UUID, UUID_PREFIX;
13352
13396
  var init_pm_actions = __esm({
13353
13397
  "src/pm-actions.ts"() {
13354
13398
  "use strict";
13355
13399
  init_cjs_shims();
13356
13400
  init_argv();
13357
13401
  init_pm_action_core();
13402
+ UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
13403
+ UUID_PREFIX = /^[0-9a-f-]{8,35}$/i;
13358
13404
  }
13359
13405
  });
13360
13406
 
@@ -14019,15 +14065,23 @@ async function buildContext2(parsed, deps) {
14019
14065
  const { cfg } = context;
14020
14066
  const doFetch = deps.fetch ?? fetch;
14021
14067
  const out = deps.stdout ?? console;
14022
- const token = await getDeveloperToken(
14068
+ const platformWide = parsed.options["platform-wide"] === true;
14069
+ const tokenOptions = {
14070
+ token: stringOpt(parsed.options.token),
14071
+ email: stringOpt(parsed.options.email),
14072
+ open: parsed.options.open === false ? false : parsed.options.open === true ? true : void 0,
14073
+ openApprovalUrl: deps.openUrl
14074
+ };
14075
+ const token = platformWide ? await resolveAdminPlatformToken({
14076
+ platform: cfg.platformUrl,
14077
+ scope: "platform:pm:read",
14078
+ rootDir: cfg.rootDir,
14079
+ fetch: doFetch,
14080
+ stdout: out,
14081
+ ...tokenOptions
14082
+ }) : await getDeveloperToken(
14023
14083
  cfg,
14024
- {
14025
- configPath: cfg.configPath,
14026
- token: stringOpt(parsed.options.token),
14027
- email: stringOpt(parsed.options.email),
14028
- open: parsed.options.open === false ? false : parsed.options.open === true ? true : void 0,
14029
- openApprovalUrl: deps.openUrl
14030
- },
14084
+ { configPath: cfg.configPath, ...tokenOptions },
14031
14085
  doFetch,
14032
14086
  out
14033
14087
  );
@@ -14042,8 +14096,8 @@ async function buildContext2(parsed, deps) {
14042
14096
  json: parsed.options.json === true,
14043
14097
  // Preserve PM's existing cross-project default when a config is present;
14044
14098
  // only an explicit remote-agent environment or profile selects an app.
14045
- appId: context.app.source === "environment" || context.app.source === "profile" ? context.app.value ?? void 0 : compatibleProject?.appId,
14046
- projectId: compatibleProject?.projectId,
14099
+ appId: platformWide ? void 0 : context.app.source === "environment" || context.app.source === "profile" ? context.app.value ?? void 0 : compatibleProject?.appId,
14100
+ projectId: platformWide ? void 0 : compatibleProject?.projectId,
14047
14101
  rootDir: cfg.rootDir,
14048
14102
  ...deps.sleep ? { sleep: deps.sleep } : {},
14049
14103
  ...deps.now ? { now: deps.now } : {}
@@ -14153,6 +14207,7 @@ var init_pm_command = __esm({
14153
14207
  init_pm_comments();
14154
14208
  init_pm_history();
14155
14209
  init_token();
14210
+ init_admin_ai_auth();
14156
14211
  init_pm_watch();
14157
14212
  init_pm_project_actions();
14158
14213
  init_pm_project_context();
@@ -14167,9 +14222,9 @@ var init_pm_command = __esm({
14167
14222
  };
14168
14223
  COMMON_OPTIONS = ["config", "token", "email", "json", "platform", "context", "open"];
14169
14224
  ACTION_OPTIONS = {
14170
- list: ["app", "project", "q", "limit", "offset"],
14225
+ list: ["app", "project", "q", "limit", "offset", "platform-wide"],
14171
14226
  add: ["app", "project", "title", "mutation-id"],
14172
- get: [],
14227
+ get: ["platform-wide"],
14173
14228
  set: ["mutation-id"],
14174
14229
  done: ["mutation-id"],
14175
14230
  comment: ["body", "mutation-id"],