@orion-agents/orion-code 0.3.27 → 0.3.29

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 (30) hide show
  1. package/CHANGELOG.md +115 -3
  2. package/README.md +9 -10
  3. package/README.zh-CN.md +7 -7
  4. package/dist/commands/workflow-command-handlers.d.ts +9 -1
  5. package/dist/commands/workflow-command-handlers.js +66 -0
  6. package/dist/commands/workflow-commands.js +5 -5
  7. package/dist/services/code-review/format.d.ts +12 -0
  8. package/dist/services/code-review/format.js +79 -0
  9. package/dist/services/code-review/runner.d.ts +76 -0
  10. package/dist/services/code-review/runner.js +368 -0
  11. package/dist/services/code-review/selector.d.ts +24 -0
  12. package/dist/services/code-review/selector.js +86 -0
  13. package/dist/services/code-review/snapshot.d.ts +7 -0
  14. package/dist/services/code-review/snapshot.js +11 -2
  15. package/dist/web/code-review-run-service.d.ts +68 -0
  16. package/dist/web/code-review-run-service.js +228 -0
  17. package/dist/web/server.js +37 -0
  18. package/dist/web/workbench-controller.d.ts +16 -0
  19. package/dist/web/workbench-controller.js +61 -0
  20. package/dist/web-client/assets/{FilesPanel-CdoCa8u0.js → FilesPanel-iBYj9ZRf.js} +1 -1
  21. package/dist/web-client/assets/{GitPanel-CRr_iIDz.js → GitPanel-D33R_bZr.js} +1 -1
  22. package/dist/web-client/assets/ReviewPanel-C_0upsDk.js +6 -0
  23. package/dist/web-client/assets/{TerminalPanel-BniCjatZ.js → TerminalPanel-C7A8dMNf.js} +1 -1
  24. package/dist/web-client/assets/{index-DCYKIeOj.css → index-BaOxrwGB.css} +1 -1
  25. package/dist/web-client/assets/{index-kQqA3li6.js → index-CqCgJ2ov.js} +13 -13
  26. package/dist/web-client/assets/{useAutoNotice-DPXFWIwK.js → useAutoNotice-C1qM-_Sg.js} +1 -1
  27. package/dist/web-client/index.html +2 -2
  28. package/npm-shrinkwrap.json +2 -2
  29. package/package.json +1 -1
  30. package/dist/web-client/assets/ReviewPanel-C1Cu2IRV.js +0 -5
package/CHANGELOG.md CHANGED
@@ -22,9 +22,121 @@ which is **not** a pass.
22
22
 
23
23
  ## [Unreleased]
24
24
 
25
- ## [0.3.27] — UNRELEASED
25
+ ## [0.3.29] — UNRELEASED
26
+
27
+ > **Status: candidate.** Open. The Web shared review loop
28
+ > (plan: `docs/plan/v0.3.29-plan.md`, PR3 core of the v0.3.27 review loop):
29
+ > the Host now starts the same bounded single-pass review runner the CLI uses
30
+ > (`runCodeReview`, v0.3.28) against the active Workspace. `POST /review/run`
31
+ > performs fast admission (one in-flight run per Host, typed
32
+ > `review_run_in_progress` 409 and `review_no_model` 422) and the model
33
+ > completion continues in the background; `GET /review/runs` and
34
+ > `GET /review/runs/:runId` read a bounded in-memory history where every
35
+ > receipt passes digest re-verification and is flagged `stale` when the
36
+ > repository revision changed after admission. The Review panel lists the runs
37
+ > with honest state banners (running / cancelled / failed / partial / stale
38
+ > never render as a green pass), groups findings P0→P3 with file:line anchors
39
+ > into the existing diff view, counts contract-invalid model output instead of
40
+ > hiding it, and can send each finding back to the Composer as a typed draft
41
+ > the user still confirms. The fileKey→path mapping is captured through an
42
+ > additive `onSnapshotCaptured` runner hook; the frozen receipt contract is
43
+ > unchanged. Not merged, tagged or published.
26
44
 
