@oxagen/cli 2.1.4-654 → 2.1.4-671

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.
Files changed (2) hide show
  1. package/oxagen.mjs +324 -193
  2. package/package.json +1 -1
package/oxagen.mjs CHANGED
@@ -9656,7 +9656,7 @@ function describeAgent(agent) {
9656
9656
  if (agent.host.revoked_at !== null)
9657
9657
  return `${what} (retired on this machine)`;
9658
9658
  if (agent.host.host_status === "revoked")
9659
- return `${what} (revoked on the fleet page)`;
9659
+ return `${what} (revoked on the Runs page)`;
9660
9660
  return what;
9661
9661
  }
9662
9662
  function portsInUse(home, exceptDir) {
@@ -24104,7 +24104,7 @@ import { readFileSync as readFileSync11 } from "node:fs";
24104
24104
  import { dirname as dirname9, resolve as resolve3 } from "node:path";
24105
24105
  import { fileURLToPath } from "node:url";
24106
24106
  function readVersion() {
24107
- if (true) return "2.1.4-654";
24107
+ if (true) return "2.1.4-671";
24108
24108
  try {
24109
24109
  const here = dirname9(fileURLToPath(import.meta.url));
24110
24110
  const pkg = JSON.parse(
@@ -28266,7 +28266,7 @@ function printStatus(report, deps) {
28266
28266
  } = report;
28267
28267
  if (report.retired === true)
28268
28268
  deps.out(
28269
- `Not enrolled. ${h.host_enrollment_id} was unenrolled here on ${h.revoked_at ?? ""}. The server-side revoke is still pending: run \`oxagen agent unenroll\` again while signed in, or revoke it from the fleet page.`
28269
+ `Not enrolled. ${h.host_enrollment_id} was unenrolled here on ${h.revoked_at ?? ""}. The server-side revoke is still pending: run \`oxagen agent unenroll\` again while signed in, or revoke it from the Runs page.`
28270
28270
  );
28271
28271
  for (const problem of report.problems ?? [])
28272
28272
  deps.out(`Unreadable ${problem}`);
@@ -28428,7 +28428,7 @@ async function revokeOnControlPlane(host, options, deps, warnings) {
28428
28428
  );
28429
28429
  if ("missing" in resolved) {
28430
28430
  warnings.push(
28431
- "no operator token; the host stays active server-side until an operator revokes it (`oxagen login`, then `oxagen agent unenroll` again, or revoke from the fleet page)"
28431
+ "no operator token; the host stays active server-side until an operator revokes it (`oxagen login`, then `oxagen agent unenroll` again, or revoke from the Runs page)"
28432
28432
  );
28433
28433
  return false;
28434
28434
  }
@@ -28806,7 +28806,7 @@ async function unenrollLocked(options, deps) {
28806
28806
  const host = read2.host;
28807
28807
  if (read2.error !== void 0) {
28808
28808
  warnings.push(
28809
- `${read2.error}; removing the hooks and the service anyway. The enrollment cannot be revoked from here: revoke it from the fleet page.`
28809
+ `${read2.error}; removing the hooks and the service anyway. The enrollment cannot be revoked from here: revoke it from the Runs page.`
28810
28810
  );
28811
28811
  incomplete = true;
28812
28812
  }
@@ -29758,7 +29758,7 @@ ${problems.map((problem) => ` ${problem}`).join("\n")}`
29758
29758
  }
29759
29759
  } else
29760
29760
  warnings.push(
29761
- `the previous enrollment ${existing.host_enrollment_id} could not be revoked (${problems.join("; ")}); its host key stays valid until ${existing.expires_at} unless an operator revokes it from the fleet page`
29761
+ `the previous enrollment ${existing.host_enrollment_id} could not be revoked (${problems.join("; ")}); its host key stays valid until ${existing.expires_at} unless an operator revokes it from the Runs page`
29762
29762
  );
29763
29763
  }
29764
29764
  }
@@ -31166,7 +31166,7 @@ ${refusals.map((refusal) => ` ${refusal}`).join("\n")}`
31166
31166
  warnings
31167
31167
  );
31168
31168
  deps.out(
31169
- revoked ? " revoked" : " not revoked server-side; the next reassign or unenroll asks again, or an operator can finish it from the fleet page"
31169
+ revoked ? " revoked" : " not revoked server-side; the next reassign or unenroll asks again, or an operator can finish it from the Runs page"
31170
31170
  );
31171
31171
  deps.out("[2/3] Removing the old enrollment's hooks");
31172
31172
  for (const failure2 of (await stripEnrollmentHooks(host, deps)).failed)
@@ -31636,7 +31636,7 @@ async function uninstall(options, deps) {
31636
31636
  for (const path2 of tally2.removed) deps.out(` removed ${path2}`);
31637
31637
  for (const revoke of pending)
31638
31638
  warnings.push(
31639
- `the control plane did not confirm the revoke of ${revoke}. Revoke it on the fleet page`
31639
+ `the control plane did not confirm the revoke of ${revoke}. Revoke it on the Runs page`
31640
31640
  );
31641
31641
  for (const warning of warnings.slice(unenrolled.warnings.length))
31642
31642
  deps.err(`warning: ${warning}`);
@@ -55176,7 +55176,7 @@ var init_package = __esm({
55176
55176
  "package.json"() {
55177
55177
  package_default = {
55178
55178
  name: "@oxagen/cli",
55179
- version: "2.1.4-654",
55179
+ version: "2.1.4-671",
55180
55180
  description: "Oxagen governance CLI \u2014 spend, lineage, grounding, credentials, and audit (agentic coding lives in the stella CLI)",
55181
55181
  type: "module",
55182
55182
  main: "./dist/index.js",
@@ -58176,6 +58176,233 @@ var init_repo = __esm({
58176
58176
  }
58177
58177
  });
58178
58178
 
58179
+ // src/commands/steering-findings.ts
58180
+ var steering_findings_exports = {};
58181
+ __export(steering_findings_exports, {
58182
+ PROPOSAL_STATUS_WORDS: () => PROPOSAL_STATUS_WORDS,
58183
+ STEERING_FINDINGS_CAPABILITIES: () => STEERING_FINDINGS_CAPABILITIES,
58184
+ apiRefusal: () => apiRefusal,
58185
+ reportApiFailure: () => reportApiFailure,
58186
+ steeringFindings: () => steeringFindings,
58187
+ usageError: () => usageError
58188
+ });
58189
+ function isRecord7(value) {
58190
+ return typeof value === "object" && value !== null && !Array.isArray(value);
58191
+ }
58192
+ function textOrNull(value) {
58193
+ return typeof value === "string" && value.length > 0 ? value : null;
58194
+ }
58195
+ function apiRefusal(err2) {
58196
+ const message = errorMessage(err2);
58197
+ const start = message.indexOf("{");
58198
+ const end = message.lastIndexOf("}");
58199
+ if (start >= 0 && end > start) {
58200
+ try {
58201
+ const body2 = JSON.parse(message.slice(start, end + 1));
58202
+ const error = isRecord7(body2) && isRecord7(body2.error) ? body2.error : null;
58203
+ const said = error === null ? null : textOrNull(error.message);
58204
+ if (error !== null && said !== null) {
58205
+ return {
58206
+ code: textOrNull(error.code),
58207
+ reason: textOrNull(error.reason),
58208
+ message: said
58209
+ };
58210
+ }
58211
+ } catch {
58212
+ }
58213
+ }
58214
+ return { code: null, reason: null, message };
58215
+ }
58216
+ function reportApiFailure(out, writer, err2, nextSteps = {}) {
58217
+ const refusal = apiRefusal(err2);
58218
+ out.error(refusal.message, refusal.reason ?? refusal.code ?? "api");
58219
+ if (out.isJson || refusal.reason === null) return;
58220
+ const next = nextSteps[refusal.reason];
58221
+ if (next !== void 0) writer.writeErr(next);
58222
+ }
58223
+ function usageError(writer, message, line) {
58224
+ writer.writeErr(`error: ${message}`);
58225
+ writer.writeErr(`usage: ${line}`);
58226
+ process.exitCode = 2;
58227
+ }
58228
+ function plural(count12, one, many) {
58229
+ return `${count12} ${count12 === 1 ? one : many}`;
58230
+ }
58231
+ function findingRow(finding) {
58232
+ const pr = finding.pull_request;
58233
+ const proposal = finding.proposal;
58234
+ return [
58235
+ finding.id,
58236
+ finding.kind,
58237
+ `${finding.path}:${finding.line}`,
58238
+ finding.record.label ?? finding.record.lineage,
58239
+ `#${pr.number} ${pr.state}`,
58240
+ proposal === null ? "none" : `${proposal.id} (${PROPOSAL_STATUS_WORDS[proposal.status]})`
58241
+ ];
58242
+ }
58243
+ async function steeringFindings(opts = {}, writer = stdoutWriter) {
58244
+ const out = createOutput({ json: opts.json }, writer);
58245
+ let result2;
58246
+ try {
58247
+ result2 = await apiGetOrThrow(
58248
+ "repository/findings"
58249
+ );
58250
+ } catch (err2) {
58251
+ reportApiFailure(out, writer, err2);
58252
+ return;
58253
+ }
58254
+ if (out.isJson) {
58255
+ out.data(result2);
58256
+ return;
58257
+ }
58258
+ const repositories = result2.repositories.filter((r) => r.findings.length > 0);
58259
+ if (repositories.length === 0) {
58260
+ writer.write(
58261
+ "No findings. The Oxagen check found no statement in a linked repository's instruction files that repeats or contradicts a steering record."
58262
+ );
58263
+ return;
58264
+ }
58265
+ let total2 = 0;
58266
+ for (const [index, repository] of repositories.entries()) {
58267
+ if (index > 0) writer.write("");
58268
+ writer.write(`${repository.full_name} (${repository.provider})`);
58269
+ printTable(
58270
+ ["FINDING", "KIND", "FILE", "RECORD", "PULL REQUEST", "PROPOSAL"],
58271
+ repository.findings.map(findingRow),
58272
+ writer
58273
+ );
58274
+ total2 += repository.findings.length;
58275
+ }
58276
+ writer.write("");
58277
+ writer.write(
58278
+ `${plural(total2, "finding", "findings")} in ${plural(repositories.length, "repository", "repositories")}.`
58279
+ );
58280
+ const promotable = repositories.some(
58281
+ (r) => r.findings.some((f) => f.kind === "contradiction" && f.proposal === null)
58282
+ );
58283
+ if (promotable) {
58284
+ writer.write(
58285
+ "Promote a contradiction to a proposal with `oxagen steering promote <finding-id>`."
58286
+ );
58287
+ }
58288
+ }
58289
+ var STEERING_FINDINGS_CAPABILITIES, PROPOSAL_STATUS_WORDS;
58290
+ var init_steering_findings = __esm({
58291
+ "src/commands/steering-findings.ts"() {
58292
+ init_api();
58293
+ init_capture_writer();
58294
+ init_output();
58295
+ STEERING_FINDINGS_CAPABILITIES = [
58296
+ "list_code_repository_findings"
58297
+ ];
58298
+ PROPOSAL_STATUS_WORDS = {
58299
+ proposed: "waiting for its steering PR",
58300
+ pr_open: "steering PR open",
58301
+ checks_running: "checks running",
58302
+ checks_passed: "checks passed",
58303
+ checks_failed: "checks failed",
58304
+ merged: "merged",
58305
+ rejected: "rejected"
58306
+ };
58307
+ }
58308
+ });
58309
+
58310
+ // src/commands/repo-scan.ts
58311
+ var repo_scan_exports = {};
58312
+ __export(repo_scan_exports, {
58313
+ REPO_SCAN_CAPABILITIES: () => REPO_SCAN_CAPABILITIES,
58314
+ repoScan: () => repoScan
58315
+ });
58316
+ function fileRow(file) {
58317
+ const size = file.size === null ? "-" : String(file.size);
58318
+ const files3 = file.kind === "skill" ? ` (${file.files.length} files)` : "";
58319
+ return [
58320
+ file.kind,
58321
+ `${file.path}${files3}`,
58322
+ file.harness,
58323
+ size,
58324
+ file.fixture ? "fixture" : ""
58325
+ ];
58326
+ }
58327
+ function plural2(count12, one, many) {
58328
+ return `${count12} ${count12 === 1 ? one : many}`;
58329
+ }
58330
+ function countsLine(counts) {
58331
+ const parts = [
58332
+ [counts.instructions, "instruction file", "instruction files"],
58333
+ [counts.rule, "rule", "rules"],
58334
+ [counts.skill, "skill", "skills"],
58335
+ [counts.command, "command", "commands"],
58336
+ [counts.subagent, "subagent file", "subagent files"],
58337
+ [counts.settings, "settings file", "settings files"],
58338
+ [counts.mcpConfig, "MCP config", "MCP configs"],
58339
+ [counts.personal, "personal file", "personal files"]
58340
+ ];
58341
+ const found = parts.filter(([n4]) => n4 > 0).map(([n4, one, many]) => plural2(n4, one, many));
58342
+ const fixtures = counts.fixtures > 0 ? `, and ${plural2(counts.fixtures, "file", "files")} under fixture folders` : "";
58343
+ return `${found.length > 0 ? found.join(", ") : "No harness files"}${fixtures}.`;
58344
+ }
58345
+ async function repoScan(ref2, opts = {}, writer = stdoutWriter) {
58346
+ const fullName = ref2.trim().replace(/^\/+|\/+$/g, "");
58347
+ if (!/^[^/\s]+(\/[^/\s]+)+$/.test(fullName)) {
58348
+ usageError(
58349
+ writer,
58350
+ `expected <owner/name>, got ${JSON.stringify(ref2)}`,
58351
+ USAGE
58352
+ );
58353
+ return;
58354
+ }
58355
+ const out = createOutput({ json: opts.json }, writer);
58356
+ let result2;
58357
+ try {
58358
+ result2 = await apiPostOrThrow(
58359
+ "repository/config/scan",
58360
+ { provider: opts.gitlab ? "gitlab" : "github", fullName }
58361
+ );
58362
+ } catch (err2) {
58363
+ reportApiFailure(out, writer, err2, NEXT_STEPS);
58364
+ return;
58365
+ }
58366
+ if (out.isJson) {
58367
+ out.data(result2);
58368
+ return;
58369
+ }
58370
+ writer.write(
58371
+ `${result2.fullName} (${result2.provider}), ${result2.defaultBranch} at ${result2.commitSha}`
58372
+ );
58373
+ if (result2.partialReason !== null) writer.write(result2.partialReason);
58374
+ if (result2.files.length > 0) {
58375
+ writer.write("");
58376
+ printTable(
58377
+ ["KIND", "PATH", "HARNESS", "BYTES", "FIXTURE"],
58378
+ result2.files.map(fileRow),
58379
+ writer
58380
+ );
58381
+ }
58382
+ if (result2.aliases.length > 0) {
58383
+ writer.write("");
58384
+ for (const alias of result2.aliases) writer.write(`${alias.path}: ${alias.reason}`);
58385
+ }
58386
+ writer.write("");
58387
+ writer.write(countsLine(result2.counts));
58388
+ }
58389
+ var REPO_SCAN_CAPABILITIES, USAGE, NEXT_STEPS;
58390
+ var init_repo_scan = __esm({
58391
+ "src/commands/repo-scan.ts"() {
58392
+ init_api();
58393
+ init_capture_writer();
58394
+ init_output();
58395
+ init_steering_findings();
58396
+ REPO_SCAN_CAPABILITIES = ["scan_repository_config"];
58397
+ USAGE = "oxagen repo scan <owner/name> [--gitlab] [--json]";
58398
+ NEXT_STEPS = {
58399
+ github_not_connected: "Connect GitHub from the Repositories page, then scan again.",
58400
+ repository_not_installed: "Give the Oxagen GitHub App access to the repository, then scan again.",
58401
+ gitlab_not_connected: "Connect the GitLab project with a project access token, then scan again."
58402
+ };
58403
+ }
58404
+ });
58405
+
58179
58406
  // ../../packages/steering-freshness/src/git.ts
58180
58407
  import { execFile as execFile5 } from "node:child_process";
58181
58408
  function classifyProbeFailure(err2) {
@@ -58601,23 +58828,23 @@ function hookConfigPath(projectRoot, harness, env = process.env, home = homedir1
58601
58828
  function stellaJsonPath(env, home) {
58602
58829
  return join46(env["STELLA_HOME"] ?? join46(home, ".stella"), "settings.json");
58603
58830
  }
58604
- function isRecord7(v) {
58831
+ function isRecord8(v) {
58605
58832
  return v !== null && typeof v === "object" && !Array.isArray(v);
58606
58833
  }
58607
58834
  function readConfig2(text5) {
58608
58835
  try {
58609
58836
  const parsed2 = JSON.parse(text5);
58610
- if (!isRecord7(parsed2)) return null;
58837
+ if (!isRecord8(parsed2)) return null;
58611
58838
  if (parsed2["hooks"] === void 0) return parsed2;
58612
58839
  const hooks = parsed2["hooks"];
58613
- if (!isRecord7(hooks)) return null;
58840
+ if (!isRecord8(hooks)) return null;
58614
58841
  for (const groups of Object.values(hooks)) {
58615
58842
  if (!Array.isArray(groups)) return null;
58616
58843
  for (const group of groups) {
58617
- if (!isRecord7(group)) return null;
58844
+ if (!isRecord8(group)) return null;
58618
58845
  if (group["hooks"] === void 0) continue;
58619
58846
  if (!Array.isArray(group["hooks"])) return null;
58620
- if (!group["hooks"].every(isRecord7)) return null;
58847
+ if (!group["hooks"].every(isRecord8)) return null;
58621
58848
  }
58622
58849
  }
58623
58850
  return parsed2;
@@ -58749,12 +58976,12 @@ async function groupHookInstalled(path2, io) {
58749
58976
  function readCursorConfig(text5) {
58750
58977
  try {
58751
58978
  const parsed2 = JSON.parse(text5);
58752
- if (!isRecord7(parsed2)) return null;
58979
+ if (!isRecord8(parsed2)) return null;
58753
58980
  if (parsed2["hooks"] === void 0) return parsed2;
58754
58981
  const hooks = parsed2["hooks"];
58755
- if (!isRecord7(hooks)) return null;
58982
+ if (!isRecord8(hooks)) return null;
58756
58983
  for (const entries2 of Object.values(hooks)) {
58757
- if (!Array.isArray(entries2) || !entries2.every(isRecord7)) return null;
58984
+ if (!Array.isArray(entries2) || !entries2.every(isRecord8)) return null;
58758
58985
  }
58759
58986
  return parsed2;
58760
58987
  } catch {
@@ -73339,6 +73566,15 @@ var init_src4 = __esm({
73339
73566
  }
73340
73567
  });
73341
73568
 
73569
+ // ../../packages/oxagen/src/run-enrichment.ts
73570
+ var RUN_SUMMARY_MODES;
73571
+ var init_run_enrichment = __esm({
73572
+ "../../packages/oxagen/src/run-enrichment.ts"() {
73573
+ "use strict";
73574
+ RUN_SUMMARY_MODES = ["always", "on_demand", "never"];
73575
+ }
73576
+ });
73577
+
73342
73578
  // ../../packages/oxagen/src/run-fit.ts
73343
73579
  var RUN_FIT_METHOD, runEffortSourceSchema, runFitReadSchema, runModelFitSchema, runEffortFitSchema, runFitReadingSchema, runFitSchema;
73344
73580
  var init_run_fit = __esm({
@@ -73415,6 +73651,7 @@ var init_run_list = __esm({
73415
73651
  init_zod();
73416
73652
  init_src3();
73417
73653
  init_registry2();
73654
+ init_run_enrichment();
73418
73655
  init_run_fit();
73419
73656
  init_spend_shared();
73420
73657
  init_run_shared();
@@ -73802,21 +74039,38 @@ var init_run_list = __esm({
73802
74039
  version: external_exports.string().nullable(),
73803
74040
  runtime: external_exports.string().nullable()
73804
74041
  }).nullable(),
73805
- /** False when the workspace turned automatic run names and summaries off (ADR-153). */
74042
+ /**
74043
+ * The workspace's run summaries mode (D30): `always`, `on_demand`, or
74044
+ * `never`. It decides whether the run offers Summarize
74045
+ * (`summarizeOffered` in `@oxagen/oxagen/run-enrichment`). oxagen names
74046
+ * every run in every mode.
74047
+ */
74048
+ summaries: external_exports.enum(RUN_SUMMARY_MODES).optional(),
74049
+ /**
74050
+ * Deprecated: true only under the `always` mode. It used to be the switch
74051
+ * that turned run names and summaries off together (ADR-153).
74052
+ */
73806
74053
  enrichmentEnabled: external_exports.boolean().optional(),
73807
74054
  /**
73808
74055
  * Why the last automatic account failed, as a short reason code such as
73809
- * `model_refused` or `credit_refused:<code>`. Absent once an account exists.
74056
+ * `customer_key_refused` or `credit_refused:<code>`. Absent once an
74057
+ * account exists, and under the `never` mode.
73810
74058
  */
73811
74059
  enrichmentError: external_exports.string().optional(),
74060
+ /**
74061
+ * True on a sealed run under `always` whose summary failed: the model
74062
+ * provider refused a key the customer brought (D30). Such a run offers
74063
+ * Summarize and a banner that names the reason.
74064
+ */
74065
+ summaryFailed: external_exports.boolean().optional(),
73812
74066
  /**
73813
74067
  * What the run is called, cut to `RUN_LABEL_MAX` with an ellipsis. A
73814
74068
  * name a person gave the run (`edit_run`) comes first. Otherwise a
73815
74069
  * wrapped session reads the title its harness gave it, then the name
73816
74070
  * Oxagen wrote (the model's, or the fallback from the first prompt),
73817
74071
  * then the title ingest derived, and a ledger run reads the name Oxagen
73818
- * wrote. With automatic accounts turned off, only a person's name and
73819
- * the harness title are read. Null when there is none.
74072
+ * wrote. oxagen names every run in every run summaries mode (D30). Null
74073
+ * when there is none.
73820
74074
  */
73821
74075
  name: external_exports.string().max(RUN_LABEL_MAX).nullable(),
73822
74076
  /**
@@ -73940,7 +74194,7 @@ var init_run_list = __esm({
73940
74194
  /**
73941
74195
  * `true` answers `liveRuns`, the workspace's live count. The count reads
73942
74196
  * every root session the workspace holds, so a read that does not show
73943
- * it leaves this out and pays nothing for it. Fleet sets it.
74197
+ * it leaves this out and pays nothing for it. Runs sets it.
73944
74198
  */
73945
74199
  countLive: external_exports.boolean().optional()
73946
74200
  }).strict(),
@@ -74413,7 +74667,7 @@ var init_steering_repo = __esm({
74413
74667
  });
74414
74668
 
74415
74669
  // ../../packages/steering-check/src/repo.ts
74416
- function isRecord8(value) {
74670
+ function isRecord9(value) {
74417
74671
  return typeof value === "object" && value !== null && !Array.isArray(value);
74418
74672
  }
74419
74673
  function isString(value) {
@@ -74539,7 +74793,7 @@ function parseTomlLoose(text5) {
74539
74793
  if (text5 === void 0) return null;
74540
74794
  try {
74541
74795
  const value = parse(text5);
74542
- return isRecord8(value) ? value : null;
74796
+ return isRecord9(value) ? value : null;
74543
74797
  } catch {
74544
74798
  return null;
74545
74799
  }
@@ -74547,7 +74801,7 @@ function parseTomlLoose(text5) {
74547
74801
  function canonicalJson(value) {
74548
74802
  if (Array.isArray(value))
74549
74803
  return `[${value.map(canonicalJson).join(",")}]`;
74550
- if (isRecord8(value)) {
74804
+ if (isRecord9(value)) {
74551
74805
  const keys = Object.keys(value).sort();
74552
74806
  return `{${keys.map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`).join(",")}}`;
74553
74807
  }
@@ -74557,7 +74811,7 @@ function parseJsonLoose(text5) {
74557
74811
  if (text5 === void 0) return null;
74558
74812
  try {
74559
74813
  const value = JSON.parse(text5);
74560
- return isRecord8(value) ? value : null;
74814
+ return isRecord9(value) ? value : null;
74561
74815
  } catch {
74562
74816
  return null;
74563
74817
  }
@@ -74571,9 +74825,9 @@ function workspaceRepositories(tree) {
74571
74825
  }
74572
74826
  function entries(value) {
74573
74827
  const found = /* @__PURE__ */ new Map();
74574
- if (!isRecord8(value)) return found;
74828
+ if (!isRecord9(value)) return found;
74575
74829
  for (const [key, entry2] of Object.entries(value)) {
74576
- if (isRecord8(entry2)) found.set(key, entry2);
74830
+ if (isRecord9(entry2)) found.set(key, entry2);
74577
74831
  }
74578
74832
  return found;
74579
74833
  }
@@ -74739,7 +74993,7 @@ function isPositiveInteger(value) {
74739
74993
  }
74740
74994
  function alwaysOnBudget(tree) {
74741
74995
  const steering = parseTomlLoose(tree?.get(GOVERNANCE_TOML_PATH))?.steering;
74742
- const value = isRecord8(steering) ? steering.always_on_tokens : void 0;
74996
+ const value = isRecord9(steering) ? steering.always_on_tokens : void 0;
74743
74997
  if (value === "off") return "off";
74744
74998
  if (isPositiveInteger(value))
74745
74999
  return { tokens: value, source: "governance.toml" };
@@ -74747,7 +75001,7 @@ function alwaysOnBudget(tree) {
74747
75001
  }
74748
75002
  function definitionBudget(tree) {
74749
75003
  const tools = parseTomlLoose(tree?.get(WORKSPACE_TOML_PATH))?.tools;
74750
- const value = isRecord8(tools) ? tools.definition_budget : void 0;
75004
+ const value = isRecord9(tools) ? tools.definition_budget : void 0;
74751
75005
  return isPositiveInteger(value) ? { tokens: value, source: "workspace.toml" } : {
74752
75006
  tokens: DEFAULT_WORKSPACE_DEFINITION_BUDGET,
74753
75007
  source: "Oxagen's default"
@@ -74855,12 +75109,12 @@ function directDefinitions(tree) {
74855
75109
  const servers = [];
74856
75110
  for (const [name, folder] of serverFolders(tree)) {
74857
75111
  const exposure = folder.server?.exposure;
74858
- if (!isRecord8(exposure) || exposure.mode !== "direct") continue;
75112
+ if (!isRecord9(exposure) || exposure.mode !== "direct") continue;
74859
75113
  let tokens = 0;
74860
75114
  let tools = 0;
74861
75115
  for (const [key, entry2] of folder.tools) {
74862
75116
  const upstream = folder.locked.get(key)?.upstream;
74863
- if (!isRecord8(upstream)) continue;
75117
+ if (!isRecord9(upstream)) continue;
74864
75118
  const description = isString(entry2.description) ? entry2.description : upstream.description;
74865
75119
  const definition = {
74866
75120
  name: `${name}__${key}`,
@@ -75613,7 +75867,7 @@ function credentialFields(value, prefix = "") {
75613
75867
  (item, n4) => credentialFields(item, prefix === "" ? String(n4) : `${prefix}.${n4}`)
75614
75868
  );
75615
75869
  }
75616
- if (!isRecord8(value)) return [];
75870
+ if (!isRecord9(value)) return [];
75617
75871
  return Object.entries(value).flatMap(
75618
75872
  ([key, item]) => credentialFields(item, prefix === "" ? key : `${prefix}.${key}`)
75619
75873
  );
@@ -75649,7 +75903,7 @@ function groupFindings(tree, context) {
75649
75903
  const reviewers = parsed2.reviewers;
75650
75904
  const findings = [];
75651
75905
  reviewers.forEach((entry2, n4) => {
75652
- if (!isRecord8(entry2) || !isString(entry2.group) || context.groups.includes(entry2.group))
75906
+ if (!isRecord9(entry2) || !isString(entry2.group) || context.groups.includes(entry2.group))
75653
75907
  return;
75654
75908
  const field = `reviewers.${n4}.group`;
75655
75909
  findings.push(
@@ -77309,137 +77563,6 @@ var init_steering_import = __esm({
77309
77563
  }
77310
77564
  });
77311
77565
 
77312
- // src/commands/steering-findings.ts
77313
- var steering_findings_exports = {};
77314
- __export(steering_findings_exports, {
77315
- PROPOSAL_STATUS_WORDS: () => PROPOSAL_STATUS_WORDS,
77316
- STEERING_FINDINGS_CAPABILITIES: () => STEERING_FINDINGS_CAPABILITIES,
77317
- apiRefusal: () => apiRefusal,
77318
- reportApiFailure: () => reportApiFailure,
77319
- steeringFindings: () => steeringFindings,
77320
- usageError: () => usageError
77321
- });
77322
- function isRecord9(value) {
77323
- return typeof value === "object" && value !== null && !Array.isArray(value);
77324
- }
77325
- function textOrNull(value) {
77326
- return typeof value === "string" && value.length > 0 ? value : null;
77327
- }
77328
- function apiRefusal(err2) {
77329
- const message = errorMessage(err2);
77330
- const start = message.indexOf("{");
77331
- const end = message.lastIndexOf("}");
77332
- if (start >= 0 && end > start) {
77333
- try {
77334
- const body2 = JSON.parse(message.slice(start, end + 1));
77335
- const error = isRecord9(body2) && isRecord9(body2.error) ? body2.error : null;
77336
- const said = error === null ? null : textOrNull(error.message);
77337
- if (error !== null && said !== null) {
77338
- return {
77339
- code: textOrNull(error.code),
77340
- reason: textOrNull(error.reason),
77341
- message: said
77342
- };
77343
- }
77344
- } catch {
77345
- }
77346
- }
77347
- return { code: null, reason: null, message };
77348
- }
77349
- function reportApiFailure(out, writer, err2, nextSteps = {}) {
77350
- const refusal = apiRefusal(err2);
77351
- out.error(refusal.message, refusal.reason ?? refusal.code ?? "api");
77352
- if (out.isJson || refusal.reason === null) return;
77353
- const next = nextSteps[refusal.reason];
77354
- if (next !== void 0) writer.writeErr(next);
77355
- }
77356
- function usageError(writer, message, line) {
77357
- writer.writeErr(`error: ${message}`);
77358
- writer.writeErr(`usage: ${line}`);
77359
- process.exitCode = 2;
77360
- }
77361
- function plural(count12, one, many) {
77362
- return `${count12} ${count12 === 1 ? one : many}`;
77363
- }
77364
- function findingRow(finding) {
77365
- const pr = finding.pull_request;
77366
- const proposal = finding.proposal;
77367
- return [
77368
- finding.id,
77369
- finding.kind,
77370
- `${finding.path}:${finding.line}`,
77371
- finding.record.label ?? finding.record.lineage,
77372
- `#${pr.number} ${pr.state}`,
77373
- proposal === null ? "none" : `${proposal.id} (${PROPOSAL_STATUS_WORDS[proposal.status]})`
77374
- ];
77375
- }
77376
- async function steeringFindings(opts = {}, writer = stdoutWriter) {
77377
- const out = createOutput({ json: opts.json }, writer);
77378
- let result2;
77379
- try {
77380
- result2 = await apiGetOrThrow(
77381
- "repository/findings"
77382
- );
77383
- } catch (err2) {
77384
- reportApiFailure(out, writer, err2);
77385
- return;
77386
- }
77387
- if (out.isJson) {
77388
- out.data(result2);
77389
- return;
77390
- }
77391
- const repositories = result2.repositories.filter((r) => r.findings.length > 0);
77392
- if (repositories.length === 0) {
77393
- writer.write(
77394
- "No findings. The Oxagen check found no statement in a linked repository's instruction files that repeats or contradicts a steering record."
77395
- );
77396
- return;
77397
- }
77398
- let total2 = 0;
77399
- for (const [index, repository] of repositories.entries()) {
77400
- if (index > 0) writer.write("");
77401
- writer.write(`${repository.full_name} (${repository.provider})`);
77402
- printTable(
77403
- ["FINDING", "KIND", "FILE", "RECORD", "PULL REQUEST", "PROPOSAL"],
77404
- repository.findings.map(findingRow),
77405
- writer
77406
- );
77407
- total2 += repository.findings.length;
77408
- }
77409
- writer.write("");
77410
- writer.write(
77411
- `${plural(total2, "finding", "findings")} in ${plural(repositories.length, "repository", "repositories")}.`
77412
- );
77413
- const promotable = repositories.some(
77414
- (r) => r.findings.some((f) => f.kind === "contradiction" && f.proposal === null)
77415
- );
77416
- if (promotable) {
77417
- writer.write(
77418
- "Promote a contradiction to a proposal with `oxagen steering promote <finding-id>`."
77419
- );
77420
- }
77421
- }
77422
- var STEERING_FINDINGS_CAPABILITIES, PROPOSAL_STATUS_WORDS;
77423
- var init_steering_findings = __esm({
77424
- "src/commands/steering-findings.ts"() {
77425
- init_api();
77426
- init_capture_writer();
77427
- init_output();
77428
- STEERING_FINDINGS_CAPABILITIES = [
77429
- "list_code_repository_findings"
77430
- ];
77431
- PROPOSAL_STATUS_WORDS = {
77432
- proposed: "waiting for its steering PR",
77433
- pr_open: "steering PR open",
77434
- checks_running: "checks running",
77435
- checks_passed: "checks passed",
77436
- checks_failed: "checks failed",
77437
- merged: "merged",
77438
- rejected: "rejected"
77439
- };
77440
- }
77441
- });
77442
-
77443
77566
  // src/commands/steering-promote.ts
77444
77567
  var steering_promote_exports = {};
77445
77568
  __export(steering_promote_exports, {
@@ -77452,7 +77575,7 @@ async function steeringPromote(findingId, opts = {}, writer = stdoutWriter) {
77452
77575
  usageError(
77453
77576
  writer,
77454
77577
  `expected a finding id that starts with crf_, got ${JSON.stringify(findingId)}. Run \`oxagen steering findings\` to list them.`,
77455
- USAGE
77578
+ USAGE2
77456
77579
  );
77457
77580
  return;
77458
77581
  }
@@ -77464,7 +77587,7 @@ async function steeringPromote(findingId, opts = {}, writer = stdoutWriter) {
77464
77587
  { finding_id: id2 }
77465
77588
  );
77466
77589
  } catch (err2) {
77467
- reportApiFailure(out, writer, err2, NEXT_STEPS);
77590
+ reportApiFailure(out, writer, err2, NEXT_STEPS2);
77468
77591
  return;
77469
77592
  }
77470
77593
  if (out.isJson) {
@@ -77481,7 +77604,7 @@ async function steeringPromote(findingId, opts = {}, writer = stdoutWriter) {
77481
77604
  writer.write(`Status: ${PROPOSAL_STATUS_WORDS[result2.status]}`);
77482
77605
  writer.write("Nothing steers until a person merges the steering PR.");
77483
77606
  }
77484
- var STEERING_PROMOTE_CAPABILITIES, FINDING_ID, USAGE, NEXT_STEPS;
77607
+ var STEERING_PROMOTE_CAPABILITIES, FINDING_ID, USAGE2, NEXT_STEPS2;
77485
77608
  var init_steering_promote = __esm({
77486
77609
  "src/commands/steering-promote.ts"() {
77487
77610
  init_api();
@@ -77492,8 +77615,8 @@ var init_steering_promote = __esm({
77492
77615
  "promote_instruction_to_steering"
77493
77616
  ];
77494
77617
  FINDING_ID = /^crf_[0-9A-Za-z]+$/;
77495
- USAGE = "oxagen steering promote <finding-id> [--json]";
77496
- NEXT_STEPS = {
77618
+ USAGE2 = "oxagen steering promote <finding-id> [--json]";
77619
+ NEXT_STEPS2 = {
77497
77620
  finding_resolved: "Run `oxagen steering findings` to see the statements that still match a record.",
77498
77621
  already_proposed: "Run `oxagen steering findings` to see the open proposal and its steering PR.",
77499
77622
  lineage_pr_open: "Merge or close the PR that is open on the record, then promote the finding again."
@@ -77519,7 +77642,7 @@ async function steeringRestoreBlock(proposalId, path2, opts = {}, writer = stdou
77519
77642
  usageError(
77520
77643
  writer,
77521
77644
  `expected a proposal id that starts with prp_, got ${JSON.stringify(proposalId)}`,
77522
- USAGE2
77645
+ USAGE3
77523
77646
  );
77524
77647
  return;
77525
77648
  }
@@ -77528,7 +77651,7 @@ async function steeringRestoreBlock(proposalId, path2, opts = {}, writer = stdou
77528
77651
  usageError(
77529
77652
  writer,
77530
77653
  `expected AGENTS.md, CLAUDE.md, or README.md, got ${JSON.stringify(path2)}`,
77531
- USAGE2
77654
+ USAGE3
77532
77655
  );
77533
77656
  return;
77534
77657
  }
@@ -77553,7 +77676,7 @@ async function steeringRestoreBlock(proposalId, path2, opts = {}, writer = stdou
77553
77676
  writer.write(`Commit: ${result2.commit_sha}`);
77554
77677
  writer.write(`Status: ${PROPOSAL_STATUS_WORDS[result2.status]}`);
77555
77678
  }
77556
- var STEERING_RESTORE_BLOCK_CAPABILITIES, MANAGED_BLOCK_FILES, PROPOSAL_ID2, USAGE2;
77679
+ var STEERING_RESTORE_BLOCK_CAPABILITIES, MANAGED_BLOCK_FILES, PROPOSAL_ID2, USAGE3;
77557
77680
  var init_steering_restore_block = __esm({
77558
77681
  "src/commands/steering-restore-block.ts"() {
77559
77682
  init_api();
@@ -77569,7 +77692,7 @@ var init_steering_restore_block = __esm({
77569
77692
  "README.md": true
77570
77693
  };
77571
77694
  PROPOSAL_ID2 = /^prp_[0-9A-Za-z]+$/;
77572
- USAGE2 = "oxagen steering restore-block <proposal-id> <AGENTS.md|CLAUDE.md|README.md> [--json]";
77695
+ USAGE3 = "oxagen steering restore-block <proposal-id> <AGENTS.md|CLAUDE.md|README.md> [--json]";
77573
77696
  }
77574
77697
  });
77575
77698
 
@@ -79024,7 +79147,7 @@ function formatFrame(frame) {
79024
79147
  return parts.join(" ");
79025
79148
  }
79026
79149
  function formatCounts(counts) {
79027
- return counts.map((c) => `${c.kind} ${c.count} (in ${plural2(c.frames, "frame")})`).join(", ");
79150
+ return counts.map((c) => `${c.kind} ${c.count} (in ${plural3(c.frames, "frame")})`).join(", ");
79028
79151
  }
79029
79152
  function formatVerification(result2) {
79030
79153
  const lines = [];
@@ -79037,7 +79160,7 @@ function formatVerification(result2) {
79037
79160
  ).length;
79038
79161
  if (notCarried > 0) {
79039
79162
  lines.push(
79040
- ` Digest not carried on ${plural2(notCarried, "wrapped (tse_) frame")}. A wrapped frame is hashed over its full event, and the bundle does not hold that event for these frames: an export before format 3 never did, and a format-3 export leaves it out when the stored row cannot be proven to rebuild it. For these frames, only the links and the Merkle root can be checked.`
79163
+ ` Digest not carried on ${plural3(notCarried, "wrapped (tse_) frame")}. A wrapped frame is hashed over its full event, and the bundle does not hold that event for these frames: an export before format 3 never did, and a format-3 export leaves it out when the stored row cannot be proven to rebuild it. For these frames, only the links and the Merkle root can be checked.`
79041
79164
  );
79042
79165
  }
79043
79166
  lines.push("");
@@ -79066,7 +79189,7 @@ function formatVerification(result2) {
79066
79189
  (c) => c.status === "broken"
79067
79190
  ).length;
79068
79191
  lines.push(
79069
- result2.ok ? `HELD ${runId}: ${plural2(result2.frames.length, "frame")}` : `BROKEN ${runId}: ${brokenFrames} of ${plural2(result2.frames.length, "frame")} broken, ${plural2(brokenChecks, "check")} broken`
79192
+ result2.ok ? `HELD ${runId}: ${plural3(result2.frames.length, "frame")}` : `BROKEN ${runId}: ${brokenFrames} of ${plural3(result2.frames.length, "frame")} broken, ${plural3(brokenChecks, "check")} broken`
79070
79193
  );
79071
79194
  return lines;
79072
79195
  }
@@ -79084,7 +79207,7 @@ async function verifyBundle3(bundle2, opts = {}, writer = stdoutWriter) {
79084
79207
  if (!result2.ok && (process.exitCode === void 0 || process.exitCode === 0))
79085
79208
  process.exitCode = 1;
79086
79209
  }
79087
- var REQUIRED, OPTIONAL, BundleReadError, plural2;
79210
+ var REQUIRED, OPTIONAL, BundleReadError, plural3;
79088
79211
  var init_verify2 = __esm({
79089
79212
  "src/commands/verify.ts"() {
79090
79213
  init_esm2();
@@ -79099,7 +79222,7 @@ var init_verify2 = __esm({
79099
79222
  OPTIONAL = "redactions.json";
79100
79223
  BundleReadError = class extends Error {
79101
79224
  };
79102
- plural2 = (n4, word) => `${n4} ${word}${n4 === 1 ? "" : "s"}`;
79225
+ plural3 = (n4, word) => `${n4} ${word}${n4 === 1 ? "" : "s"}`;
79103
79226
  }
79104
79227
  });
79105
79228
 
@@ -79320,7 +79443,7 @@ function ago(iso, now = /* @__PURE__ */ new Date()) {
79320
79443
  if (hours < 48) return `${hours}h ago`;
79321
79444
  return `${Math.round(hours / 24)}d ago`;
79322
79445
  }
79323
- function plural3(count12, one, many) {
79446
+ function plural4(count12, one, many) {
79324
79447
  return `${count12} ${count12 === 1 ? one : many}`;
79325
79448
  }
79326
79449
  function table(headers, rows) {
@@ -79334,7 +79457,7 @@ function table(headers, rows) {
79334
79457
  }
79335
79458
  function formatWorkspaceMemories(result2, now = /* @__PURE__ */ new Date()) {
79336
79459
  if (result2.groups.length === 0) {
79337
- return result2.total_groups === 0 ? "No memories yet. Oxagen collects them from enrolled hosts every five minutes." : `No memories on this page. The list holds ${plural3(result2.total_groups, "group", "groups")}.`;
79460
+ return result2.total_groups === 0 ? "No memories yet. Oxagen collects them from enrolled hosts every five minutes." : `No memories on this page. The list holds ${plural4(result2.total_groups, "group", "groups")}.`;
79338
79461
  }
79339
79462
  const rows = result2.groups.map((group) => {
79340
79463
  const { memory } = group;
@@ -79359,14 +79482,14 @@ function formatWorkspaceMemories(result2, now = /* @__PURE__ */ new Date()) {
79359
79482
  const shown2 = result2.groups.length;
79360
79483
  lines.push(
79361
79484
  "",
79362
- shown2 < result2.total_groups ? `Showing ${shown2} of ${plural3(result2.total_groups, "group", "groups")}. Use --limit and --offset to page.` : `${plural3(result2.total_groups, "group", "groups")}.`
79485
+ shown2 < result2.total_groups ? `Showing ${shown2} of ${plural4(result2.total_groups, "group", "groups")}. Use --limit and --offset to page.` : `${plural4(result2.total_groups, "group", "groups")}.`
79363
79486
  );
79364
79487
  if (result2.truncated)
79365
79488
  lines.push(
79366
79489
  `More than ${result2.total_memories} memories matched, and the list groups the top ${result2.total_memories}. Narrow the filters to see the rest.`
79367
79490
  );
79368
79491
  lines.push(
79369
- `${plural3(result2.waiting, "memory waits", "memories wait")} in this workspace.`
79492
+ `${plural4(result2.waiting, "memory waits", "memories wait")} in this workspace.`
79370
79493
  );
79371
79494
  return lines.join("\n");
79372
79495
  }
@@ -79450,7 +79573,7 @@ function formatDismissResult(result2, restore) {
79450
79573
  const lines = [];
79451
79574
  if (result2.changed.length > 0)
79452
79575
  lines.push(
79453
- `${restore ? "Restored" : "Dismissed"} ${plural3(result2.changed.length, "memory", "memories")}: ${result2.changed.join(", ")}.`
79576
+ `${restore ? "Restored" : "Dismissed"} ${plural4(result2.changed.length, "memory", "memories")}: ${result2.changed.join(", ")}.`
79454
79577
  );
79455
79578
  else lines.push(`No memory was ${restore ? "restored" : "dismissed"}.`);
79456
79579
  if (!restore && result2.rejections > 0)
@@ -101965,11 +102088,11 @@ function errorText4(error) {
101965
102088
  function asSentence(text5) {
101966
102089
  return /[.!?…]$/.test(text5) ? text5 : `${text5}.`;
101967
102090
  }
101968
- function plural4(count12, one, many) {
102091
+ function plural5(count12, one, many) {
101969
102092
  return `${count12} ${count12 === 1 ? one : many}`;
101970
102093
  }
101971
102094
  function pagingNote(paged, options) {
101972
- const read2 = `${plural4(paged.items, "item", "items")} from ${plural4(paged.pages, "page", "pages")}`;
102095
+ const read2 = `${plural5(paged.items, "item", "items")} from ${plural5(paged.pages, "page", "pages")}`;
101973
102096
  switch (paged.stop) {
101974
102097
  case "last_page":
101975
102098
  return void 0;
@@ -121430,12 +121553,12 @@ function checkString(schema, value, path2) {
121430
121553
  const length = [...value].length;
121431
121554
  if (typeof schema.minLength === "number" && length < schema.minLength) {
121432
121555
  issues.push(
121433
- `${path2} must be at least ${schema.minLength} ${plural5(schema.minLength, "character")} long.`
121556
+ `${path2} must be at least ${schema.minLength} ${plural6(schema.minLength, "character")} long.`
121434
121557
  );
121435
121558
  }
121436
121559
  if (typeof schema.maxLength === "number" && length > schema.maxLength) {
121437
121560
  issues.push(
121438
- `${path2} must be at most ${schema.maxLength} ${plural5(schema.maxLength, "character")} long.`
121561
+ `${path2} must be at most ${schema.maxLength} ${plural6(schema.maxLength, "character")} long.`
121439
121562
  );
121440
121563
  }
121441
121564
  if (typeof schema.pattern === "string" && testPattern(schema.pattern, value) === false) {
@@ -121524,7 +121647,7 @@ function listOf(values) {
121524
121647
  const more = values.length - shown2.length;
121525
121648
  return more > 0 ? `${shown2.join(", ")}, and ${more} more` : shown2.join(", ");
121526
121649
  }
121527
- function plural5(count12, one, many = `${one}s`) {
121650
+ function plural6(count12, one, many = `${one}s`) {
121528
121651
  return count12 === 1 ? one : many;
121529
121652
  }
121530
121653
  var MAX_DEPTH2, MAX_STEPS, MAX_ISSUES, TYPE_NAMES, Checker;
@@ -121588,12 +121711,12 @@ var init_validate = __esm({
121588
121711
  const issues = [];
121589
121712
  if (typeof schema.minItems === "number" && value.length < schema.minItems) {
121590
121713
  issues.push(
121591
- `${path2} must have at least ${schema.minItems} ${plural5(schema.minItems, "item")}.`
121714
+ `${path2} must have at least ${schema.minItems} ${plural6(schema.minItems, "item")}.`
121592
121715
  );
121593
121716
  }
121594
121717
  if (typeof schema.maxItems === "number" && value.length > schema.maxItems) {
121595
121718
  issues.push(
121596
- `${path2} must have at most ${schema.maxItems} ${plural5(schema.maxItems, "item")}.`
121719
+ `${path2} must have at most ${schema.maxItems} ${plural6(schema.maxItems, "item")}.`
121597
121720
  );
121598
121721
  }
121599
121722
  if (schema.uniqueItems === true) {
@@ -121640,12 +121763,12 @@ var init_validate = __esm({
121640
121763
  }
121641
121764
  if (typeof schema.minProperties === "number" && present.length < schema.minProperties) {
121642
121765
  issues.push(
121643
- `${path2} must have at least ${schema.minProperties} ${plural5(schema.minProperties, "property", "properties")}.`
121766
+ `${path2} must have at least ${schema.minProperties} ${plural6(schema.minProperties, "property", "properties")}.`
121644
121767
  );
121645
121768
  }
121646
121769
  if (typeof schema.maxProperties === "number" && present.length > schema.maxProperties) {
121647
121770
  issues.push(
121648
- `${path2} must have at most ${schema.maxProperties} ${plural5(schema.maxProperties, "property", "properties")}.`
121771
+ `${path2} must have at most ${schema.maxProperties} ${plural6(schema.maxProperties, "property", "properties")}.`
121649
121772
  );
121650
121773
  }
121651
121774
  const properties = isRecord10(schema.properties) ? schema.properties : {};
@@ -130773,6 +130896,14 @@ function buildProgram() {
130773
130896
  const { repoLink: repoLink2 } = await Promise.resolve().then(() => (init_repo(), repo_exports));
130774
130897
  await repoLink2(ref2, opts);
130775
130898
  });
130899
+ repoCmd.command("scan").description(
130900
+ "List the agent harness files on a repository's default branch: instruction and rule files, skills, commands, subagent files, settings files and MCP configs. The repository need not be linked."
130901
+ ).argument("<owner/name>", "The repository, or the GitLab project path").option("--gitlab", "Scan a GitLab project the workspace has connected").option("--json", "Output JSON").action(
130902
+ async (ref2, opts) => {
130903
+ const { repoScan: repoScan2 } = await Promise.resolve().then(() => (init_repo_scan(), repo_scan_exports));
130904
+ await repoScan2(ref2, opts);
130905
+ }
130906
+ );
130776
130907
  repoCmd.command("unlink").description(
130777
130908
  "Unlink a linked repository by its binding id. A repository workspace.toml lists is removed by a steering PR. The steering repository is refused."
130778
130909
  ).argument("<bindingId>", "The rpb_\u2026 binding id `oxagen repo list` shows").option("--json", "Output JSON").action(async (bindingId, opts) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxagen/cli",
3
- "version": "2.1.4-654",
3
+ "version": "2.1.4-671",
4
4
  "description": "Oxagen governance CLI — spend, lineage, grounding, credentials, and audit (agentic coding lives in the stella CLI)",
5
5
  "type": "module",
6
6
  "bin": {