@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.
- package/CHANGELOG.md +115 -3
- package/README.md +9 -10
- package/README.zh-CN.md +7 -7
- package/dist/commands/workflow-command-handlers.d.ts +9 -1
- package/dist/commands/workflow-command-handlers.js +66 -0
- package/dist/commands/workflow-commands.js +5 -5
- package/dist/services/code-review/format.d.ts +12 -0
- package/dist/services/code-review/format.js +79 -0
- package/dist/services/code-review/runner.d.ts +76 -0
- package/dist/services/code-review/runner.js +368 -0
- package/dist/services/code-review/selector.d.ts +24 -0
- package/dist/services/code-review/selector.js +86 -0
- package/dist/services/code-review/snapshot.d.ts +7 -0
- package/dist/services/code-review/snapshot.js +11 -2
- package/dist/web/code-review-run-service.d.ts +68 -0
- package/dist/web/code-review-run-service.js +228 -0
- package/dist/web/server.js +37 -0
- package/dist/web/workbench-controller.d.ts +16 -0
- package/dist/web/workbench-controller.js +61 -0
- package/dist/web-client/assets/{FilesPanel-CdoCa8u0.js → FilesPanel-iBYj9ZRf.js} +1 -1
- package/dist/web-client/assets/{GitPanel-CRr_iIDz.js → GitPanel-D33R_bZr.js} +1 -1
- package/dist/web-client/assets/ReviewPanel-C_0upsDk.js +6 -0
- package/dist/web-client/assets/{TerminalPanel-BniCjatZ.js → TerminalPanel-C7A8dMNf.js} +1 -1
- package/dist/web-client/assets/{index-DCYKIeOj.css → index-BaOxrwGB.css} +1 -1
- package/dist/web-client/assets/{index-kQqA3li6.js → index-CqCgJ2ov.js} +13 -13
- package/dist/web-client/assets/{useAutoNotice-DPXFWIwK.js → useAutoNotice-C1qM-_Sg.js} +1 -1
- package/dist/web-client/index.html +2 -2
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- 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.
|
|
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
|
-
|
|
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
|
|
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.
|
|
6
|
-
>
|
|
7
|
-
>
|
|
8
|
-
>
|
|
9
|
-
>
|
|
10
|
-
>
|
|
11
|
-
>
|
|
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.
|
|
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.
|
|
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.
|
|
6
|
-
>
|
|
7
|
-
>
|
|
8
|
-
>
|
|
9
|
-
>
|
|
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.
|
|
104
|
+
v0.3.29 在 npm 可用后,可安装固定版本:
|
|
105
105
|
|
|
106
106
|
```bash
|
|
107
|
-
npm install -g @orion-agents/orion-code@0.3.
|
|
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
|
-
|
|
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: '
|
|
58
|
-
argumentHint: '[
|
|
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: '
|
|
62
|
-
execution: '
|
|
61
|
+
type: 'builtin',
|
|
62
|
+
execution: 'builtin',
|
|
63
63
|
risk: 'read-only',
|
|
64
|
-
execute: (
|
|
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
|