27
- > **Status: candidate.** Open. First slice of the professional code review loop
45
+ ### Added
46
+
47
+ - `src/web/code-review-run-service.ts` — the Host-side review run service:
48
+ single-flight admission, background execution of the shared runner, bounded
49
+ receipt history (20 runs, oldest finished evicted first), digest
50
+ re-verification on read, repository-revision staleness flags, cancellation,
51
+ and the `parseWebReviewSelectorV1` request validation.
52
+ - `src/web/workbench-controller.ts` — `reviewRunStart` / `reviewRunList` /
53
+ `reviewRunGet` / `reviewRunCancel`, with the review model adapter derived
54
+ from the control-plane Runtime's `llm` (typed 422 when the Host has no
55
+ configured model).
56
+ - `src/web/server.ts` — `POST /review/run` and
57
+ `POST /review/runs/:runId/cancel` behind `assertMutation` +
58
+ `executeMutation`, plus read-only `GET /review/runs[/:runId]` with context
59
+ guards.
60
+ - `web/src/components/review/ReviewRunsSection.tsx` and
61
+ `review-runs-view.ts` — the Review panel results section: run button,
62
+ polling while a run is in flight, priority-grouped findings, honest banners,
63
+ diff anchoring and typed Composer drafts.
64
+ - Tests: `tests/web-code-review-run-service.test.ts` (10 unit tests),
65
+ `tests/web-review-run-endpoint.test.ts` (4 real-host tests on a temp Git
66
+ repository, including the 403 nonce guard and the 422 no-model path),
67
+ `tests/web-review-runs-view.test.tsx` (13 pure + SSR view tests).
68
+
69
+ ### Not run
70
+
71
+ - Real Host + Chrome full-chain E2E and the human-labeled quality benchmark
72
+ (PR4) — the local automation sandbox has no model credentials; recorded
73
+ honestly as `not_run`, not silently skipped.
74
+
75
+ ## [0.3.28] — 2026-10-22
76
+
77
+ > **Status: published.** The typed `/review` runtime & CLI slice
78
+ > (plan: `docs/plan/v0.3.28-plan.md`, PR2 core of the v0.3.27 review loop):
79
+ > `/review` arguments now parse into the frozen `ReviewSelectorV1` (worktree /
80
+ > `--base` / repeatable `--path`, back-compat single-path filter) and unknown
81
+ > input returns the usage text instead of silently continuing as an ordinary
82
+ > chat turn. The review runs against the admission-time frozen Git snapshot
83
+ > through a bounded single-pass model completion; the model's findings are
84
+ > validated against the contract and anchored to the snapshot manifest, with
85
+ > invalid or unanchored findings counted and surfaced rather than silently
86
+ > dropped. Every run produces a digest-verifiable `CodeReviewResultV1` receipt
87
+ > rendered by the shared formatter with honest state banners: an empty scope
88
+ > reports "no changes under review" without calling the model, and partial,
89
+ > failed, cancelled or inconclusive runs never render as a green pass.
90
+ > Web wiring (PR3) and the qualification benchmark (PR4) remain subsequent
91
+ > slices. Merged as #284, tagged `v0.3.28` on main (`8a4722b`), published to
92
+ > npm (registry `latest` = 0.3.28).
93
+
94
+ ### Added
95
+
96
+ - `src/services/code-review/selector.ts` — the typed `/review` argument
97
+ parser: empty / `all` → worktree scope, `--base <ref>` → base scope,
98
+ repeatable `--path <path>` filters, single bare relative path kept as a
99
+ back-compat worktree filter; unknown options, missing values, repeated
100
+ `--base`, absolute paths and traversal are typed usage errors. Fourteen
101
+ tests pin every accepted shape and rejection path.
102
+ - `src/services/code-review/runner.ts` — the bounded single-pass review
103
+ runner: `resolveReviewBudgets` (tighten-only) → `captureReviewSnapshot`
104
+ (worktree contained reader) → frozen unified diff captured with the same
105
+ admission-time arguments → rules digest binding the read-only constraints
106
+ digest plus ancestor `AGENTS.md` contents → one model completion through an
107
+ injected adapter → contract validation + snapshot-membership anchoring +
108
+ `maxFindings` budget → `resolveReviewConclusion` → receipt digest
109
+ recomputation. Empty scope completes without a model call and is labeled
110
+ `empty_scope_no_changes`; cancellation, model errors and unparsable output
111
+ are typed failures, never green passes.
112
+ - `src/services/code-review/format.ts` — the shared TUI formatter: scope and
113
+ resolved target header, findings grouped P0→P3 with side:line locations,
114
+ invalid-finding counts, coverage / skips / budget exhaustion footer and a
115
+ receipt digest line; partial / failed / cancelled banners never render as a
116
+ clean pass.
117
+ - `/review` command wiring (`src/commands/workflow-commands.ts`,
118
+ `workflow-command-handlers.ts`): the command is now a read-only builtin
119
+ that runs the typed workflow; unrecognized arguments return usage, a
120
+ missing model returns an explicit error, and no path falls back to ordinary
121
+ chat.
122
+
123
+ ### Changed
124
+
125
+ - `src/services/code-review/snapshot.ts` exports `reviewUnifiedDiffArgs` so
126
+ the runner reuses the exact frozen diff arguments instead of re-deriving
127
+ OIDs after admission; no frozen semantics changed.
128
+
129
+ ### Not run
130
+
131
+ - Real-PTY CLI verification, Web E2E (no Web changes in this slice), and the
132
+ paid human-annotated review-quality benchmark remain `not_run`, matching
133
+ the v0.3.27 plan's PR3/PR4 sequencing.
134
+
135
+ ## [0.3.27] — 2026-10-22
136
+
137
+ > **Status: published, 2026-10-22.** Tagged `v0.3.27` (`0be5b18`), merged via
138
+ > #283, and visible on npm as registry `latest`. First slice of the
139
+ > professional code review loop
28
140
  > (plan: `docs/plan/v0.3.27-plan.md`): the shared review contract (selectors,
29
141
  > states, conclusions, findings, tighten-only budgets, receipt digests,
30
142
  > stale-applicability) is frozen in `src/services/code-review` and bound by
