@open-code-review/cli 2.1.0 → 2.2.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.
Files changed (62) hide show
  1. package/dist/dashboard/client/assets/{_basePickBy-B3ALyupE.js → _basePickBy-BAlGnwHG.js} +1 -1
  2. package/dist/dashboard/client/assets/{_baseUniq-b2RALAWc.js → _baseUniq-CoauyOeL.js} +1 -1
  3. package/dist/dashboard/client/assets/{arc-DcSVvhUd.js → arc-DtS0aHfP.js} +1 -1
  4. package/dist/dashboard/client/assets/{architectureDiagram-VXUJARFQ-BNUlmSCS.js → architectureDiagram-VXUJARFQ-CnWmtRTh.js} +1 -1
  5. package/dist/dashboard/client/assets/{blockDiagram-VD42YOAC-BmhiQVwa.js → blockDiagram-VD42YOAC-DgPp4oGV.js} +1 -1
  6. package/dist/dashboard/client/assets/{c4Diagram-YG6GDRKO-jyJ3WOv5.js → c4Diagram-YG6GDRKO--LV4qQaE.js} +1 -1
  7. package/dist/dashboard/client/assets/channel-BU2129fl.js +1 -0
  8. package/dist/dashboard/client/assets/{chunk-4BX2VUAB-x1dQU_s3.js → chunk-4BX2VUAB-BRglpc7Z.js} +1 -1
  9. package/dist/dashboard/client/assets/{chunk-55IACEB6-CwbsE2XQ.js → chunk-55IACEB6-Bgx06_CV.js} +1 -1
  10. package/dist/dashboard/client/assets/{chunk-B4BG7PRW-BaE7c-ti.js → chunk-B4BG7PRW-D6HN3Yiy.js} +1 -1
  11. package/dist/dashboard/client/assets/{chunk-DI55MBZ5-Bw5PUaMK.js → chunk-DI55MBZ5-NH9EgN9T.js} +1 -1
  12. package/dist/dashboard/client/assets/{chunk-FMBD7UC4-B7cF6P3s.js → chunk-FMBD7UC4-xriO6WNP.js} +1 -1
  13. package/dist/dashboard/client/assets/{chunk-QN33PNHL-OY4evNHd.js → chunk-QN33PNHL-CV1h6_Zl.js} +1 -1
  14. package/dist/dashboard/client/assets/{chunk-QZHKN3VN-BpjQwIWz.js → chunk-QZHKN3VN-CV4VzxNq.js} +1 -1
  15. package/dist/dashboard/client/assets/{chunk-TZMSLE5B-D8b_Oq9B.js → chunk-TZMSLE5B-isdklocW.js} +1 -1
  16. package/dist/dashboard/client/assets/classDiagram-2ON5EDUG-CVftFGiR.js +1 -0
  17. package/dist/dashboard/client/assets/classDiagram-v2-WZHVMYZB-CVftFGiR.js +1 -0
  18. package/dist/dashboard/client/assets/clone-DC6LEEC5.js +1 -0
  19. package/dist/dashboard/client/assets/{cose-bilkent-S5V4N54A-C-sfP8PN.js → cose-bilkent-S5V4N54A-CCzlFSJf.js} +1 -1
  20. package/dist/dashboard/client/assets/{dagre-6UL2VRFP-Cqfo0NRg.js → dagre-6UL2VRFP-DVN3PkjZ.js} +1 -1
  21. package/dist/dashboard/client/assets/{diagram-PSM6KHXK-BR3ppxqI.js → diagram-PSM6KHXK-SzJVoSsb.js} +1 -1
  22. package/dist/dashboard/client/assets/{diagram-QEK2KX5R-Dvcx6x3R.js → diagram-QEK2KX5R-CgGn7ts-.js} +1 -1
  23. package/dist/dashboard/client/assets/{diagram-S2PKOQOG-DoyBLnVN.js → diagram-S2PKOQOG-Bz1ukSx8.js} +1 -1
  24. package/dist/dashboard/client/assets/{erDiagram-Q2GNP2WA-hy77l1cL.js → erDiagram-Q2GNP2WA-CpstUTMZ.js} +1 -1
  25. package/dist/dashboard/client/assets/{flowDiagram-NV44I4VS-Bz0B1rKM.js → flowDiagram-NV44I4VS-aYVydGhp.js} +1 -1
  26. package/dist/dashboard/client/assets/{ganttDiagram-JELNMOA3-CLgrZPoC.js → ganttDiagram-JELNMOA3-Cb2DUSRk.js} +1 -1
  27. package/dist/dashboard/client/assets/{gitGraphDiagram-V2S2FVAM-DwJ-1f-v.js → gitGraphDiagram-V2S2FVAM-BUOnwA2w.js} +1 -1
  28. package/dist/dashboard/client/assets/{graph-DDBMM_t2.js → graph-4X5ddhLp.js} +1 -1
  29. package/dist/dashboard/client/assets/index-CKWqYAfu.js +581 -0
  30. package/dist/dashboard/client/assets/index-CzxeSSaQ.css +1 -0
  31. package/dist/dashboard/client/assets/{infoDiagram-HS3SLOUP-Bhn1FmAk.js → infoDiagram-HS3SLOUP-BlMqcrwm.js} +1 -1
  32. package/dist/dashboard/client/assets/{journeyDiagram-XKPGCS4Q-CzGbjX1y.js → journeyDiagram-XKPGCS4Q-DF2ew7ju.js} +1 -1
  33. package/dist/dashboard/client/assets/{kanban-definition-3W4ZIXB7-Da77-WYk.js → kanban-definition-3W4ZIXB7-BKQMx0-n.js} +1 -1
  34. package/dist/dashboard/client/assets/{layout-CVwSB-GS.js → layout-DNcn2g9w.js} +1 -1
  35. package/dist/dashboard/client/assets/{linear-CTRAc5Jn.js → linear-Bqy9gvqb.js} +1 -1
  36. package/dist/dashboard/client/assets/{mermaid-renderer-Bjo170ax.js → mermaid-renderer-dJ71wgld.js} +4 -4
  37. package/dist/dashboard/client/assets/{mindmap-definition-VGOIOE7T-B55C2odl.js → mindmap-definition-VGOIOE7T-BARc8sqJ.js} +1 -1
  38. package/dist/dashboard/client/assets/{pieDiagram-ADFJNKIX-5lrQLrSz.js → pieDiagram-ADFJNKIX-CULlNZTd.js} +1 -1
  39. package/dist/dashboard/client/assets/{quadrantDiagram-AYHSOK5B-Bg55gC30.js → quadrantDiagram-AYHSOK5B-BJEZPVe9.js} +1 -1
  40. package/dist/dashboard/client/assets/{requirementDiagram-UZGBJVZJ-CyR4YFJY.js → requirementDiagram-UZGBJVZJ-BhMsmUIs.js} +1 -1
  41. package/dist/dashboard/client/assets/{sankeyDiagram-TZEHDZUN-BVWKr9_-.js → sankeyDiagram-TZEHDZUN-BYbNgogG.js} +1 -1
  42. package/dist/dashboard/client/assets/{sequenceDiagram-WL72ISMW-D0AJg_tE.js → sequenceDiagram-WL72ISMW-MoM_NwWk.js} +1 -1
  43. package/dist/dashboard/client/assets/{stateDiagram-FKZM4ZOC-BuHpTgim.js → stateDiagram-FKZM4ZOC-ditrlbM3.js} +1 -1
  44. package/dist/dashboard/client/assets/stateDiagram-v2-4FDKWEC3-SqoG2LCn.js +1 -0
  45. package/dist/dashboard/client/assets/{timeline-definition-IT6M3QCI-LDhpAmDd.js → timeline-definition-IT6M3QCI-DOAJyjuz.js} +1 -1
  46. package/dist/dashboard/client/assets/{treemap-GDKQZRPO-Dd4gjvUl.js → treemap-GDKQZRPO-BBJkjnJl.js} +1 -1
  47. package/dist/dashboard/client/assets/{xychartDiagram-PRI3JC2R-B9RDod39.js → xychartDiagram-PRI3JC2R-CPW4s5vm.js} +1 -1
  48. package/dist/dashboard/client/index.html +2 -2
  49. package/dist/dashboard/server.js +1188 -579
  50. package/dist/index.js +1395 -335
  51. package/dist/lib/db/index.js +485 -24
  52. package/dist/lib/models.js +125 -50
  53. package/dist/lib/runtime-config.js +29 -13
  54. package/dist/lib/state/index.js +2196 -0
  55. package/package.json +8 -2
  56. package/dist/dashboard/client/assets/channel-D3J8-GF_.js +0 -1
  57. package/dist/dashboard/client/assets/classDiagram-2ON5EDUG-tkFUL-1Y.js +0 -1
  58. package/dist/dashboard/client/assets/classDiagram-v2-WZHVMYZB-tkFUL-1Y.js +0 -1
  59. package/dist/dashboard/client/assets/clone-CkY5ajLr.js +0 -1
  60. package/dist/dashboard/client/assets/index-Cr9yEo_B.js +0 -576
  61. package/dist/dashboard/client/assets/index-Z1pPudAt.css +0 -1
  62. package/dist/dashboard/client/assets/stateDiagram-v2-4FDKWEC3-DwAPhteN.js +0 -1
