pi-harness-runtime 1.1.407 → 1.1.408
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/index.ts +78 -0
- package/package.json +1 -1
- package/packages/a2a-adapter/package.json +1 -1
- package/packages/agent-policy/package.json +1 -1
- package/packages/architecture-generator/package.json +1 -1
- package/packages/auth/package.json +1 -1
- package/packages/autonomous-refactor/package.json +1 -1
- package/packages/autonomous-runtime/package.json +1 -1
- package/packages/cache-strategy/package.json +1 -1
- package/packages/capability-registry/package.json +1 -1
- package/packages/checkpoint/package.json +1 -1
- package/packages/cli-plugin-sdk/package.json +1 -1
- package/packages/clipboard/package.json +1 -1
- package/packages/clipboard-plugin/package.json +1 -1
- package/packages/code-generation/package.json +1 -1
- package/packages/code-review/package.json +1 -1
- package/packages/codex-adapter/package.json +1 -1
- package/packages/codex-watcher/package.json +1 -1
- package/packages/config-capture/package.json +1 -1
- package/packages/connection-runtime/package.json +1 -1
- package/packages/context-compiler/package.json +1 -1
- package/packages/context-discovery/package.json +1 -1
- package/packages/context-manager/package.json +1 -1
- package/packages/contracts/package.json +1 -1
- package/packages/cookie-sanitizer/package.json +1 -1
- package/packages/cost-optimizer/package.json +1 -1
- package/packages/dependency-analyzer/package.json +1 -1
- package/packages/django-plugin/package.json +1 -1
- package/packages/doc-generator/package.json +1 -1
- package/packages/durable-review/package.json +1 -1
- package/packages/e2e-tester/package.json +1 -1
- package/packages/evaluation-engine/package.json +1 -1
- package/packages/evaluation-runner/package.json +1 -1
- package/packages/event-bus/package.json +1 -1
- package/packages/event-sink/package.json +1 -1
- package/packages/event-store/package.json +1 -1
- package/packages/experience-replay/package.json +1 -1
- package/packages/feedback-collector/package.json +1 -1
- package/packages/file-copy-helper/package.json +1 -1
- package/packages/framework-detector/package.json +1 -1
- package/packages/framework-plugin-sdk/package.json +1 -1
- package/packages/frappe-plugin/package.json +1 -1
- package/packages/generic-web-plugin/package.json +1 -1
- package/packages/health-monitor/package.json +1 -1
- package/packages/intent-analyzer/package.json +1 -1
- package/packages/jev-judge/package.json +1 -1
- package/packages/knowledge-graph/package.json +1 -1
- package/packages/knowledge-retrieval/package.json +1 -1
- package/packages/laravel-plugin/package.json +1 -1
- package/packages/learning-engine/package.json +1 -1
- package/packages/logging/package.json +1 -1
- package/packages/mcp-adapter/package.json +1 -1
- package/packages/memory-engine/package.json +1 -1
- package/packages/milestone-manager/package.json +1 -1
- package/packages/model-registry/package.json +1 -1
- package/packages/nextjs-plugin/package.json +1 -1
- package/packages/notification/package.json +1 -1
- package/packages/observability/package.json +1 -1
- package/packages/okf-indexer/package.json +1 -1
- package/packages/paperclip-integration/package.json +1 -1
- package/packages/performance-optimizer/package.json +1 -1
- package/packages/permission-mode/package.json +1 -1
- package/packages/privilege-broker/package.json +1 -1
- package/packages/project-analyzer/package.json +1 -1
- package/packages/project-bootstrap/package.json +1 -1
- package/packages/projection-engine/package.json +1 -1
- package/packages/prompt-compiler/package.json +1 -1
- package/packages/prompt-versioning/package.json +1 -1
- package/packages/provider-adapter-sdk/package.json +1 -1
- package/packages/provider-router/package.json +1 -1
- package/packages/provider-selector/package.json +1 -1
- package/packages/providers/package.json +1 -1
- package/packages/qdrant-skills/package.json +1 -1
- package/packages/quota-manager/package.json +1 -1
- package/packages/rate-limiter/package.json +1 -1
- package/packages/react-vite-plugin/package.json +1 -1
- package/packages/relay/package.json +1 -1
- package/packages/release-manager/package.json +1 -1
- package/packages/requirement-compiler/package.json +1 -1
- package/packages/runtime/package.json +1 -1
- package/packages/scheduler/package.json +1 -1
- package/packages/scheduler-adapter/package.json +1 -1
- package/packages/session/package.json +1 -1
- package/packages/session-api/package.json +1 -1
- package/packages/session-export/package.json +1 -1
- package/packages/shared-context/package.json +1 -1
- package/packages/skill-mcp-client/package.json +1 -1
- package/packages/skill-registry/package.json +1 -1
- package/packages/skills/package.json +1 -1
- package/packages/sprint-planner/package.json +1 -1
- package/packages/subscription-engine/package.json +1 -1
- package/packages/task-compiler/package.json +1 -1
- package/packages/telegram/package.json +1 -1
- package/packages/tencentdb-memory/package.json +1 -1
- package/packages/tencentdb-sync/package.json +1 -1
- package/packages/test-data-generator/package.json +1 -1
- package/packages/test-generator/package.json +1 -1
- package/packages/todo-bd-sync/package.json +1 -1
- package/packages/token-estimation/package.json +1 -1
- package/packages/token-optimizer/package.json +1 -1
- package/packages/tooling-preference/package.json +1 -1
- package/packages/trajectory/package.json +1 -1
- package/packages/tui/package.json +1 -1
- package/packages/two-phase-review/dist/classify.d.ts +56 -0
- package/packages/two-phase-review/dist/classify.d.ts.map +1 -0
- package/packages/two-phase-review/dist/classify.js +108 -0
- package/packages/two-phase-review/dist/classify.js.map +1 -0
- package/packages/two-phase-review/dist/index.d.ts +20 -0
- package/packages/two-phase-review/dist/index.d.ts.map +1 -0
- package/packages/two-phase-review/dist/index.js +14 -0
- package/packages/two-phase-review/dist/index.js.map +1 -0
- package/packages/two-phase-review/dist/rules.d.ts +81 -0
- package/packages/two-phase-review/dist/rules.d.ts.map +1 -0
- package/packages/two-phase-review/dist/rules.js +195 -0
- package/packages/two-phase-review/dist/rules.js.map +1 -0
- package/packages/two-phase-review/dist/runtime.d.ts +70 -0
- package/packages/two-phase-review/dist/runtime.d.ts.map +1 -0
- package/packages/two-phase-review/dist/runtime.js +298 -0
- package/packages/two-phase-review/dist/runtime.js.map +1 -0
- package/packages/two-phase-review/dist/scope.d.ts +68 -0
- package/packages/two-phase-review/dist/scope.d.ts.map +1 -0
- package/packages/two-phase-review/dist/scope.js +205 -0
- package/packages/two-phase-review/dist/scope.js.map +1 -0
- package/packages/two-phase-review/dist/signals.d.ts +74 -0
- package/packages/two-phase-review/dist/signals.d.ts.map +1 -0
- package/packages/two-phase-review/dist/signals.js +297 -0
- package/packages/two-phase-review/dist/signals.js.map +1 -0
- package/packages/two-phase-review/dist/state.d.ts +72 -0
- package/packages/two-phase-review/dist/state.d.ts.map +1 -0
- package/packages/two-phase-review/dist/state.js +238 -0
- package/packages/two-phase-review/dist/state.js.map +1 -0
- package/packages/two-phase-review/dist/types.d.ts +62 -0
- package/packages/two-phase-review/dist/types.d.ts.map +1 -0
- package/packages/two-phase-review/dist/types.js +9 -0
- package/packages/two-phase-review/dist/types.js.map +1 -0
- package/packages/two-phase-review/package.json +21 -0
- package/packages/two-phase-review/src/classify.ts +129 -0
- package/packages/two-phase-review/src/index.ts +110 -0
- package/packages/two-phase-review/src/rules.ts +236 -0
- package/packages/two-phase-review/src/runtime.ts +392 -0
- package/packages/two-phase-review/src/scope.ts +247 -0
- package/packages/two-phase-review/src/signals.ts +340 -0
- package/packages/two-phase-review/src/state.ts +280 -0
- package/packages/two-phase-review/src/types.ts +72 -0
- package/packages/two-phase-review/test/classify.test.ts +102 -0
- package/packages/two-phase-review/test/helpers.ts +72 -0
- package/packages/two-phase-review/test/rules.test.ts +150 -0
- package/packages/two-phase-review/test/runtime.test.ts +362 -0
- package/packages/two-phase-review/test/scope.test.ts +186 -0
- package/packages/two-phase-review/test/signals.test.ts +183 -0
- package/packages/two-phase-review/test/state.test.ts +201 -0
- package/packages/types/package.json +1 -1
- package/packages/voice-api/package.json +1 -1
- package/packages/webmcp-tester/package.json +1 -1
- package/packages/wiki/package.json +1 -1
- package/packages/workflow-events/package.json +1 -1
- package/packages/workspace-scanner/package.json +1 -1
- package/packages/worktree/dist/worktree.d.ts +31 -0
- package/packages/worktree/dist/worktree.d.ts.map +1 -1
- package/packages/worktree/dist/worktree.js +21 -8
- package/packages/worktree/dist/worktree.js.map +1 -1
- package/packages/worktree/package.json +1 -1
- package/packages/worktree/src/worktree.ts +49 -8
- package/packages/worktree/test/worktree.test.ts +27 -27
- package/packages/write-review/package.json +1 -1
- package/packages/worktree/worktree.ts +0 -293
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The runtime wiring of the two-phase workflow.
|
|
3
|
+
*
|
|
4
|
+
* The wiring lives in the package so it can be tested without a Pi session:
|
|
5
|
+
* the extension API, the todo reader and the workspace are injected. Every
|
|
6
|
+
* decision that the runtime takes is conservative - when the state of the
|
|
7
|
+
* todo list is unknown, the workflow waits instead of guessing.
|
|
8
|
+
*/
|
|
9
|
+
import { implementationTodos, reviewFixTodos, reviewTodos, } from "./classify.js";
|
|
10
|
+
import { detectReviewInvocation, explicitReviewRequest, parseExtraPatterns, } from "./signals.js";
|
|
11
|
+
import { chunkScope, collectScope, currentRevision } from "./scope.js";
|
|
12
|
+
import { TwoPhaseStateStore, allChunksDone, createState, hasQueuedReview, markComplete, recordSignal, startReview, transitionToReviewFixes, transitionToReviewPending, } from "./state.js";
|
|
13
|
+
import { TWO_PHASE_CONTRACT, buildChunkTodoSubject, buildDeferralReason, buildPhaseInstruction, buildPhaseView, buildReviewTodoDescription, buildReviewTodoSubject, formatPhaseStatus, syncChunkStatus, } from "./rules.js";
|
|
14
|
+
/** The marker every message of the harness itself carries. */
|
|
15
|
+
export const HARNESS_MESSAGE_MARKER = "[harness:";
|
|
16
|
+
function errorMessage(error) {
|
|
17
|
+
if (error instanceof Error)
|
|
18
|
+
return error.message;
|
|
19
|
+
return String(error);
|
|
20
|
+
}
|
|
21
|
+
/** The text of a message content (a string or a list of parts). */
|
|
22
|
+
function messageText(content) {
|
|
23
|
+
if (typeof content === "string")
|
|
24
|
+
return content;
|
|
25
|
+
if (Array.isArray(content)) {
|
|
26
|
+
return content
|
|
27
|
+
.map((part) => {
|
|
28
|
+
if (!part || typeof part !== "object")
|
|
29
|
+
return "";
|
|
30
|
+
const entry = part;
|
|
31
|
+
return entry.type === "text" ? (entry.text ?? "") : "";
|
|
32
|
+
})
|
|
33
|
+
.join("\n");
|
|
34
|
+
}
|
|
35
|
+
return "";
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Register the two-phase workflow in the session.
|
|
39
|
+
*
|
|
40
|
+
* The handlers are registered before the function returns, so a session that
|
|
41
|
+
* starts right after the registration is already covered.
|
|
42
|
+
*/
|
|
43
|
+
export async function initTwoPhaseReview(options) {
|
|
44
|
+
const { pi } = options;
|
|
45
|
+
const store = options.store ?? new TwoPhaseStateStore();
|
|
46
|
+
const log = options.log ?? (() => { });
|
|
47
|
+
const workspaceRoot = options.workspaceRoot ?? (() => process.cwd());
|
|
48
|
+
const extraPatterns = options.extraPatterns ?? parseExtraPatterns();
|
|
49
|
+
let state = createState("default");
|
|
50
|
+
/** The last message of the human of this session (never a harness message). */
|
|
51
|
+
let lastUserMessage = "";
|
|
52
|
+
/** The messages the runtime sent itself. */
|
|
53
|
+
const sentMessages = new Set();
|
|
54
|
+
const sessionId = (ctx) => {
|
|
55
|
+
const context = ctx;
|
|
56
|
+
try {
|
|
57
|
+
return context?.sessionManager?.getSessionId?.() ?? "default";
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return "default";
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Persist a state.
|
|
65
|
+
*
|
|
66
|
+
* The state is only replaced when it was written: the file is the source
|
|
67
|
+
* of truth, so a failed write must not change what the runtime believes.
|
|
68
|
+
*/
|
|
69
|
+
const persist = (next) => {
|
|
70
|
+
try {
|
|
71
|
+
state = store.write(next);
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
log(`state not written: ${errorMessage(error)}`);
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
const readTodos = async (ctx) => {
|
|
80
|
+
try {
|
|
81
|
+
const result = await options.readTodos(ctx);
|
|
82
|
+
if (!result || typeof result !== "object") {
|
|
83
|
+
return { available: false, todos: [], reason: "the todo reader returned nothing" };
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
available: result.available !== false,
|
|
87
|
+
todos: Array.isArray(result.todos) ? result.todos : [],
|
|
88
|
+
reason: result.reason,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
return { available: false, todos: [], reason: errorMessage(error) };
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const updateStatus = (ctx) => {
|
|
96
|
+
const context = ctx;
|
|
97
|
+
try {
|
|
98
|
+
context?.ui?.setStatus?.("harness-review", formatPhaseStatus(state));
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
// The status line is a convenience, never a requirement.
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Keep the chunk status and the phase in sync with the todo list.
|
|
106
|
+
*
|
|
107
|
+
* The chunk status only moves forward, so a todo list that is briefly
|
|
108
|
+
* empty can never erase the progress of the review.
|
|
109
|
+
*/
|
|
110
|
+
const syncProgress = (todos) => {
|
|
111
|
+
const synced = syncChunkStatus(state, todos);
|
|
112
|
+
const openFixes = reviewFixTodos(todos).length;
|
|
113
|
+
let next = synced;
|
|
114
|
+
if (next.phase === "review" && allChunksDone(next)) {
|
|
115
|
+
next = openFixes > 0 ? transitionToReviewFixes(next) : markComplete(next);
|
|
116
|
+
}
|
|
117
|
+
else if (next.phase === "review_fixes" && openFixes === 0) {
|
|
118
|
+
next = markComplete(next);
|
|
119
|
+
}
|
|
120
|
+
if (next !== state)
|
|
121
|
+
persist(next);
|
|
122
|
+
};
|
|
123
|
+
pi.on("session_start", (_event, ctx) => {
|
|
124
|
+
const id = sessionId(ctx);
|
|
125
|
+
state = store.read(id) ?? createState(id);
|
|
126
|
+
if (!state.startRevision) {
|
|
127
|
+
const revision = currentRevision(workspaceRoot());
|
|
128
|
+
if (revision)
|
|
129
|
+
state = { ...state, startRevision: revision };
|
|
130
|
+
}
|
|
131
|
+
// The intent of a previous session never carries over.
|
|
132
|
+
lastUserMessage = "";
|
|
133
|
+
persist(state);
|
|
134
|
+
updateStatus(ctx);
|
|
135
|
+
});
|
|
136
|
+
// The intent of the human wins over the phase order.
|
|
137
|
+
pi.on("message_end", (event) => {
|
|
138
|
+
const message = event?.message;
|
|
139
|
+
if (!message || message.role !== "user")
|
|
140
|
+
return;
|
|
141
|
+
const text = messageText(message.content).trim();
|
|
142
|
+
if (!text)
|
|
143
|
+
return;
|
|
144
|
+
// A message of the harness is not the intent of the human.
|
|
145
|
+
if (sentMessages.has(text))
|
|
146
|
+
return;
|
|
147
|
+
if (text.startsWith(HARNESS_MESSAGE_MARKER))
|
|
148
|
+
return;
|
|
149
|
+
lastUserMessage = text;
|
|
150
|
+
});
|
|
151
|
+
// A comprehensive review is deferred while the implementation runs.
|
|
152
|
+
pi.on("tool_call", async (event, ctx) => {
|
|
153
|
+
if (state.phase !== "implementation")
|
|
154
|
+
return {};
|
|
155
|
+
const invocation = detectReviewInvocation(event?.toolName ?? "", event?.input, extraPatterns);
|
|
156
|
+
if (!invocation)
|
|
157
|
+
return {};
|
|
158
|
+
// The human asked for the review explicitly: the phase order does not win.
|
|
159
|
+
if (explicitReviewRequest(lastUserMessage))
|
|
160
|
+
return {};
|
|
161
|
+
const read = await readTodos(ctx);
|
|
162
|
+
if (!read.available) {
|
|
163
|
+
// The implementation state is unknown, so the review waits.
|
|
164
|
+
return {
|
|
165
|
+
block: true,
|
|
166
|
+
reason: `The todo list of the session is not readable (${read.reason ?? "unknown reason"}), so the workflow cannot prove that the implementation is done. The comprehensive review is deferred.`,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
const openImplementation = implementationTodos(read.todos).length;
|
|
170
|
+
if (openImplementation === 0)
|
|
171
|
+
return {};
|
|
172
|
+
const next = recordSignal(state, {
|
|
173
|
+
source: invocation.source,
|
|
174
|
+
files: invocation.files,
|
|
175
|
+
reason: invocation.reason,
|
|
176
|
+
at: new Date().toISOString(),
|
|
177
|
+
});
|
|
178
|
+
if (next !== state) {
|
|
179
|
+
if (!persist(next)) {
|
|
180
|
+
// The signal is not persisted, so it is not queued either.
|
|
181
|
+
return {
|
|
182
|
+
block: true,
|
|
183
|
+
reason: buildDeferralReason(state, {
|
|
184
|
+
source: invocation.source,
|
|
185
|
+
implementationOpen: openImplementation,
|
|
186
|
+
}),
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
// The queued item is part of the session, so a compaction cannot lose it.
|
|
190
|
+
try {
|
|
191
|
+
pi.appendEntry?.("harness-two-phase-review", {
|
|
192
|
+
queued: {
|
|
193
|
+
source: invocation.source,
|
|
194
|
+
files: invocation.files,
|
|
195
|
+
reason: invocation.reason,
|
|
196
|
+
subject: buildReviewTodoSubject(state),
|
|
197
|
+
description: buildReviewTodoDescription(state),
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
// The session entry is a copy; the state file is the truth.
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
updateStatus(ctx);
|
|
206
|
+
return {
|
|
207
|
+
block: true,
|
|
208
|
+
reason: buildDeferralReason(state, {
|
|
209
|
+
source: invocation.source,
|
|
210
|
+
implementationOpen: openImplementation,
|
|
211
|
+
}),
|
|
212
|
+
};
|
|
213
|
+
});
|
|
214
|
+
// The implementation is done: the review scope is derived from the task diff.
|
|
215
|
+
pi.on("turn_end", async (_event, ctx) => {
|
|
216
|
+
const read = await readTodos(ctx);
|
|
217
|
+
if (!read.available) {
|
|
218
|
+
// The implementation state is unknown, so the phase does not move.
|
|
219
|
+
updateStatus(ctx);
|
|
220
|
+
return undefined;
|
|
221
|
+
}
|
|
222
|
+
if (state.phase === "implementation") {
|
|
223
|
+
if (implementationTodos(read.todos).length > 0) {
|
|
224
|
+
updateStatus(ctx);
|
|
225
|
+
return undefined;
|
|
226
|
+
}
|
|
227
|
+
const queued = hasQueuedReview(state) || reviewTodos(read.todos).length > 0;
|
|
228
|
+
if (!queued) {
|
|
229
|
+
updateStatus(ctx);
|
|
230
|
+
return undefined;
|
|
231
|
+
}
|
|
232
|
+
const scope = collectScope(workspaceRoot(), state.startRevision);
|
|
233
|
+
let next = transitionToReviewPending(state, scope.files);
|
|
234
|
+
next = startReview(next, chunkScope(scope.files));
|
|
235
|
+
if (!persist(next)) {
|
|
236
|
+
// Without a persisted state the review must not start.
|
|
237
|
+
updateStatus(ctx);
|
|
238
|
+
return undefined;
|
|
239
|
+
}
|
|
240
|
+
updateStatus(ctx);
|
|
241
|
+
const lines = [
|
|
242
|
+
"[harness:two-phase] The implementation todos of this request are done. Phase 2 (review) starts now.",
|
|
243
|
+
`Review scope: ${scope.files.length} file(s) (${scope.reason}).`,
|
|
244
|
+
...state.chunks.map((chunk) => `- ${chunk.id}: ${chunk.label}`),
|
|
245
|
+
"Review every chunk in scope (never the whole repository). Record confirmed findings as [REVIEW-FIX] todos grouped by root cause and severity, fix them after the pass, then run one final integration review over the task diff.",
|
|
246
|
+
"Create one [REVIEW] todo per chunk with the chunk id in the subject and complete it when the chunk is reviewed:",
|
|
247
|
+
...state.chunks.map((chunk) => `- ${buildChunkTodoSubject(chunk)}`),
|
|
248
|
+
`Keep exactly one queued review item: ${buildReviewTodoSubject(state)}`,
|
|
249
|
+
];
|
|
250
|
+
const message = lines.join("\n");
|
|
251
|
+
try {
|
|
252
|
+
sentMessages.add(message);
|
|
253
|
+
await pi.sendUserMessage?.(message, { deliverAs: "steer" });
|
|
254
|
+
log(`review started (${scope.files.length} file(s))`);
|
|
255
|
+
}
|
|
256
|
+
catch (error) {
|
|
257
|
+
log(`review steer failed: ${errorMessage(error)}`);
|
|
258
|
+
}
|
|
259
|
+
return undefined;
|
|
260
|
+
}
|
|
261
|
+
// Phase 2: the chunk status and the phase follow the review todos.
|
|
262
|
+
syncProgress(read.todos);
|
|
263
|
+
updateStatus(ctx);
|
|
264
|
+
return undefined;
|
|
265
|
+
});
|
|
266
|
+
// The workflow rules and the current phase reach the agent.
|
|
267
|
+
pi.on("before_agent_start", async (event, ctx) => {
|
|
268
|
+
const read = await readTodos(ctx);
|
|
269
|
+
if (!read.available)
|
|
270
|
+
return undefined;
|
|
271
|
+
syncProgress(read.todos);
|
|
272
|
+
const view = buildPhaseView(state, read.todos);
|
|
273
|
+
// The workflow is only active when it has something to say.
|
|
274
|
+
const active = view.implementationOpen > 0 ||
|
|
275
|
+
view.reviewOpen > 0 ||
|
|
276
|
+
view.reviewFixOpen > 0 ||
|
|
277
|
+
state.signals.length > 0;
|
|
278
|
+
if (!active)
|
|
279
|
+
return undefined;
|
|
280
|
+
// The system prompt is built per run, so the contract belongs to every
|
|
281
|
+
// run of the phase, not only to the first one.
|
|
282
|
+
const parts = [TWO_PHASE_CONTRACT];
|
|
283
|
+
const instruction = buildPhaseInstruction(state, view);
|
|
284
|
+
if (instruction)
|
|
285
|
+
parts.push(instruction);
|
|
286
|
+
return { systemPrompt: `${event?.systemPrompt ?? ""}\n\n${parts.join("\n\n")}` };
|
|
287
|
+
});
|
|
288
|
+
return {
|
|
289
|
+
getState: () => state,
|
|
290
|
+
getPhase: (todos = []) => {
|
|
291
|
+
if (state.phase === "complete" && reviewFixTodos(todos).length > 0) {
|
|
292
|
+
return "review_fixes";
|
|
293
|
+
}
|
|
294
|
+
return state.phase;
|
|
295
|
+
},
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The review scope.
|
|
3
|
+
*
|
|
4
|
+
* The scope of the review is the diff of the task: the changes since the
|
|
5
|
+
* revision the task started at, including the uncommitted ones. It is never
|
|
6
|
+
* the whole repository. A large scope is split into logical chunks so the
|
|
7
|
+
* review can run per module.
|
|
8
|
+
*/
|
|
9
|
+
import type { ReviewChunk } from "./types.js";
|
|
10
|
+
/** Directories that never belong to a review scope. */
|
|
11
|
+
export declare const EXCLUDED_SCOPE_PREFIXES: string[];
|
|
12
|
+
/** Is the path part of a review scope? */
|
|
13
|
+
export declare function isReviewablePath(file: string): boolean;
|
|
14
|
+
/** Is the workspace a Git repository? */
|
|
15
|
+
export declare function isGitRepository(root: string): boolean;
|
|
16
|
+
/** The current revision of the workspace. */
|
|
17
|
+
export declare function currentRevision(root: string): string | null;
|
|
18
|
+
/** Does the revision exist in the repository? */
|
|
19
|
+
export declare function revisionExists(root: string, revision: string): boolean;
|
|
20
|
+
/** The measured size of a scope. */
|
|
21
|
+
export interface ScopeMetrics {
|
|
22
|
+
files: number;
|
|
23
|
+
modules: number;
|
|
24
|
+
changedLines: number;
|
|
25
|
+
}
|
|
26
|
+
/** The scope of the review. */
|
|
27
|
+
export interface ScopeResult {
|
|
28
|
+
files: string[];
|
|
29
|
+
detected: boolean;
|
|
30
|
+
reason: string;
|
|
31
|
+
metrics: ScopeMetrics;
|
|
32
|
+
}
|
|
33
|
+
/** The module a file belongs to (the review chunk it is grouped in). */
|
|
34
|
+
export declare function moduleKey(file: string): string;
|
|
35
|
+
/** Count the modules a scope crosses. */
|
|
36
|
+
export declare function countModules(files: string[]): number;
|
|
37
|
+
/** Parse `git diff --numstat` into the changed line count. */
|
|
38
|
+
export declare function parseNumstat(output: string): number;
|
|
39
|
+
/**
|
|
40
|
+
* Collect the files the review has to cover.
|
|
41
|
+
*
|
|
42
|
+
* The scope is the diff since the start revision (committed and uncommitted)
|
|
43
|
+
* plus the untracked files. A workspace that is not a Git repository has no
|
|
44
|
+
* honest scope, so nothing is reviewed.
|
|
45
|
+
*/
|
|
46
|
+
export declare function collectScope(root: string, startRevision: string | null): ScopeResult;
|
|
47
|
+
/** The default number of files one review chunk covers. */
|
|
48
|
+
export declare const DEFAULT_CHUNK_SIZE = 12;
|
|
49
|
+
/**
|
|
50
|
+
* Split a scope into independent review chunks.
|
|
51
|
+
*
|
|
52
|
+
* The chunks follow the modules of the change, so a reviewer of one chunk
|
|
53
|
+
* does not read the same files as a reviewer of another one.
|
|
54
|
+
*/
|
|
55
|
+
export declare function chunkScope(files: string[], options?: {
|
|
56
|
+
maxFilesPerChunk?: number;
|
|
57
|
+
}): ReviewChunk[];
|
|
58
|
+
/**
|
|
59
|
+
* Is the scope large enough to be split?
|
|
60
|
+
*
|
|
61
|
+
* The threshold is measured, not assumed: a scope counts as large when it
|
|
62
|
+
* crosses many modules or many files.
|
|
63
|
+
*/
|
|
64
|
+
export declare function shouldChunkScope(metrics: ScopeMetrics, thresholds?: {
|
|
65
|
+
maxFiles?: number;
|
|
66
|
+
maxModules?: number;
|
|
67
|
+
}): boolean;
|
|
68
|
+
//# sourceMappingURL=scope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,uDAAuD;AACvD,eAAO,MAAM,uBAAuB,EAAE,MAAM,EAW3C,CAAC;AAEF,0CAA0C;AAC1C,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOtD;AAsBD,yCAAyC;AACzC,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGrD;AAED,6CAA6C;AAC7C,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI3D;AAED,iDAAiD;AACjD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEtE;AAED,oCAAoC;AACpC,MAAM,WAAW,YAAY;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;CACrB;AAED,+BAA+B;AAC/B,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,YAAY,CAAC;CACtB;AAED,wEAAwE;AACxE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAa9C;AAED,yCAAyC;AACzC,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAEpD;AAED,8DAA8D;AAC9D,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAWnD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,WAAW,CAyDpF;AAED,2DAA2D;AAC3D,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC;;;;;GAKG;AACH,wBAAgB,UAAU,CACzB,KAAK,EAAE,MAAM,EAAE,EACf,OAAO,GAAE;IAAE,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAO,GACzC,WAAW,EAAE,CA6Bf;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC/B,OAAO,EAAE,YAAY,EACrB,UAAU,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,GACzD,OAAO,CAIT"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The review scope.
|
|
3
|
+
*
|
|
4
|
+
* The scope of the review is the diff of the task: the changes since the
|
|
5
|
+
* revision the task started at, including the uncommitted ones. It is never
|
|
6
|
+
* the whole repository. A large scope is split into logical chunks so the
|
|
7
|
+
* review can run per module.
|
|
8
|
+
*/
|
|
9
|
+
import { spawnSync } from "node:child_process";
|
|
10
|
+
/** Directories that never belong to a review scope. */
|
|
11
|
+
export const EXCLUDED_SCOPE_PREFIXES = [
|
|
12
|
+
"node_modules",
|
|
13
|
+
"dist",
|
|
14
|
+
"build",
|
|
15
|
+
"out",
|
|
16
|
+
"coverage",
|
|
17
|
+
".next",
|
|
18
|
+
".turbo",
|
|
19
|
+
".cache",
|
|
20
|
+
"vendor",
|
|
21
|
+
"__pycache__",
|
|
22
|
+
];
|
|
23
|
+
/** Is the path part of a review scope? */
|
|
24
|
+
export function isReviewablePath(file) {
|
|
25
|
+
const path = file.trim().replace(/^\.\//, "");
|
|
26
|
+
if (!path)
|
|
27
|
+
return false;
|
|
28
|
+
// An excluded directory is excluded everywhere in the path, not only at
|
|
29
|
+
// its root: "packages/foo/dist/index.js" is generated as well.
|
|
30
|
+
const segments = path.split("/").filter(Boolean);
|
|
31
|
+
return !segments.some((segment) => EXCLUDED_SCOPE_PREFIXES.includes(segment));
|
|
32
|
+
}
|
|
33
|
+
function runGit(root, args) {
|
|
34
|
+
try {
|
|
35
|
+
const result = spawnSync("git", ["-C", root, ...args], {
|
|
36
|
+
encoding: "utf8",
|
|
37
|
+
timeout: 20_000,
|
|
38
|
+
shell: false,
|
|
39
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
40
|
+
});
|
|
41
|
+
if (result.error || result.status !== 0)
|
|
42
|
+
return { ok: false, stdout: "" };
|
|
43
|
+
return { ok: true, stdout: result.stdout ?? "" };
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return { ok: false, stdout: "" };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** Is the workspace a Git repository? */
|
|
50
|
+
export function isGitRepository(root) {
|
|
51
|
+
const result = runGit(root, ["rev-parse", "--is-inside-work-tree"]);
|
|
52
|
+
return result.ok && result.stdout.trim() === "true";
|
|
53
|
+
}
|
|
54
|
+
/** The current revision of the workspace. */
|
|
55
|
+
export function currentRevision(root) {
|
|
56
|
+
const result = runGit(root, ["rev-parse", "HEAD"]);
|
|
57
|
+
const revision = result.stdout.trim();
|
|
58
|
+
return result.ok && revision ? revision : null;
|
|
59
|
+
}
|
|
60
|
+
/** Does the revision exist in the repository? */
|
|
61
|
+
export function revisionExists(root, revision) {
|
|
62
|
+
return runGit(root, ["cat-file", "-e", `${revision}^{commit}`]).ok;
|
|
63
|
+
}
|
|
64
|
+
/** The module a file belongs to (the review chunk it is grouped in). */
|
|
65
|
+
export function moduleKey(file) {
|
|
66
|
+
const parts = file.split("/").filter(Boolean);
|
|
67
|
+
if (parts.length >= 2) {
|
|
68
|
+
const root = parts[0];
|
|
69
|
+
if (root === "packages" || root === "apps" || root === "services") {
|
|
70
|
+
return `${root}/${parts[1]}`;
|
|
71
|
+
}
|
|
72
|
+
if (root === "harness") {
|
|
73
|
+
return parts.length >= 3 ? `harness/${parts[1]}` : "harness";
|
|
74
|
+
}
|
|
75
|
+
return root;
|
|
76
|
+
}
|
|
77
|
+
return "root";
|
|
78
|
+
}
|
|
79
|
+
/** Count the modules a scope crosses. */
|
|
80
|
+
export function countModules(files) {
|
|
81
|
+
return new Set(files.map((file) => moduleKey(file))).size;
|
|
82
|
+
}
|
|
83
|
+
/** Parse `git diff --numstat` into the changed line count. */
|
|
84
|
+
export function parseNumstat(output) {
|
|
85
|
+
let lines = 0;
|
|
86
|
+
for (const row of output.split("\n")) {
|
|
87
|
+
const parts = row.split("\t");
|
|
88
|
+
if (parts.length < 3)
|
|
89
|
+
continue;
|
|
90
|
+
const added = Number.parseInt(parts[0] ?? "", 10);
|
|
91
|
+
const removed = Number.parseInt(parts[1] ?? "", 10);
|
|
92
|
+
if (Number.isFinite(added))
|
|
93
|
+
lines += added;
|
|
94
|
+
if (Number.isFinite(removed))
|
|
95
|
+
lines += removed;
|
|
96
|
+
}
|
|
97
|
+
return lines;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Collect the files the review has to cover.
|
|
101
|
+
*
|
|
102
|
+
* The scope is the diff since the start revision (committed and uncommitted)
|
|
103
|
+
* plus the untracked files. A workspace that is not a Git repository has no
|
|
104
|
+
* honest scope, so nothing is reviewed.
|
|
105
|
+
*/
|
|
106
|
+
export function collectScope(root, startRevision) {
|
|
107
|
+
const empty = {
|
|
108
|
+
files: [],
|
|
109
|
+
detected: false,
|
|
110
|
+
reason: "the workspace is not a Git repository",
|
|
111
|
+
metrics: { files: 0, modules: 0, changedLines: 0 },
|
|
112
|
+
};
|
|
113
|
+
if (!isGitRepository(root))
|
|
114
|
+
return empty;
|
|
115
|
+
let base = startRevision;
|
|
116
|
+
if (base && !revisionExists(root, base)) {
|
|
117
|
+
// A missing baseline would silently reduce the scope to the last
|
|
118
|
+
// commit, so the scope is empty instead of incomplete.
|
|
119
|
+
return {
|
|
120
|
+
...empty,
|
|
121
|
+
reason: `the revision the task started at (${base.slice(0, 7)}) does not exist`,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
const revision = base ?? "HEAD";
|
|
125
|
+
const diff = runGit(root, ["diff", "--name-only", revision]);
|
|
126
|
+
if (!diff.ok) {
|
|
127
|
+
return { ...empty, reason: `the diff against ${revision} could not be read` };
|
|
128
|
+
}
|
|
129
|
+
const files = new Set();
|
|
130
|
+
for (const line of diff.stdout.split("\n")) {
|
|
131
|
+
const file = line.trim();
|
|
132
|
+
if (file)
|
|
133
|
+
files.add(file);
|
|
134
|
+
}
|
|
135
|
+
const untracked = runGit(root, ["ls-files", "--others", "--exclude-standard"]);
|
|
136
|
+
if (!untracked.ok) {
|
|
137
|
+
// Without the untracked files the scope would miss new work.
|
|
138
|
+
return { ...empty, reason: "the untracked files of the workspace could not be read" };
|
|
139
|
+
}
|
|
140
|
+
for (const line of untracked.stdout.split("\n")) {
|
|
141
|
+
const file = line.trim();
|
|
142
|
+
if (file)
|
|
143
|
+
files.add(file);
|
|
144
|
+
}
|
|
145
|
+
const scopeFiles = [...files]
|
|
146
|
+
.filter((file) => isReviewablePath(file))
|
|
147
|
+
.sort((a, b) => a.localeCompare(b));
|
|
148
|
+
const numstat = runGit(root, ["diff", "--numstat", revision]);
|
|
149
|
+
return {
|
|
150
|
+
files: scopeFiles,
|
|
151
|
+
detected: true,
|
|
152
|
+
reason: base ? `the diff since ${base.slice(0, 7)}` : "the diff since HEAD",
|
|
153
|
+
metrics: {
|
|
154
|
+
files: scopeFiles.length,
|
|
155
|
+
modules: countModules(scopeFiles),
|
|
156
|
+
changedLines: numstat.ok ? parseNumstat(numstat.stdout) : 0,
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
/** The default number of files one review chunk covers. */
|
|
161
|
+
export const DEFAULT_CHUNK_SIZE = 12;
|
|
162
|
+
/**
|
|
163
|
+
* Split a scope into independent review chunks.
|
|
164
|
+
*
|
|
165
|
+
* The chunks follow the modules of the change, so a reviewer of one chunk
|
|
166
|
+
* does not read the same files as a reviewer of another one.
|
|
167
|
+
*/
|
|
168
|
+
export function chunkScope(files, options = {}) {
|
|
169
|
+
const maxFiles = Math.max(1, options.maxFilesPerChunk ?? DEFAULT_CHUNK_SIZE);
|
|
170
|
+
const groups = new Map();
|
|
171
|
+
for (const file of files) {
|
|
172
|
+
const key = moduleKey(file);
|
|
173
|
+
const group = groups.get(key) ?? [];
|
|
174
|
+
group.push(file);
|
|
175
|
+
groups.set(key, group);
|
|
176
|
+
}
|
|
177
|
+
const ordered = [...groups.entries()].sort((a, b) => b[1].length - a[1].length || a[0].localeCompare(b[0]));
|
|
178
|
+
const chunks = [];
|
|
179
|
+
let index = 0;
|
|
180
|
+
for (const [key, group] of ordered) {
|
|
181
|
+
for (let start = 0; start < group.length; start += maxFiles) {
|
|
182
|
+
const slice = group.slice(start, start + maxFiles);
|
|
183
|
+
index += 1;
|
|
184
|
+
chunks.push({
|
|
185
|
+
id: `chunk-${index}`,
|
|
186
|
+
label: `${key} (${slice.length} file${slice.length === 1 ? "" : "s"})`,
|
|
187
|
+
files: slice,
|
|
188
|
+
status: "pending",
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return chunks;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Is the scope large enough to be split?
|
|
196
|
+
*
|
|
197
|
+
* The threshold is measured, not assumed: a scope counts as large when it
|
|
198
|
+
* crosses many modules or many files.
|
|
199
|
+
*/
|
|
200
|
+
export function shouldChunkScope(metrics, thresholds = {}) {
|
|
201
|
+
const maxFiles = thresholds.maxFiles ?? 12;
|
|
202
|
+
const maxModules = thresholds.maxModules ?? 3;
|
|
203
|
+
return metrics.files > maxFiles || metrics.modules > maxModules;
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=scope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope.js","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"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"}
|