@open-code-review/cli 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -35769,6 +35769,7 @@ var import_express14 = __toESM(require_express2(), 1);
35769
35769
  var import_yaml = __toESM(require_dist(), 1);
35770
35770
  import { existsSync as existsSync12, readFileSync as readFileSync8 } from "node:fs";
35771
35771
  import { join as join16 } from "node:path";
35772
+ var MAX_INSTANCES_PER_PERSONA = 50;
35772
35773
  function loadTeamConfig(ocrDir) {
35773
35774
  const configPath = join16(ocrDir, "config.yaml");
35774
35775
  if (!existsSync12(configPath)) {
@@ -35830,6 +35831,11 @@ function parseEntry(persona, entry) {
35830
35831
  `default_team.${persona}: count must be a positive integer (got ${entry})`
35831
35832
  );
35832
35833
  }
35834
+ if (entry > MAX_INSTANCES_PER_PERSONA) {
35835
+ throw new Error(
35836
+ `default_team.${persona}: count must be <= ${MAX_INSTANCES_PER_PERSONA} (got ${entry})`
35837
+ );
35838
+ }
35833
35839
  return Array.from({ length: entry }, () => ({}));
35834
35840
  }
35835
35841
  if (Array.isArray(entry)) {
@@ -35838,6 +35844,11 @@ function parseEntry(persona, entry) {
35838
35844
  `default_team.${persona}: list form must contain at least one instance`
35839
35845
  );
35840
35846
  }
35847
+ if (entry.length > MAX_INSTANCES_PER_PERSONA) {
35848
+ throw new Error(
35849
+ `default_team.${persona}: list form must contain <= ${MAX_INSTANCES_PER_PERSONA} instances (got ${entry.length})`
35850
+ );
35851
+ }
35841
35852
  return entry.map((item, idx) => parseListItem(persona, idx, item));
35842
35853
  }
35843
35854
  if (entry && typeof entry === "object") {
@@ -35859,6 +35870,11 @@ function parseEntry(persona, entry) {
35859
35870
  `default_team.${persona}: count must be a positive integer (got ${String(count)})`
35860
35871
  );
35861
35872
  }
35873
+ if (count > MAX_INSTANCES_PER_PERSONA) {
35874
+ throw new Error(
35875
+ `default_team.${persona}: count must be <= ${MAX_INSTANCES_PER_PERSONA} (got ${count})`
35876
+ );
35877
+ }
35862
35878
  const teamModel = readOptionalString(obj, "model", `default_team.${persona}.model`);
35863
35879
  return Array.from({ length: count }, () => ({ teamModel }));
35864
35880
  }
package/dist/index.js CHANGED
@@ -30024,6 +30024,7 @@ function ensureGitignore(ocrDir) {
30024
30024
  var import_yaml = __toESM(require_dist(), 1);
30025
30025
  import { existsSync as existsSync2, readFileSync as readFileSync3 } from "node:fs";
30026
30026
  import { join as join2 } from "node:path";
30027
+ var MAX_INSTANCES_PER_PERSONA = 50;
30027
30028
  function loadTeamConfig(ocrDir) {
30028
30029
  const configPath = join2(ocrDir, "config.yaml");
30029
30030
  if (!existsSync2(configPath)) {
@@ -30085,6 +30086,11 @@ function parseEntry(persona, entry) {
30085
30086
  `default_team.${persona}: count must be a positive integer (got ${entry})`
30086
30087
  );
30087
30088
  }
30089
+ if (entry > MAX_INSTANCES_PER_PERSONA) {
30090
+ throw new Error(
30091
+ `default_team.${persona}: count must be <= ${MAX_INSTANCES_PER_PERSONA} (got ${entry})`
30092
+ );
30093
+ }
30088
30094
  return Array.from({ length: entry }, () => ({}));
30089
30095
  }
30090
30096
  if (Array.isArray(entry)) {
@@ -30093,6 +30099,11 @@ function parseEntry(persona, entry) {
30093
30099
  `default_team.${persona}: list form must contain at least one instance`
30094
30100
  );
30095
30101
  }
30102
+ if (entry.length > MAX_INSTANCES_PER_PERSONA) {
30103
+ throw new Error(
30104
+ `default_team.${persona}: list form must contain <= ${MAX_INSTANCES_PER_PERSONA} instances (got ${entry.length})`
30105
+ );
30106
+ }
30096
30107
  return entry.map((item, idx) => parseListItem(persona, idx, item));
30097
30108
  }