@@ -34,7 +146,7 @@ which is **not** a pass.
34
146
  > workflow constraints deny every non-read tool by default with a dispatch-level
35
147
  > guard whose digest binds receipts. Runtime / CLI wiring (PR2), the Web loop
36
148
  > (PR3) and the qualification benchmark (PR4) are subsequent slices of the same
37
- > plan and are not part of this release. Not merged, tagged or published.
149
+ > plan and are not part of this release; PR2's core CLI slice ships in 0.3.28.
38
150
 
39
151
  ### Added
40
152
 
package/README.md CHANGED
@@ -2,14 +2,13 @@
2
2
 
3
3
  Local-first, goal-driven coding agent for the terminal and browser.
4
4
 
5
- > v0.3.27 candidate — open. First slice of the professional code review loop: the
6
- > shared review contract (selectors, states, conclusions, findings, tighten-only
7
- > budgets, receipt digests, stale-applicability) is frozen and contract-tested,
8
- > the shared Git snapshot reader captures worktree and frozen-base scopes with
9
- > typed errors, and the read-only workflow constraints deny every non-read tool
10
- > by default. Runtime/CLI wiring, the Web loop and the qualification benchmark
11
- > are subsequent slices of the same plan. The previous release 0.3.26 is on npm
12
- > (registry `latest`), tagged `v0.3.26` (`b810996`, #278) and released on GitHub.
5
+ > v0.3.29 candidate — open. The Web shared review loop: the Host starts the same
6
+ > bounded `/review` runner the CLI uses, the Review panel lists digest-verifiable
7
+ > receipts with honest state banners (running / partial / failed / cancelled /
8
+ > stale never green), findings are grouped P0→P3 and anchor to the existing diff
9
+ > view, and each finding can be sent back to the Composer as a typed draft. The
10
+ > previous release 0.3.28 is on npm (registry `latest`), tagged `v0.3.28`
11
+ > (`8a4722b`, #284) and released on GitHub.
13
12
 
14
13
  [中文说明](README.zh-CN.md) ·
15
14
  [v0.3.24 plan](docs/plan/v0.3.24-plan.md) ·
@@ -172,10 +171,10 @@ user extension boundaries.
172
171
  Node.js 22.12+, 24, and 26 are supported. Use Node 24 LTS for production or Node 26 Current for
173
172
  current development environments. Node 20 is upstream EOL and is no longer a v0.3 runtime.
174
173
 
175
- To install the pinned v0.3.27 package when it is available on npm:
174
+ To install the pinned v0.3.29 package when it is available on npm:
176
175
 
177
176
  ```bash
178
- npm install -g @orion-agents/orion-code@0.3.27
177
+ npm install -g @orion-agents/orion-code@0.3.29
179
178
  orion --version
180
179
  orion doctor
181
180
  ```
package/README.zh-CN.md CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  面向终端与浏览器、本地优先的目标驱动 Coding Agent。
4
4
 
5
- > v0.3.27 候选版本:进行中。专业代码审查闭环首切片:共享审查契约(selector、状态、结论、
6
- > finding、只收紧预算、receipt digest、stale 标注)已冻结并通过契约测试;共享 Git snapshot
7
- > reader 捕获 worktree 与冻结 base 两种范围并给出类型化错误;只读 workflow 约束默认拒绝一切
8
- > 非读取工具。Runtime/CLI 接线、Web 闭环与资格验证为同一计划的后续切片。上一版 0.3.26 已发布
9
- > npm(registry `latest`)、打 tag `v0.3.26`(`b810996`,#278)并发布 GitHub Release。
5
+ > v0.3.29 候选版本:进行中。Web 共享审查闭环:Host 复用 CLI 同一有界审查运行器发起
6
+ > 审查;审阅面板列出 digest 可验证的 receipt 与如实状态横幅(running / partial /
7
+ > failed / cancelled / 过期永远不会显示为绿色);finding 按 P0→P3 分组并可定位到既有
8
+ > diff 视图;每个 finding 可作为类型化草稿送回对话。上一版 0.3.28 已发布 npm
9
+ > (registry `latest`)、打 tag `v0.3.28`(`8a4722b`,#284)并发布 GitHub Release。
10
10
 
11
11
  [English](README.md) ·
12
12
  [v0.3.24 方案](docs/plan/v0.3.24-plan.md) ·
@@ -101,10 +101,10 @@ MCP 仍是用户可见的扩展边界。
101
101
  支持 Node.js 22.12+、24 和 26。生产环境建议使用 Node 24 LTS,当前开发环境也支持 Node 26
102
102
  Current。Node 20 已结束上游维护,不再属于 v0.3 Runtime 合同。
103
103
 
104
- v0.3.27 在 npm 可用后,可安装固定版本:
104
+ v0.3.29 在 npm 可用后,可安装固定版本:
105
105
 
106
106
  ```bash
107
- npm install -g @orion-agents/orion-code@0.3.27
107
+ npm install -g @orion-agents/orion-code@0.3.29
108
108
  orion --version
109
109
  orion doctor
110
110
  ```
@@ -4,5 +4,13 @@ declare function handlePlan(ctx: CommandContext, args: string): Promise<CommandR
4
4
  declare function handleDiff(ctx: CommandContext, args: string): CommandResult;
5
5
  declare function handleCommitPlan(ctx: CommandContext, args: string): CommandResult;
6
6
  declare function continueAsSlashChat(name: string, args: string): CommandResult;
7
- export { handlePlan, handleDiff, handleCommitPlan, continueAsSlashChat };
7
+ /**
8
+ * v0.3.28 — the typed `/review` workflow (docs/plan/v0.3.28-plan.md S4).
9
+ * Arguments are parsed into a frozen selector; unrecognized input returns the
10
+ * usage text instead of silently continuing as an ordinary chat turn. The
11
+ * run goes through the bounded single-pass review runner against the frozen
12
+ * Git snapshot, and the receipt is rendered by the shared formatter.
13
+ */
14
+ declare function handleReview(ctx: CommandContext, args: string): Promise<CommandResult>;
15
+ export { handlePlan, handleDiff, handleCommitPlan, continueAsSlashChat, handleReview };
8
16
  //# sourceMappingURL=workflow-command-handlers.d.ts.map
@@ -5,9 +5,13 @@ exports.handlePlan = handlePlan;
5
5
  exports.handleDiff = handleDiff;
6
6
  exports.handleCommitPlan = handleCommitPlan;
7
7
  exports.continueAsSlashChat = continueAsSlashChat;
8
+ exports.handleReview = handleReview;
8
9
  const workspace_diff_1 = require("../services/workspace-diff");
9
10
  const commit_plan_1 = require("../services/commit-plan");
10
11
  const agent_mode_1 = require("../framework/agent-mode");
12
+ const selector_1 = require("../services/code-review/selector");
13
+ const runner_1 = require("../services/code-review/runner");
14
+ const format_1 = require("../services/code-review/format");
11
15
  async function handlePlan(ctx, args) {
12
16
  const task = args.trim();
13
17
  const [subcommand = '', ...tail] = task.split(/\s+/);
@@ -92,4 +96,66 @@ function continueAsSlashChat(name, args) {
92
96
  chatInput: `/${name}${trimmed ? ` ${trimmed}` : ''}`,
93
97
  };
94
98
  }
99
+ /**
100
+ * v0.3.28 — the typed `/review` workflow (docs/plan/v0.3.28-plan.md S4).
101
+ * Arguments are parsed into a frozen selector; unrecognized input returns the
102
+ * usage text instead of silently continuing as an ordinary chat turn. The
103
+ * run goes through the bounded single-pass review runner against the frozen
104
+ * Git snapshot, and the receipt is rendered by the shared formatter.
105
+ */
106
+ async function handleReview(ctx, args) {
107
+ const parsed = (0, selector_1.parseReviewSelector)(args);
108
+ if (!parsed.ok)
109
+ return { success: false, error: parsed.usage };
110
+ if (!ctx.llm) {
111
+ return {
112
+ success: false,
113
+ error: 'Code review needs a configured model. Run /model first, then retry /review.',
114
+ };
115
+ }
116
+ const llm = ctx.llm;
117
+ const outcome = await (0, runner_1.runCodeReview)({
118
+ cwd: ctx.cwd,
119
+ selector: parsed.selector,
120
+ adapter: {
121
+ async complete(messages) {
122
+ const response = await llm.chat(messages.map(message => ({ role: message.role, content: message.content })));
123
+ return {
124
+ content: response.content,
125
+ model: response.model,
126
+ usage: {
127
+ inputTokens: response.usage?.promptTokens ?? 0,
128
+ outputTokens: response.usage?.completionTokens ?? 0,
129
+ },
130
+ };
131
+ },
132
+ },
133
+ identity: {
134
+ workspaceIdentity: ctx.cwd,
135
+ sessionId: ctx.sessionId ?? 'pending-session',
136
+ threadId: ctx.sessionId ?? 'pending-session',
137
+ turnId: String(ctx.turnId ?? 'ad-hoc'),
138
+ },
139
+ ...(ctx.abortSignal ? { abortSignal: ctx.abortSignal } : {}),
140
+ });
141
+ if (!outcome.ok) {
142
+ const failure = outcome.failure;
143
+ if (failure.kind === 'cancelled')
144
+ return { success: false, error: 'Review cancelled.' };
145
+ if (failure.kind === 'budget') {
146
+ return { success: false, error: `Review budget rejected: ${failure.field}` };
147
+ }
148
+ if (failure.kind === 'snapshot') {
149
+ return {
150
+ success: false,
151
+ error: `Review scope error (${failure.code}): ${failure.message}`,
152
+ };
153
+ }
154
+ if (failure.kind === 'model_error') {
155
+ return { success: false, error: `Review model call failed: ${failure.message}` };
156
+ }
157
+ return { success: false, error: `Review output could not be parsed: ${failure.message}` };
158
+ }
159
+ return { success: true, output: (0, format_1.formatReviewReport)(outcome.result) };
160
+ }
95
161
  //# sourceMappingURL=workflow-command-handlers.js.map
@@ -54,14 +54,14 @@ exports.WORKFLOW_COMMANDS = [
54
54
  },
55
55
  {
56
56
  name: 'review',
57
- description: 'Review the current change or requested files',
58
- argumentHint: '[scope]',
57
+ description: 'Run a bounded read-only code review of the current change or a base comparison',
58
+ argumentHint: '[all | --base <ref>] [--path <path>]',
59
59
  category: 'workflow',
60
60
  priority: 10,
61
- type: 'chat',
62
- execution: 'agent-workflow',
61
+ type: 'builtin',
62
+ execution: 'builtin',
63
63
  risk: 'read-only',
64
- execute: (_ctx, args) => (0, workflow_command_handlers_1.continueAsSlashChat)('review', args),
64
+ execute: (ctx, args) => (0, workflow_command_handlers_1.handleReview)(ctx, args),
65
65
  },
66
66
  {
67
67
  name: 'research',
@@ -0,0 +1,12 @@
1
+ /**
2
+ * v0.3.28 — TUI rendering of a code-review receipt (docs/plan/v0.3.28-plan.md
3
+ * S3). The formatter is deliberately honest about state: a partial, failed,
4
+ * cancelled or inconclusive run never renders as a green "no findings" pass,
5
+ * and an empty scope is reported as "no changes under review", distinct from a
6
+ * completed review that found nothing (v0.3.27 plan §4.1).
7
+ */
8
+ import type { CodeReviewResultV1 } from './contract';
9
+ /** Renders the full report shown after `/review` finishes. `fileLabels` maps
10
+ * snapshot fileKeys to human paths when the caller still holds the manifest. */
11
+ export declare function formatReviewReport(result: CodeReviewResultV1, fileLabels?: ReadonlyMap<string, string>): string;
12
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatReviewReport = formatReviewReport;
4
+ const PRIORITY_ORDER = ['P0', 'P1', 'P2', 'P3'];
5
+ const STATE_BANNERS = {
6
+ queued: 'Review queued.',
7
+ running: 'Review running.',
8
+ completed: 'Review completed.',
9
+ partial: 'Review PARTIAL — coverage was incomplete; findings below are valid but not exhaustive.',
10
+ failed: 'Review FAILED — no conclusions can be drawn from this run.',
11
+ cancelled: 'Review CANCELLED — no conclusions can be drawn from this run.',
12
+ };
13
+ function formatScope(result) {
14
+ const selector = result.requestedSelector;
15
+ if (selector.kind === 'base') {
16
+ const paths = selector.paths?.length ? ` paths: ${selector.paths.join(', ')}` : '';
17
+ return `base ${selector.ref} (${result.resolvedTarget.baseOid?.slice(0, 12) ?? '?'}..${result.resolvedTarget.headOid?.slice(0, 12) ?? '?'})${paths}`;
18
+ }
19
+ const paths = selector.paths?.length ? ` paths: ${selector.paths.join(', ')}` : '';
20
+ return `worktree (snapshot ${result.resolvedTarget.snapshotId})${paths}`;
21
+ }
22
+ /** Renders the full report shown after `/review` finishes. `fileLabels` maps
23
+ * snapshot fileKeys to human paths when the caller still holds the manifest. */
24
+ function formatReviewReport(result, fileLabels) {
25
+ const lines = [];
26
+ lines.push(`Code review ${result.reviewId} — ${formatScope(result)}`);
27
+ lines.push(`Model: ${result.model.provider}/${result.model.model} · input snapshot ${result.inputSnapshotDigest.slice(0, 12)}`);
28
+ const emptyScope = result.limits.includes('empty_scope_no_changes');
29
+ if (emptyScope) {
30
+ lines.push('');
31
+ lines.push('No changes under the selected scope — nothing to review.');
32
+ return lines.join('\n');
33
+ }
34
+ lines.push('');
35
+ lines.push(STATE_BANNERS[result.state]);
36
+ if (result.findings.length > 0) {
37
+ lines.push('');
38
+ lines.push(`Findings (${result.findings.length}):`);
39
+ for (const priority of PRIORITY_ORDER) {
40
+ const group = result.findings.filter(finding => finding.priority === priority);
41
+ if (group.length === 0)
42
+ continue;
43
+ for (const finding of group) {
44
+ lines.push('');
45
+ lines.push(`[${priority}] ${finding.title}`);
46
+ lines.push(` Location: ${fileLabels?.get(finding.fileKey) ?? finding.fileKey.slice(0, 12)} ${finding.side}:${finding.startLine}-${finding.endLine}`);
47
+ lines.push(` Trigger: ${finding.trigger}`);
48
+ lines.push(` Impact: ${finding.impact}`);
49
+ lines.push(` Evidence: ${finding.evidence}`);
50
+ }
51
+ }
52
+ }
53
+ else if (result.state === 'completed' && result.conclusion === 'no_findings') {
54
+ lines.push('No findings within the reviewed scope.');
55
+ }
56
+ if (result.invalidFindingCount > 0) {
57
+ lines.push('');
58
+ lines.push(`${result.invalidFindingCount} finding(s) from the model were invalid or outside the frozen snapshot and are not shown.`);
59
+ }
60
+ lines.push('');
61
+ const coverage = result.coverage;
62
+ lines.push(`Coverage: ${coverage.inspectedFiles.length} file(s) inspected, ${coverage.skipped.length} skipped${coverage.truncated ? ', output truncated' : ''}`);
63
+ for (const skip of coverage.skipped) {
64
+ lines.push(` skipped: ${skip.fileKey} (${skip.reason})`);
65
+ }
66
+ if (coverage.budgetExhausted.length > 0) {
67
+ lines.push(`Budget exhausted: ${coverage.budgetExhausted.join(', ')}`);
68
+ }
69
+ for (const limit of result.limits) {
70
+ if (limit !== 'empty_scope_no_changes')
71
+ lines.push(`Limit: ${limit}`);
72
+ }
73
+ if (!result.coverageAssertion.complete && result.state === 'completed') {
74
+ lines.push(`Coverage incomplete: ${result.coverageAssertion.reason ?? 'not all changed files were reviewed'}`);
75
+ }
76
+ lines.push(`Receipt digest: ${result.receiptDigest.slice(0, 16)}`);
77
+ return lines.join('\n');
78
+ }
79
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1,76 @@
1
+ import { DEFAULT_REVIEW_BUDGETS, type CodeReviewResultV1, type ReviewBudgetsV1, type ReviewSelectorV1 } from './contract';
2
+ import { type CodeReviewSnapshotV1, type ReviewGitRunner } from './snapshot';
3
+ /** One bounded model completion. CLI wiring adapts `LLMService.chat`. */
4
+ export interface ReviewModelAdapterV1 {
5
+ complete(messages: readonly {
6
+ readonly role: 'system' | 'user';
7
+ readonly content: string;
8
+ }[]): Promise<{
9
+ readonly content: string;
10
+ readonly model: string;
11
+ readonly usage?: {
12
+ readonly inputTokens: number;
13
+ readonly outputTokens: number;
14
+ };
15
+ }>;
16
+ }
17
+ export interface ReviewRunIdentityV1 {
18
+ readonly workspaceIdentity: string;
19
+ readonly sessionId: string;
20
+ readonly threadId: string;
21
+ readonly turnId: string;
22
+ }
23
+ export interface ReviewRunOptionsV1 {
24
+ readonly cwd: string;
25
+ readonly selector: ReviewSelectorV1;
26
+ readonly adapter: ReviewModelAdapterV1;
27
+ readonly identity: ReviewRunIdentityV1;
28
+ readonly budgets?: Partial<ReviewBudgetsV1>;
29
+ readonly abortSignal?: AbortSignal;
30
+ readonly runGit?: ReviewGitRunner;
31
+ readonly now?: () => number;
32
+ /** v0.3.29 — additive observation hook fired inside the admission window
33
+ * right after the frozen snapshot is captured. Lets a host keep the
34
+ * fileKey -> path mapping for diff anchoring without changing the frozen
35
+ * receipt contract. */
36
+ readonly onSnapshotCaptured?: (snapshot: CodeReviewSnapshotV1) => void;
37
+ }
38
+ export type ReviewRunFailureV1 = {
39
+ readonly kind: 'budget';
40
+ readonly field: string;
41
+ } | {
42
+ readonly kind: 'snapshot';
43
+ readonly code: string;
44
+ readonly message: string;
45
+ } | {
46
+ readonly kind: 'cancelled';
47
+ } | {
48
+ readonly kind: 'model_error';
49
+ readonly message: string;
50
+ } | {
51
+ readonly kind: 'unparsable_output';
52
+ readonly message: string;
53
+ };
54
+ export type ReviewRunOutcomeV1 = {
55
+ readonly ok: true;
56
+ readonly result: CodeReviewResultV1;
57
+ } | {
58
+ readonly ok: false;
59
+ readonly failure: ReviewRunFailureV1;
60
+ };
61
+ /** Production git runner: argument arrays, no shell, read-only profile is the
62
+ * caller's responsibility (the runner only issues read commands). */
63
+ export declare function createProcessGitRunner(cwd: string): ReviewGitRunner;
64
+ /** Rules provenance: AGENTS.md contents from cwd up to the filesystem root
65
+ * (bounded to 16 levels), combined with the frozen read-only constraints
66
+ * digest. Changing the rules or the policy invalidates applicability. */
67
+ export declare function computeReviewRulesDigest(cwd: string): Promise<string>;
68
+ /** The frozen review instruction set assembled for the model. */
69
+ export declare function buildReviewSystemPrompt(rulesDigest: string): string;
70
+ /**
71
+ * Runs one bounded review. Never throws for expected review failures — the
72
+ * outcome is typed; unexpected internal errors surface as `model_error`.
73
+ */
74
+ export declare function runCodeReview(options: ReviewRunOptionsV1): Promise<ReviewRunOutcomeV1>;
75
+ export { DEFAULT_REVIEW_BUDGETS };
76
+ //# sourceMappingURL=runner.d.ts.map