@magnusekdahl/parallix 1.2.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +190 -185
- package/lib/commands/active.js +502 -579
- package/lib/commands/active.ts +665 -0
- package/lib/commands/checkpoint.js +98 -74
- package/lib/commands/checkpoint.ts +79 -0
- package/lib/commands/config.js +61 -31
- package/lib/commands/config.ts +47 -0
- package/lib/commands/coverage-gate.js +271 -246
- package/lib/commands/coverage-gate.ts +362 -0
- package/lib/commands/diff.js +140 -119
- package/lib/commands/diff.ts +125 -0
- package/lib/commands/draft.js +770 -923
- package/lib/commands/draft.ts +1021 -0
- package/lib/commands/handoff.js +588 -608
- package/lib/commands/handoff.ts +694 -0
- package/lib/commands/integrate.js +1331 -1468
- package/lib/commands/integrate.ts +1688 -0
- package/lib/commands/mission-start.js +279 -237
- package/lib/commands/mission-start.ts +263 -0
- package/lib/commands/rebase.js +606 -582
- package/lib/commands/rebase.ts +635 -0
- package/lib/commands/repair-handoff.js +181 -179
- package/lib/commands/repair-handoff.ts +228 -0
- package/lib/commands/resolve-conflict.js +121 -102
- package/lib/commands/resolve-conflict.ts +112 -0
- package/lib/commands/review.js +3 -4
- package/lib/commands/review.ts +14 -0
- package/lib/commands/setup-review.js +4 -5
- package/lib/commands/setup-review.ts +14 -0
- package/lib/commands/setup.js +3 -3
- package/lib/commands/setup.ts +2 -0
- package/lib/commands/stats-backfill.js +394 -359
- package/lib/commands/stats-backfill.ts +418 -0
- package/lib/commands/stats.js +1424 -1665
- package/lib/commands/stats.ts +2186 -0
- package/lib/commands/status.js +219 -200
- package/lib/commands/status.ts +219 -0
- package/lib/commands/verify.js +3 -1
- package/lib/commands/verify.ts +2 -0
- package/lib/core/nels.js +112 -127
- package/lib/core/nels.ts +189 -0
- package/lib/core/subagent-limit.js +15 -16
- package/lib/core/subagent-limit.ts +25 -0
- package/lib/index.js +142 -59
- package/lib/index.ts +134 -0
- package/lib/review/rebase.js +142 -145
- package/lib/review/rebase.ts +188 -0
- package/lib/review/review-adapter.js +99 -87
- package/lib/review/review-adapter.ts +198 -0
- package/lib/review/review-artifacts.js +486 -629
- package/lib/review/review-artifacts.ts +622 -0
- package/lib/review/review-commands.js +1220 -1373
- package/lib/review/review-commands.ts +1579 -0
- package/lib/review/review-events.js +544 -886
- package/lib/review/review-events.ts +954 -0
- package/lib/review/review-loop.js +945 -1020
- package/lib/review/review-loop.ts +1174 -0
- package/lib/review/review-polling.js +86 -115
- package/lib/review/review-polling.ts +194 -0
- package/lib/review/review-prompts.js +154 -189
- package/lib/review/review-prompts.ts +182 -0
- package/lib/review/review-state.js +246 -225
- package/lib/review/review-state.ts +353 -0
- package/lib/review/review.js +63 -84
- package/lib/review/review.ts +138 -0
- package/lib/tools/backlog.js +694 -680
- package/lib/tools/backlog.ts +835 -0
- package/lib/tools/forgejo.js +1270 -1405
- package/lib/tools/forgejo.ts +1793 -0
- package/lib/tools/gatekeeper.js +106 -96
- package/lib/tools/gatekeeper.ts +124 -0
- package/lib/tools/redgreen.js +200 -181
- package/lib/tools/redgreen.ts +221 -0
- package/lib/tools/sessions.js +58 -52
- package/lib/tools/sessions.ts +81 -0
- package/lib/tools/setup-review.js +902 -975
- package/lib/tools/setup-review.ts +1152 -0
- package/package.json +4 -4
- package/px.js +226 -208
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* Reviewer-family persistence for the autonomous review loop.
|
|
3
4
|
*
|
|
@@ -6,13 +7,52 @@
|
|
|
6
7
|
*
|
|
7
8
|
* Owned by the Node workflow harness (ADR 0037 / task-089).
|
|
8
9
|
*/
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
22
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
23
|
+
}) : function(o, v) {
|
|
24
|
+
o["default"] = v;
|
|
25
|
+
});
|
|
26
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
27
|
+
var ownKeys = function(o) {
|
|
28
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
29
|
+
var ar = [];
|
|
30
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
31
|
+
return ar;
|
|
32
|
+
};
|
|
33
|
+
return ownKeys(o);
|
|
34
|
+
};
|
|
35
|
+
return function (mod) {
|
|
36
|
+
if (mod && mod.__esModule) return mod;
|
|
37
|
+
var result = {};
|
|
38
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
39
|
+
__setModuleDefault(result, mod);
|
|
40
|
+
return result;
|
|
41
|
+
};
|
|
42
|
+
})();
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.ReviewState = exports.VALID_PHASES = void 0;
|
|
45
|
+
exports.reviewStateFile = reviewStateFile;
|
|
46
|
+
exports.readReviewState = readReviewState;
|
|
47
|
+
exports.resolveReviewIdentity = resolveReviewIdentity;
|
|
48
|
+
exports.normalizeReviewPhase = normalizeReviewPhase;
|
|
49
|
+
exports.writeReviewState = writeReviewState;
|
|
50
|
+
exports.resetReviewState = resetReviewState;
|
|
51
|
+
const fs = __importStar(require("fs"));
|
|
52
|
+
const path = __importStar(require("path"));
|
|
53
|
+
const git_js_1 = require("../core/git.js");
|
|
54
|
+
const mission_utils_js_1 = require("../core/mission-utils.js");
|
|
55
|
+
const fmt_js_1 = require("../core/fmt.js");
|
|
16
56
|
/**
|
|
17
57
|
* Return the path to the review-state file for a given slug.
|
|
18
58
|
* Resolves using the same mission-dir discovery as other workflow commands.
|
|
@@ -22,11 +62,12 @@ const fmt = require('../core/fmt');
|
|
|
22
62
|
* @returns {string|null} Absolute path, or null if mission dir not found
|
|
23
63
|
*/
|
|
24
64
|
function reviewStateFile(slug, rootDir = process.cwd()) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
65
|
+
const missionDir = (0, mission_utils_js_1.findMissionDir)(slug, rootDir);
|
|
66
|
+
if (!missionDir) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
return path.join(missionDir, 'review-state.json');
|
|
28
70
|
}
|
|
29
|
-
|
|
30
71
|
/**
|
|
31
72
|
* Read the persisted review state for a mission.
|
|
32
73
|
*
|
|
@@ -35,21 +76,22 @@ function reviewStateFile(slug, rootDir = process.cwd()) {
|
|
|
35
76
|
* @returns {ReviewState|null}
|
|
36
77
|
*/
|
|
37
78
|
function readReviewState(slug, rootDir = process.cwd()) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
79
|
+
const statePath = reviewStateFile(slug, rootDir);
|
|
80
|
+
if (!statePath || !fs.existsSync(statePath)) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const raw = fs.readFileSync(statePath, 'utf8');
|
|
85
|
+
const parsed = JSON.parse(raw);
|
|
86
|
+
if (parsed && parsed.reviewer && parsed.implementer) {
|
|
87
|
+
return new ReviewState(slug, parsed);
|
|
88
|
+
}
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return null;
|
|
46
93
|
}
|
|
47
|
-
return null;
|
|
48
|
-
} catch (_) {
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
94
|
}
|
|
52
|
-
|
|
53
95
|
/**
|
|
54
96
|
* Resolve the review-provider identity for a review workflow path.
|
|
55
97
|
*
|
|
@@ -61,197 +103,188 @@ function readReviewState(slug, rootDir = process.cwd()) {
|
|
|
61
103
|
* @param {{readReviewStateFn?: Function}} [options]
|
|
62
104
|
* @returns {{ identityUser: string|null, commentIdentityUser: string|null, forgejoUser: string|null, commentForgejoUser: string|null, reviewState: ReviewState|null, source: 'review-state'|null }}
|
|
63
105
|
*/
|
|
64
|
-
function resolveReviewIdentity(slug, rootDir = process.cwd(),
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
reviewState,
|
|
78
|
-
source: reviewerUser ? 'review-state' : null
|
|
79
|
-
};
|
|
106
|
+
function resolveReviewIdentity(slug, rootDir = process.cwd(), options = {}) {
|
|
107
|
+
const readReviewStateFn = options.readReviewStateFn || readReviewState;
|
|
108
|
+
const reviewState = readReviewStateFn(slug, rootDir);
|
|
109
|
+
const reviewerUser = reviewState ? (reviewState.reviewer || reviewState.implementer || null) : null;
|
|
110
|
+
const implementerUser = reviewState ? (reviewState.implementer || reviewState.reviewer || null) : null;
|
|
111
|
+
return {
|
|
112
|
+
identityUser: reviewerUser || null,
|
|
113
|
+
commentIdentityUser: implementerUser || null,
|
|
114
|
+
forgejoUser: reviewerUser || null,
|
|
115
|
+
commentForgejoUser: implementerUser || null,
|
|
116
|
+
reviewState,
|
|
117
|
+
source: reviewerUser ? 'review-state' : null
|
|
118
|
+
};
|
|
80
119
|
}
|
|
81
|
-
|
|
82
120
|
/**
|
|
83
121
|
* Manager class for mission review state.
|
|
84
122
|
* Expanded to include phase, disposition, and metadata for canonical state ownership.
|
|
85
123
|
*/
|
|
86
|
-
|
|
124
|
+
exports.VALID_PHASES = ['reviewing', 'fixing', 'pending-approval', 'approved'];
|
|
87
125
|
const PHASE_ALIASES = new Map([
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
126
|
+
['review', 'reviewing'],
|
|
127
|
+
['rewiewing', 'reviewing'],
|
|
128
|
+
['fix', 'fixing'],
|
|
129
|
+
['pending_approval', 'pending-approval'],
|
|
130
|
+
['pending approval', 'pending-approval']
|
|
93
131
|
]);
|
|
94
|
-
|
|
95
132
|
const PHASE_TRANSITIONS = {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
133
|
+
'reviewing': ['fixing', 'approved'],
|
|
134
|
+
'fixing': ['reviewing', 'pending-approval'],
|
|
135
|
+
'pending-approval': ['reviewing'],
|
|
136
|
+
'approved': []
|
|
100
137
|
};
|
|
101
|
-
|
|
102
138
|
/** @param {string} disposition */
|
|
103
139
|
function inferPhaseFromDisposition(disposition) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
140
|
+
switch (String(disposition || '').trim().toUpperCase()) {
|
|
141
|
+
case 'APPROVED':
|
|
142
|
+
return 'approved';
|
|
143
|
+
case 'REQUEST_CHANGES':
|
|
144
|
+
case 'COMMENT':
|
|
145
|
+
case 'PUSHBACK_ALL':
|
|
146
|
+
case 'BLOCKED':
|
|
147
|
+
case 'PARKED':
|
|
148
|
+
return 'fixing';
|
|
149
|
+
case 'CHANGES_MADE':
|
|
150
|
+
return 'reviewing';
|
|
151
|
+
default:
|
|
152
|
+
return 'reviewing';
|
|
153
|
+
}
|
|
118
154
|
}
|
|
119
|
-
|
|
120
155
|
/** @param {string} phase @param {string} disposition */
|
|
121
156
|
function normalizeReviewPhase(phase, disposition) {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
return {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
original: raw,
|
|
140
|
-
normalized: true
|
|
141
|
-
};
|
|
157
|
+
if (!phase) {
|
|
158
|
+
return { phase: 'reviewing', original: null, normalized: false };
|
|
159
|
+
}
|
|
160
|
+
const raw = String(phase).trim();
|
|
161
|
+
const canonical = raw.toLowerCase().replace(/[_\s]+/g, '-');
|
|
162
|
+
if (exports.VALID_PHASES.includes(canonical)) {
|
|
163
|
+
return { phase: canonical, original: raw, normalized: canonical !== raw };
|
|
164
|
+
}
|
|
165
|
+
const alias = PHASE_ALIASES.get(raw.toLowerCase()) || PHASE_ALIASES.get(canonical);
|
|
166
|
+
if (alias) {
|
|
167
|
+
return { phase: alias, original: raw, normalized: true };
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
phase: inferPhaseFromDisposition(disposition),
|
|
171
|
+
original: raw,
|
|
172
|
+
normalized: true
|
|
173
|
+
};
|
|
142
174
|
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* @typedef {{reviewer?: string, implementer?: string, round?: number, startedAt?: string, phase?: string, disposition?: string | null, reviewerRetryCount?: number, implementerRetryCount?: number, metadata?: {[key: string]: any}}} ReviewStateData
|
|
146
|
-
*/
|
|
147
|
-
|
|
148
175
|
class ReviewState {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
178
|
-
return dataOrInstance;
|
|
176
|
+
slug;
|
|
177
|
+
reviewer;
|
|
178
|
+
implementer;
|
|
179
|
+
round;
|
|
180
|
+
startedAt;
|
|
181
|
+
phase;
|
|
182
|
+
disposition;
|
|
183
|
+
reviewerRetryCount;
|
|
184
|
+
implementerRetryCount;
|
|
185
|
+
metadata;
|
|
186
|
+
phaseOriginal;
|
|
187
|
+
/**
|
|
188
|
+
* @param {string} slug
|
|
189
|
+
* @param {ReviewStateData} [data]
|
|
190
|
+
*/
|
|
191
|
+
constructor(slug, data = {}) {
|
|
192
|
+
const phaseInfo = normalizeReviewPhase(data.phase || '', data.disposition || '');
|
|
193
|
+
this.slug = slug;
|
|
194
|
+
this.reviewer = data.reviewer;
|
|
195
|
+
this.implementer = data.implementer;
|
|
196
|
+
this.round = data.round || 1;
|
|
197
|
+
this.startedAt = data.startedAt || new Date().toISOString();
|
|
198
|
+
this.phase = phaseInfo.phase;
|
|
199
|
+
this.disposition = data.disposition || null;
|
|
200
|
+
this.reviewerRetryCount = data.reviewerRetryCount || 0;
|
|
201
|
+
this.implementerRetryCount = data.implementerRetryCount || 0;
|
|
202
|
+
this.metadata = data.metadata || {};
|
|
203
|
+
this.phaseOriginal = phaseInfo.normalized ? phaseInfo.original : null;
|
|
179
204
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
205
|
+
/**
|
|
206
|
+
* @param {string} slug
|
|
207
|
+
* @param {ReviewState|ReviewStateData} dataOrInstance
|
|
208
|
+
* @returns {ReviewState}
|
|
209
|
+
*/
|
|
210
|
+
static from(slug, dataOrInstance) {
|
|
211
|
+
if (dataOrInstance instanceof ReviewState) {
|
|
212
|
+
if (dataOrInstance.slug !== slug) {
|
|
213
|
+
throw new Error(`ReviewState slug mismatch: expected "${slug}", got "${dataOrInstance.slug}"`);
|
|
214
|
+
}
|
|
215
|
+
return dataOrInstance;
|
|
216
|
+
}
|
|
217
|
+
return new ReviewState(slug, dataOrInstance || {});
|
|
190
218
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
219
|
+
/**
|
|
220
|
+
* @param {string} nextPhase
|
|
221
|
+
* @returns {ReviewState}
|
|
222
|
+
*/
|
|
223
|
+
transitionTo(nextPhase) {
|
|
224
|
+
if (!exports.VALID_PHASES.includes(nextPhase)) {
|
|
225
|
+
throw new Error(`Invalid phase: "${nextPhase}". Valid: ${exports.VALID_PHASES.join(', ')}`);
|
|
226
|
+
}
|
|
227
|
+
const allowedArr = PHASE_TRANSITIONS[this.phase];
|
|
228
|
+
if (!allowedArr || !allowedArr.includes(nextPhase)) {
|
|
229
|
+
throw new Error(`Cannot transition from "${this.phase}" to "${nextPhase}". Allowed: ${(allowedArr || []).join(', ') || 'none'}`);
|
|
230
|
+
}
|
|
231
|
+
this.phase = nextPhase;
|
|
232
|
+
return this;
|
|
195
233
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
234
|
+
advanceRound() {
|
|
235
|
+
this.round += 1;
|
|
236
|
+
this.phase = 'reviewing';
|
|
237
|
+
this.disposition = null;
|
|
238
|
+
this.reviewerRetryCount = 0;
|
|
239
|
+
this.implementerRetryCount = 0;
|
|
240
|
+
this.startedAt = new Date().toISOString();
|
|
241
|
+
return this;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* @returns {{reviewer?: string, implementer?: string, round?: number, startedAt?: string, phase?: string, disposition?: string, reviewerRetryCount?: number, implementerRetryCount?: number, metadata?: {[key: string]: unknown}}}
|
|
245
|
+
*/
|
|
246
|
+
toJSON() {
|
|
247
|
+
const payload = {
|
|
248
|
+
reviewer: this.reviewer,
|
|
249
|
+
implementer: this.implementer,
|
|
250
|
+
round: this.round,
|
|
251
|
+
startedAt: this.startedAt,
|
|
252
|
+
phase: this.phase,
|
|
253
|
+
disposition: this.disposition || undefined
|
|
254
|
+
};
|
|
255
|
+
if (this.reviewerRetryCount > 0) {
|
|
256
|
+
payload.reviewerRetryCount = this.reviewerRetryCount;
|
|
257
|
+
}
|
|
258
|
+
if (this.implementerRetryCount > 0) {
|
|
259
|
+
payload.implementerRetryCount = this.implementerRetryCount;
|
|
260
|
+
}
|
|
261
|
+
if (Object.keys(this.metadata || {}).length > 0) {
|
|
262
|
+
payload.metadata = this.metadata;
|
|
263
|
+
}
|
|
264
|
+
return payload;
|
|
265
|
+
}
|
|
266
|
+
save(worktree = (0, mission_utils_js_1.resolveWorktree)(this.slug) || process.cwd(), gitFn = git_js_1.git) {
|
|
267
|
+
const statePath = reviewStateFile(this.slug, worktree);
|
|
268
|
+
if (!statePath) {
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
const payload = this.toJSON();
|
|
272
|
+
fs.writeFileSync(statePath, JSON.stringify(payload, null, 2) + '\n', 'utf8');
|
|
273
|
+
const relPath = path.relative(worktree, statePath);
|
|
274
|
+
const result = gitFn(['-C', worktree, 'add', relPath]);
|
|
275
|
+
const msg = `review-state(${this.slug}): round ${this.round} (${this.phase}) [${this.reviewer} -> ${this.implementer}]${this.disposition ? ` disposition=${this.disposition}` : ''}`;
|
|
276
|
+
const commitResult = gitFn(['-C', worktree, 'commit', '-m', msg]);
|
|
277
|
+
if (commitResult.status !== 0) {
|
|
278
|
+
const statusResult = gitFn(['-C', worktree, 'status', '--porcelain', relPath]);
|
|
279
|
+
if (statusResult.stdout.trim() === '') {
|
|
280
|
+
return true;
|
|
281
|
+
}
|
|
282
|
+
fmt_js_1.log.warn(`Failed to commit review state update: ${commitResult.stderr}`);
|
|
283
|
+
}
|
|
246
284
|
return true;
|
|
247
|
-
}
|
|
248
|
-
fmt.log.warn(`Failed to commit review state update: ${result.stderr}`);
|
|
249
285
|
}
|
|
250
|
-
|
|
251
|
-
return true;
|
|
252
|
-
}
|
|
253
286
|
}
|
|
254
|
-
|
|
287
|
+
exports.ReviewState = ReviewState;
|
|
255
288
|
/**
|
|
256
289
|
* Write and commit the review state for a mission.
|
|
257
290
|
* Commits to the current branch so the state is visible after session restarts.
|
|
@@ -260,11 +293,10 @@ class ReviewState {
|
|
|
260
293
|
* @param {ReviewState|object} state
|
|
261
294
|
* @returns {boolean} true if written successfully
|
|
262
295
|
*/
|
|
263
|
-
function writeReviewState(slug, state, worktree = resolveWorktree(slug) || process.cwd(), gitFn = git) {
|
|
264
|
-
|
|
265
|
-
|
|
296
|
+
function writeReviewState(slug, state, worktree = (0, mission_utils_js_1.resolveWorktree)(slug) || process.cwd(), gitFn = git_js_1.git) {
|
|
297
|
+
const instance = state instanceof ReviewState ? state : new ReviewState(slug, state);
|
|
298
|
+
return instance.save(worktree, gitFn);
|
|
266
299
|
}
|
|
267
|
-
|
|
268
300
|
/**
|
|
269
301
|
* Delete the review state file for a mission (used by --reset).
|
|
270
302
|
* Commits the deletion if the file was tracked.
|
|
@@ -272,33 +304,22 @@ function writeReviewState(slug, state, worktree = resolveWorktree(slug) || proce
|
|
|
272
304
|
* @param {string} slug
|
|
273
305
|
* @returns {boolean} true if a file was deleted
|
|
274
306
|
*/
|
|
275
|
-
function resetReviewState(slug, worktree = resolveWorktree(slug) || process.cwd(), gitFn = git) {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
307
|
+
function resetReviewState(slug, worktree = (0, mission_utils_js_1.resolveWorktree)(slug) || process.cwd(), gitFn = git_js_1.git) {
|
|
308
|
+
const statePath = reviewStateFile(slug, worktree);
|
|
309
|
+
if (!statePath || !fs.existsSync(statePath)) {
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
fs.unlinkSync(statePath);
|
|
313
|
+
const relPath = path.relative(worktree, statePath);
|
|
314
|
+
try {
|
|
315
|
+
gitFn(['-C', worktree, 'rm', '--cached', relPath]);
|
|
316
|
+
const result = gitFn(['-C', worktree, 'commit', '-m', `review-state(${slug}): reset (--reset flag)`]);
|
|
317
|
+
if (result.status !== 0) {
|
|
318
|
+
fmt_js_1.log.warn(`Failed to commit review state reset: ${result.stderr}`);
|
|
319
|
+
}
|
|
287
320
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
return true;
|
|
321
|
+
catch {
|
|
322
|
+
// file may not have been tracked yet
|
|
323
|
+
}
|
|
324
|
+
return true;
|
|
293
325
|
}
|
|
294
|
-
|
|
295
|
-
module.exports = {
|
|
296
|
-
ReviewState,
|
|
297
|
-
VALID_PHASES,
|
|
298
|
-
normalizeReviewPhase,
|
|
299
|
-
reviewStateFile,
|
|
300
|
-
readReviewState,
|
|
301
|
-
resolveReviewIdentity,
|
|
302
|
-
writeReviewState,
|
|
303
|
-
resetReviewState
|
|
304
|
-
};
|