30098
30109
  if (entry && typeof entry === "object") {
@@ -30114,6 +30125,11 @@ function parseEntry(persona, entry) {
30114
30125
  `default_team.${persona}: count must be a positive integer (got ${String(count)})`
30115
30126
  );
30116
30127
  }
30128
+ if (count > MAX_INSTANCES_PER_PERSONA) {
30129
+ throw new Error(
30130
+ `default_team.${persona}: count must be <= ${MAX_INSTANCES_PER_PERSONA} (got ${count})`
30131
+ );
30132
+ }
30117
30133
  const teamModel = readOptionalString(obj, "model", `default_team.${persona}.model`);
30118
30134
  return Array.from({ length: count }, () => ({ teamModel }));
30119
30135
  }
@@ -30206,6 +30222,71 @@ function resolveTeamComposition(team, override) {
30206
30222
  }
30207
30223
  return result;
30208
30224
  }
30225
+ var REVIEWER_ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
30226
+ function parseTeamSpec(spec, aliases = {}, defaultModel = null) {
30227
+ const trimmed = spec.trim();
30228
+ if (trimmed.length === 0) {
30229
+ throw new Error(
30230
+ "--team spec is empty; expected reviewer-id:count[,reviewer-id:count...]"
30231
+ );
30232
+ }
30233
+ const model = resolveModel(null, null, aliases, defaultModel);
30234
+ if (model !== null) assertSafeModelId(model, "--team");
30235
+ const seen = /* @__PURE__ */ new Set();
30236
+ const result = [];
30237
+ for (const rawEntry of trimmed.split(",")) {
30238
+ const entry = rawEntry.trim();
30239
+ if (entry.length === 0) {
30240
+ throw new Error(
30241
+ `--team has an empty entry (stray or trailing comma) in "${spec}"`
30242
+ );
30243
+ }
30244
+ const colon = entry.indexOf(":");
30245
+ if (colon === -1) {
30246
+ throw new Error(
30247
+ `--team entry "${entry}" must be "reviewer-id:count" \u2014 the :count is required`
30248
+ );
30249
+ }
30250
+ const persona = entry.slice(0, colon).trim();
30251
+ const countRaw = entry.slice(colon + 1).trim();
30252
+ if (!REVIEWER_ID_PATTERN.test(persona)) {
30253
+ throw new Error(
30254
+ `--team reviewer id "${persona}" is invalid; expected lowercase letters, digits, and single hyphens (e.g. principal, martin-fowler)`
30255
+ );
30256
+ }
30257
+ if (seen.has(persona)) {
30258
+ throw new Error(
30259
+ `--team lists "${persona}" more than once; combine its instances into a single entry (e.g. ${persona}:2)`
30260
+ );
30261
+ }
30262
+ if (!/^[0-9]+$/.test(countRaw)) {
30263
+ throw new Error(
30264
+ `--team count for "${persona}" must be a positive integer (got "${countRaw}")`
30265
+ );
30266
+ }
30267
+ const count = Number(countRaw);
30268
+ if (count < 1) {
30269
+ throw new Error(
30270
+ `--team count for "${persona}" must be a positive integer (got ${count})`
30271
+ );
30272
+ }
30273
+ if (count > MAX_INSTANCES_PER_PERSONA) {
30274
+ throw new Error(
30275
+ `--team count for "${persona}" must be <= ${MAX_INSTANCES_PER_PERSONA} (got ${count})`
30276
+ );
30277
+ }
30278
+ seen.add(persona);
30279
+ for (let i = 0; i < count; i++) {
30280
+ result.push({
30281
+ persona,
30282
+ instance_index: i + 1,
30283
+ name: `${persona}-${i + 1}`,
30284
+ model
30285
+ });
30286
+ }
30287
+ }
30288
+ return result;
30289
+ }
30209
30290
 