@@ -7,31 +7,70 @@ import {
7
7
  import { promisify } from "node:util";
8
8
  var execFilePromise = promisify(execFile);
9
9
  var isWindows = process.platform === "win32";
10
- function execBinary(binary, args, opts) {
11
- return execFileSync(binary, args, {
10
+ async function execBinaryAsync(binary, args, opts) {
11
+ return execFilePromise(binary, args, {
12
12
  ...opts,
13
13
  shell: isWindows
14
14
  });
15
15
  }
16
16
 
17
17
  // src/lib/models.ts
18
- var BUNDLED_CLAUDE_MODELS = [
19
- { id: "claude-opus-4-7", displayName: "Claude Opus 4.7" },
20
- { id: "claude-sonnet-4-6", displayName: "Claude Sonnet 4.6" },
21
- { id: "claude-haiku-4-5-20251001", displayName: "Claude Haiku 4.5" }
22
- ];
23
- var BUNDLED_OPENCODE_MODELS = [
24
- { id: "anthropic/claude-opus-4-7", provider: "anthropic" },
25
- { id: "anthropic/claude-sonnet-4-6", provider: "anthropic" },
26
- { id: "anthropic/claude-haiku-4-5-20251001", provider: "anthropic" }
27
- ];
28
- function detectActiveVendor() {
29
- for (const vendor of ["claude", "opencode"]) {
18
+ function parseOpenCodeModelList(stdout) {
19
+ const models = [];
20
+ for (const rawLine of stdout.split(/\r?\n/)) {
21
+ const line = rawLine.trim();
22
+ if (!/^[^\s:]+\/\S+$/.test(line)) continue;
23
+ const provider = line.slice(0, line.indexOf("/"));
24
+ models.push({ id: line, provider });
25
+ }
26
+ return models.length > 0 ? models : null;
27
+ }
28
+ var VENDOR_MODEL_STRATEGIES = {
29
+ claude: {
30
+ displayName: "Claude Code",
31
+ native: {
32
+ // Verified against Claude Code 2.1.x: the CLI has no model-listing
33
+ // subcommand (`claude models --json` → "unknown option"). Revisit if
34
+ // a future release adds one.
35
+ unavailableReason: "Claude Code does not provide a model-listing command; showing its documented model aliases instead"
36
+ },
37
+ // Vendor-documented aliases that always track the latest generation —
38
+ // dated ids here would go stale by construction (the exact bug class of
39
+ // issue #39). Pinned dated ids remain available via free-text entry.
40
+ bundled: [
41
+ { id: "opus", displayName: "Claude Opus (latest)" },
42
+ { id: "sonnet", displayName: "Claude Sonnet (latest)" },
43
+ { id: "haiku", displayName: "Claude Haiku (latest)" }
44
+ ]
45
+ },
46
+ opencode: {
47
+ displayName: "OpenCode",
48
+ native: {
49
+ // Plain `opencode models` — newline-delimited ids. (`--json` is not a
50
+ // real flag, and `--verbose` interleaves JSON metadata blocks that
51
+ // defeat line parsing.)
52
+ args: ["models"],
53
+ parse: parseOpenCodeModelList
54
+ },
55
+ bundled: [
56
+ { id: "anthropic/claude-opus-4-8", provider: "anthropic" },
57
+ { id: "anthropic/claude-sonnet-4-6", provider: "anthropic" },
58
+ { id: "anthropic/claude-haiku-4-5", provider: "anthropic" }
59
+ ]
60
+ }
61
+ };
62
+ var SUPPORTED_VENDORS = Object.keys(
63
+ VENDOR_MODEL_STRATEGIES
64
+ );
65
+ function isModelVendor(value) {
66
+ return Object.hasOwn(VENDOR_MODEL_STRATEGIES, value);
67
+ }
68
+ async function detectActiveVendor() {
69
+ for (const vendor of SUPPORTED_VENDORS) {
30
70
  try {
31
- execBinary(vendor, ["--version"], {
71
+ await execBinaryAsync(vendor, ["--version"], {
32
72
  encoding: "utf-8",
33
- timeout: 3e3,
34
- stdio: ["ignore", "pipe", "ignore"]
73
+ timeout: 3e3
35
74
  });
36
75
  return vendor;
37
76
  } catch {
@@ -39,47 +78,83 @@ function detectActiveVendor() {
39
78
  }
40
79
  return null;
41
80
  }
42
- function tryNativeEnumeration(vendor) {
81
+ function describeProbeFailure(vendor, args, err) {
82
+ const command = `${vendor} ${args.join(" ")}`;
83
+ const e = err;
84
+ if (e.code === "ENOENT") {
85
+ return `\`${vendor}\` is not installed or not on PATH`;
86
+ }
87
+ if (e.killed) {
88
+ return `\`${command}\` timed out or exceeded output limits`;
89
+ }
90
+ const stderr = typeof e.stderr === "string" ? e.stderr.trim() : "";
91
+ const firstLine = (stderr.split(/\r?\n/)[0] ?? "").replace(/\u001b\[[0-9;]*[A-Za-z]/g, "").replace(/[\u0000-\u001f\u007f]/g, "").slice(0, 200);
92
+ const detail = firstLine ? `: ${firstLine}` : "";
93
+ const exit = typeof e.code === "number" ? ` with exit code ${e.code}` : "";
94
+ return `\`${command}\` failed${exit}${detail}`;
95
+ }
96
+ async function tryNativeEnumeration(vendor, probe) {
97
+ let stdout;
43
98
  try {
44
- const output = execBinary(vendor, ["models", "--json"], {
99
+ const result = await execBinaryAsync(vendor, probe.args, {
45
100
  encoding: "utf-8",
46
- timeout: 5e3,
47
- stdio: ["ignore", "pipe", "ignore"]
101
+ timeout: 5e3
48
102
  });
49
- const parsed = JSON.parse(output);
50
- if (!Array.isArray(parsed)) return null;
51
- const models = [];
52
- for (const item of parsed) {
53
- if (typeof item === "string") {
54
- models.push({ id: item });
55
- } else if (typeof item === "object" && item !== null && "id" in item && typeof item.id === "string") {
56
- const obj = item;
57
- const desc = { id: obj.id };
58
- if (typeof obj.displayName === "string") desc.displayName = obj.displayName;
59
- if (typeof obj.provider === "string") desc.provider = obj.provider;
60
- if (Array.isArray(obj.tags)) {
61
- desc.tags = obj.tags.filter((t) => typeof t === "string");
62
- }
63
- models.push(desc);
64
- }
65
- }
66
- return models.length > 0 ? models : null;
67
- } catch {
68
- return null;
103
+ stdout = result.stdout;
104
+ } catch (err) {
105
+ return { models: null, reason: describeProbeFailure(vendor, probe.args, err) };
69
106
  }
107
+ const models = probe.parse(stdout);
108
+ if (!models) {
109
+ return {
110
+ models: null,
111
+ reason: `\`${vendor} ${probe.args.join(" ")}\` output did not contain any model identifiers`
112
+ };
113
+ }
114
+ return { models };
70
115
  }
71
- function bundledForVendor(vendor) {
72
- if (vendor === "claude") return BUNDLED_CLAUDE_MODELS;
73
- return BUNDLED_OPENCODE_MODELS;
116
+ var SUCCESS_TTL_MS = 6e4;
117
+ var FAILURE_TTL_MS = 1e4;
118
+ var cache = /* @__PURE__ */ new Map();
119
+ function clearModelListCache() {
120
+ cache.clear();
74
121
  }
75
- function listModelsForVendor(vendor) {
76
- const native = tryNativeEnumeration(vendor);
77
- if (native) {
78
- return { vendor, source: "native", models: native };
122
+ async function listModelsForVendor(vendor) {
123
+ const cached = cache.get(vendor);
124
+ if (cached && cached.expiresAt > Date.now()) {
125
+ return cached.result;
126
+ }
127
+ const strategy = VENDOR_MODEL_STRATEGIES[vendor];
128
+ if (!strategy) {
129
+ throw new Error(`Unknown vendor: ${vendor}`);
130
+ }
131
+ let result;
132
+ if ("unavailableReason" in strategy.native) {
133
+ result = {
134
+ vendor,
135
+ source: "bundled",
136
+ models: strategy.bundled,
137
+ nativeUnavailableReason: strategy.native.unavailableReason
138
+ };
139
+ } else {
140
+ const native = await tryNativeEnumeration(vendor, strategy.native);
141
+ result = native.models ? { vendor, source: "native", models: native.models } : {
142
+ vendor,
143
+ source: "bundled",
144
+ models: strategy.bundled,
145
+ nativeUnavailableReason: native.reason
146
+ };
79
147
  }
80
- return { vendor, source: "bundled", models: bundledForVendor(vendor) };
148
+ const ttl = result.source === "native" ? SUCCESS_TTL_MS : FAILURE_TTL_MS;
149
+ cache.set(vendor, { result, expiresAt: Date.now() + ttl });
150
+ return result;
81
151
  }
82
152
  export {
153
+ SUPPORTED_VENDORS,
154
+ VENDOR_MODEL_STRATEGIES,
155
+ clearModelListCache,
83
156
  detectActiveVendor,
84
- listModelsForVendor
157
+ isModelVendor,
158
+ listModelsForVendor,
159
+ parseOpenCodeModelList
85
160
  };
@@ -2,38 +2,54 @@
2
2
  import { existsSync, readFileSync } from "node:fs";
3
3
  import { join } from "node:path";
4
4
  var DEFAULT_AGENT_HEARTBEAT_SECONDS = 60;
5
- function getAgentHeartbeatSeconds(ocrDir) {
5
+ var DEFAULT_WORKFLOW_HARD_DEADLINE_MINUTES = 60;
6
+ function readRuntimePositiveInt(ocrDir, key, defaultValue) {
6
7
  const configPath = join(ocrDir, "config.yaml");
7
- if (!existsSync(configPath)) {
8
- return DEFAULT_AGENT_HEARTBEAT_SECONDS;
9
- }
8
+ if (!existsSync(configPath)) return defaultValue;
10
9
  let content;
11
10
  try {
12
11
  content = readFileSync(configPath, "utf-8");
13
12
  } catch {
14
- return DEFAULT_AGENT_HEARTBEAT_SECONDS;
13
+ return defaultValue;
15
14
  }
16
15
  const blockMatch = content.match(
17
- /^runtime:\s*\n(?:\s+[^\n]*\n)*?\s+agent_heartbeat_seconds:\s*([^\s#\n]+)/m
16
+ new RegExp(
17
+ String.raw`^runtime:\s*\n(?:\s+[^\n]*\n)*?\s+${key}:\s*([^\s#\n]+)`,
18
+ "m"
19
+ )
18
20
  );
19
21
  const inlineMatch = content.match(
20
- /^runtime:\s*\{[^}]*\bagent_heartbeat_seconds:\s*([^\s,}]+)/m
22
+ new RegExp(String.raw`^runtime:\s*\{[^}]*\b${key}:\s*([^\s,}]+)`, "m")
21
23
  );
22
24
  const raw = blockMatch?.[1] ?? inlineMatch?.[1];
23
- if (!raw) {
24
- return DEFAULT_AGENT_HEARTBEAT_SECONDS;
25
- }
25
+ if (!raw) return defaultValue;
26
26
  const parsed = Number(raw);
27
27
  if (!Number.isFinite(parsed) || parsed <= 0 || !Number.isInteger(parsed)) {
28
28
  process.stderr.write(
29
- `[ocr] runtime.agent_heartbeat_seconds is not a positive integer (got "${raw}"); falling back to ${DEFAULT_AGENT_HEARTBEAT_SECONDS}s.
29
+ `[ocr] runtime.${key} is not a positive integer (got "${raw}"); falling back to ${defaultValue}.
30
30
  `
31
31
  );
32
- return DEFAULT_AGENT_HEARTBEAT_SECONDS;
32
+ return defaultValue;
33
33
  }
34
34
  return parsed;
35
35
  }
36
+ function getAgentHeartbeatSeconds(ocrDir) {
37
+ return readRuntimePositiveInt(
38
+ ocrDir,
39
+ "agent_heartbeat_seconds",
40
+ DEFAULT_AGENT_HEARTBEAT_SECONDS
41
+ );
42
+ }
43
+ function getWorkflowHardDeadlineMs(ocrDir) {
44
+ return readRuntimePositiveInt(
45
+ ocrDir,
46
+ "workflow_hard_deadline_minutes",
47
+ DEFAULT_WORKFLOW_HARD_DEADLINE_MINUTES
48
+ ) * 60 * 1e3;
49
+ }
36
50
  export {
37
51
  DEFAULT_AGENT_HEARTBEAT_SECONDS,
38
- getAgentHeartbeatSeconds
52
+ DEFAULT_WORKFLOW_HARD_DEADLINE_MINUTES,
53
+ getAgentHeartbeatSeconds,
54
+ getWorkflowHardDeadlineMs
39
55
  };