30210
30291
  // src/lib/installer.ts
30211
30292
  init_src();
@@ -30770,7 +30851,7 @@ ${hint}
30770
30851
  }
30771
30852
 
30772
30853
  // src/lib/version.ts
30773
- var CLI_VERSION = true ? "2.3.0" : createRequire(import.meta.url)("../../package.json").version;
30854
+ var CLI_VERSION = true ? "2.4.0" : createRequire(import.meta.url)("../../package.json").version;
30774
30855
 
30775
30856
  // src/lib/deps.ts
30776
30857
  init_src();
@@ -36641,6 +36722,9 @@ function parseSessionOverride(raw) {
36641
36722
  return result;
36642
36723
  }
36643
36724
  var resolveSubcommand = new Command("resolve").description("Resolve and print the team composition for the active workspace").option(
36725
+ "--team <spec>",
36726
+ "Session team override replacing default_team. Format: reviewer-id:count[,reviewer-id:count...] (e.g. principal:2,architect:1)"
36727
+ ).option(
36644
36728
  "--session-override <json>",
36645
36729
  "JSON array of ReviewerInstance overrides applied on top of disk config"
36646
36730
  ).option("--session-override-stdin", "Read --session-override JSON from stdin").option("--json", "Emit JSON for programmatic consumption (the AI workflow uses this)").action(
@@ -36649,7 +36733,8 @@ var resolveSubcommand = new Command("resolve").description("Resolve and print th
36649
36733
  requireOcrSetup(targetDir);
36650
36734
  const ocrDir = join21(targetDir, ".ocr");
36651
36735
  try {
36652
- const { team } = loadTeamConfig(ocrDir);
36736
+ const { team, aliases, defaultModel } = loadTeamConfig(ocrDir);
36737
+ const baseTeam = options.team ? parseTeamSpec(options.team, aliases, defaultModel) : team;
36653
36738
  let override;
36654
36739
  if (options.sessionOverride) {
36655
36740
  override = parseSessionOverride(options.sessionOverride);
@@ -36659,7 +36744,7 @@ var resolveSubcommand = new Command("resolve").description("Resolve and print th
36659
36744
  override = parseSessionOverride(raw);
36660
36745
  }
36661
36746
  }
36662
- const resolved = resolveTeamComposition(team, override);
36747
+ const resolved = resolveTeamComposition(baseTeam, override);
36663
36748
  if (options.json) {
36664
36749
  console.log(JSON.stringify(resolved, null, 2));
36665
36750
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-code-review/cli",
3
- "version": "2.3.0",
3
+ "version": "2.4.0",
4
4
  "description": "CLI for Open Code Review - Multi-environment setup and progress tracking",
5
5
  "type": "module",
6
6
  "bin": {
@@ -45,14 +45,14 @@
45
45
  "ora": "^8.1.1",
46
46
  "socket.io": "^4.8",
47
47
  "yaml": "^2.8.3",
48
- "@open-code-review/agents": "2.3.0"
48
+ "@open-code-review/agents": "2.4.0"
49
49
  },
50
50
  "publishConfig": {
51
51
  "access": "public"
52
52
  },
53
53
  "devDependencies": {
54
- "@open-code-review/platform": "0.0.0",
54
+ "@open-code-review/config": "0.0.0",
55
55
  "@open-code-review/persistence": "0.0.0",
56
- "@open-code-review/config": "0.0.0"
56
+ "@open-code-review/platform": "0.0.0"
57
57
  }
58
58
  }