@open-tomato/rafa 0.40.0 → 0.41.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/README.md +1 -1
- package/dist/cli.js +2760 -1506
- package/dist/continue-criteria.md +31 -0
- package/dist/continue-decision-prompt.md +94 -0
- package/dist/effort/store/index.js +2 -2
- package/dist/{index-334y39tn.js → index-3jpz9nr3.js} +63 -8
- package/dist/{index-8veaj0t9.js → index-cd0wzc12.js} +76 -6
- package/dist/{index-j7kjj0dd.js → index-snf04fpt.js} +256 -530
- package/dist/{index-zcbj07aq.js → index-wjsarzf5.js} +2090 -725
- package/dist/{index-krpmxpkh.js → index-zg0qsb5b.js} +29 -14
- package/dist/index.js +4 -4
- package/dist/plan/index.js +2 -2
- package/package.json +2 -2
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
NO_NEXT_STEP,
|
|
40
40
|
NoSessionRefusal,
|
|
41
41
|
ORIGIN_FIELD,
|
|
42
|
+
PLACEHOLDER_REASON,
|
|
42
43
|
PREVIOUS_COPY_WARN_ABOVE,
|
|
43
44
|
PROJECT_SCOPE_FIX,
|
|
44
45
|
PROVENANCE_FIELD,
|
|
@@ -93,6 +94,7 @@ import {
|
|
|
93
94
|
branchName,
|
|
94
95
|
buildReport,
|
|
95
96
|
buildSettle,
|
|
97
|
+
buildVerifyPrompt,
|
|
96
98
|
bundledAgentsDirectory,
|
|
97
99
|
byName,
|
|
98
100
|
cancelMoveReason,
|
|
@@ -134,6 +136,7 @@ import {
|
|
|
134
136
|
createPlanDirNames,
|
|
135
137
|
createPlanRefsVerifier,
|
|
136
138
|
createStartPreflightClaim,
|
|
139
|
+
criteriaToAsk,
|
|
137
140
|
crossRepositoryRefusal,
|
|
138
141
|
defaultCleanupSeams,
|
|
139
142
|
developmentApplied,
|
|
@@ -150,9 +153,10 @@ import {
|
|
|
150
153
|
epicTickSentence,
|
|
151
154
|
estimateEta,
|
|
152
155
|
etaLine,
|
|
153
|
-
|
|
156
|
+
eventsFileOf,
|
|
154
157
|
expectTwoArguments,
|
|
155
158
|
failingRows,
|
|
159
|
+
fenceFor,
|
|
156
160
|
fetchClaimBranches,
|
|
157
161
|
findReadinessGaps,
|
|
158
162
|
fingerprintText,
|
|
@@ -235,6 +239,7 @@ import {
|
|
|
235
239
|
parseRoadmapBody,
|
|
236
240
|
parseSemanticVersion,
|
|
237
241
|
parseTreePaths,
|
|
242
|
+
parseVerifyPlan,
|
|
238
243
|
parseWorkingTree,
|
|
239
244
|
parseWorktrees,
|
|
240
245
|
pathDirectories,
|
|
@@ -273,6 +278,7 @@ import {
|
|
|
273
278
|
readEpicDependents,
|
|
274
279
|
readEpicProblems,
|
|
275
280
|
readEpics,
|
|
281
|
+
readEventsFrom,
|
|
276
282
|
readGuard,
|
|
277
283
|
readHomeAfterLoop,
|
|
278
284
|
readIssueFacts,
|
|
@@ -303,6 +309,7 @@ import {
|
|
|
303
309
|
readTextFlag,
|
|
304
310
|
readTrees,
|
|
305
311
|
readTrendInputs,
|
|
312
|
+
readVerifyPrompt,
|
|
306
313
|
readWaiting,
|
|
307
314
|
ready_default,
|
|
308
315
|
receiptProblem,
|
|
@@ -320,6 +327,7 @@ import {
|
|
|
320
327
|
renderDependentComment,
|
|
321
328
|
renderDoctorEffortSync,
|
|
322
329
|
renderDoctorRefs,
|
|
330
|
+
renderEpicBody,
|
|
323
331
|
renderHorizonComment,
|
|
324
332
|
renderMoveComment,
|
|
325
333
|
renderParkedPullRequestComment,
|
|
@@ -367,6 +375,7 @@ import {
|
|
|
367
375
|
skillItem,
|
|
368
376
|
skippedFieldWarning,
|
|
369
377
|
sourceItem,
|
|
378
|
+
splitCriteria,
|
|
370
379
|
stackPaths,
|
|
371
380
|
stacksFromEccSkillName,
|
|
372
381
|
stageOf,
|
|
@@ -400,7 +409,7 @@ import {
|
|
|
400
409
|
worktreesHolding,
|
|
401
410
|
writeSession,
|
|
402
411
|
writeShippedFile
|
|
403
|
-
} from "./index-
|
|
412
|
+
} from "./index-wjsarzf5.js";
|
|
404
413
|
import {
|
|
405
414
|
PROBE_TIMEOUT_MS,
|
|
406
415
|
loadPlanPrerequisites,
|
|
@@ -412,7 +421,7 @@ import {
|
|
|
412
421
|
runPreflight,
|
|
413
422
|
splitBlockerComment,
|
|
414
423
|
trackerPathFor
|
|
415
|
-
} from "./index-
|
|
424
|
+
} from "./index-zg0qsb5b.js";
|
|
416
425
|
import {
|
|
417
426
|
ACTION_HEADING,
|
|
418
427
|
CAUSE_HEADING,
|
|
@@ -523,7 +532,7 @@ import {
|
|
|
523
532
|
versionLine,
|
|
524
533
|
writeFrontmatter,
|
|
525
534
|
writePositionFile
|
|
526
|
-
} from "./index-
|
|
535
|
+
} from "./index-cd0wzc12.js";
|
|
527
536
|
import {
|
|
528
537
|
CONFIG_DEFAULTS,
|
|
529
538
|
CONFIG_FILE,
|
|
@@ -542,7 +551,7 @@ import {
|
|
|
542
551
|
readItemBytes,
|
|
543
552
|
readRafaBlocks,
|
|
544
553
|
resolveTiers
|
|
545
|
-
} from "./index-
|
|
554
|
+
} from "./index-3jpz9nr3.js";
|
|
546
555
|
import {
|
|
547
556
|
promotable
|
|
548
557
|
} from "./index-d6d0942q.js";
|
|
@@ -2168,7 +2177,7 @@ import { join as join4, relative as relative2 } from "path";
|
|
|
2168
2177
|
var SEARCH_PROMPT_PREFIX = "# Inventory search instructions";
|
|
2169
2178
|
var SEARCH_BLOCK_FENCE = "rafa:search";
|
|
2170
2179
|
var MIN_FENCE_LENGTH = 3;
|
|
2171
|
-
function
|
|
2180
|
+
function fenceFor2(text) {
|
|
2172
2181
|
const longestRun = Math.max(0, ...(text.match(/`+/g) ?? []).map((run) => run.length));
|
|
2173
2182
|
return "`".repeat(Math.max(MIN_FENCE_LENGTH, longestRun + 1));
|
|
2174
2183
|
}
|
|
@@ -2184,7 +2193,7 @@ var EXAMPLE_BLOCK = [
|
|
|
2184
2193
|
];
|
|
2185
2194
|
function renderSearchPrompt(input) {
|
|
2186
2195
|
const plural2 = `${input.kind}s`;
|
|
2187
|
-
const fence =
|
|
2196
|
+
const fence = fenceFor2(input.question);
|
|
2188
2197
|
const candidates = input.candidates.map((candidate) => `- ${candidate.name}: \`${candidate.file}\``);
|
|
2189
2198
|
return [
|
|
2190
2199
|
SEARCH_PROMPT_PREFIX,
|
|
@@ -8820,7 +8829,7 @@ function optionalString(record, key) {
|
|
|
8820
8829
|
}
|
|
8821
8830
|
|
|
8822
8831
|
// src/commands/stretch/item.ts
|
|
8823
|
-
import { closeSync
|
|
8832
|
+
import { closeSync, mkdirSync as mkdirSync6, openSync, readdirSync as readdirSync3, readFileSync as readFileSync15, statSync as statSync6 } from "fs";
|
|
8824
8833
|
import { dirname as dirname6, join as join20, posix } from "path";
|
|
8825
8834
|
|
|
8826
8835
|
// src/stretch/operators.ts
|
|
@@ -8995,83 +9004,6 @@ function lineText(argv) {
|
|
|
8995
9004
|
// src/commands/stretch/item-merge.ts
|
|
8996
9005
|
import { readFileSync as readFileSync14 } from "fs";
|
|
8997
9006
|
|
|
8998
|
-
// src/loop/events-file.ts
|
|
8999
|
-
import { closeSync, fstatSync, openSync, readSync } from "fs";
|
|
9000
|
-
var NEWLINE = 10;
|
|
9001
|
-
function eventsFileOf(root, record) {
|
|
9002
|
-
return eventsFilePath(root, record.sessionId);
|
|
9003
|
-
}
|
|
9004
|
-
function isPlainObject(value) {
|
|
9005
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9006
|
-
}
|
|
9007
|
-
function parseEventLine(line) {
|
|
9008
|
-
let value;
|
|
9009
|
-
try {
|
|
9010
|
-
value = JSON.parse(line);
|
|
9011
|
-
} catch {
|
|
9012
|
-
return null;
|
|
9013
|
-
}
|
|
9014
|
-
if (!isPlainObject(value))
|
|
9015
|
-
return null;
|
|
9016
|
-
const { name: name2, summary, data, ts } = value;
|
|
9017
|
-
if (typeof name2 !== "string" || typeof summary !== "string" || typeof ts !== "string")
|
|
9018
|
-
return null;
|
|
9019
|
-
if (!isPlainObject(data))
|
|
9020
|
-
return null;
|
|
9021
|
-
return Object.freeze({ name: name2, summary, data: Object.freeze({ ...data }), ts });
|
|
9022
|
-
}
|
|
9023
|
-
function bytesFrom(fd, offset) {
|
|
9024
|
-
const length = fstatSync(fd).size - offset;
|
|
9025
|
-
if (length <= 0)
|
|
9026
|
-
return null;
|
|
9027
|
-
const buffer = Buffer.alloc(length);
|
|
9028
|
-
let filled = 0;
|
|
9029
|
-
while (filled < length) {
|
|
9030
|
-
const read = readSync(fd, buffer, filled, length - filled, offset + filled);
|
|
9031
|
-
if (read === 0)
|
|
9032
|
-
break;
|
|
9033
|
-
filled += read;
|
|
9034
|
-
}
|
|
9035
|
-
return buffer.subarray(0, filled);
|
|
9036
|
-
}
|
|
9037
|
-
function readTail(file, offset) {
|
|
9038
|
-
let fd;
|
|
9039
|
-
try {
|
|
9040
|
-
fd = openSync(file, "r");
|
|
9041
|
-
} catch (error) {
|
|
9042
|
-
if (errorCode(error) === "ENOENT")
|
|
9043
|
-
return "absent";
|
|
9044
|
-
throw error;
|
|
9045
|
-
}
|
|
9046
|
-
try {
|
|
9047
|
-
return bytesFrom(fd, offset);
|
|
9048
|
-
} finally {
|
|
9049
|
-
closeSync(fd);
|
|
9050
|
-
}
|
|
9051
|
-
}
|
|
9052
|
-
function readEventsFrom(file, offset) {
|
|
9053
|
-
if (!Number.isSafeInteger(offset) || offset < 0) {
|
|
9054
|
-
throw new RangeError(`events file: unusable offset ${String(offset)}`);
|
|
9055
|
-
}
|
|
9056
|
-
const tail = readTail(file, offset);
|
|
9057
|
-
if (tail === "absent")
|
|
9058
|
-
return Object.freeze({ kind: "absent" });
|
|
9059
|
-
const end = tail?.lastIndexOf(NEWLINE) ?? -1;
|
|
9060
|
-
if (tail === null || end < 0) {
|
|
9061
|
-
return Object.freeze({ kind: "read", events: Object.freeze([]), malformed: 0, offset });
|
|
9062
|
-
}
|
|
9063
|
-
const lines = tail.subarray(0, end).toString("utf8").split(`
|
|
9064
|
-
`);
|
|
9065
|
-
const parsed = lines.map(parseEventLine);
|
|
9066
|
-
const events = parsed.filter((event) => event !== null);
|
|
9067
|
-
return Object.freeze({
|
|
9068
|
-
kind: "read",
|
|
9069
|
-
events: Object.freeze(events),
|
|
9070
|
-
malformed: parsed.length - events.length,
|
|
9071
|
-
offset: offset + end + 1
|
|
9072
|
-
});
|
|
9073
|
-
}
|
|
9074
|
-
|
|
9075
9007
|
// src/stretch/items.ts
|
|
9076
9008
|
import { appendFileSync, mkdirSync as mkdirSync4, readFileSync as readFileSync11 } from "fs";
|
|
9077
9009
|
import { dirname as dirname3, join as join17 } from "path";
|
|
@@ -10194,7 +10126,7 @@ async function spawnOnTerminal(argv, cwd, env) {
|
|
|
10194
10126
|
function spawnDetached(argv, cwd, env, logPath) {
|
|
10195
10127
|
let fd;
|
|
10196
10128
|
try {
|
|
10197
|
-
fd =
|
|
10129
|
+
fd = openSync(logPath, "a");
|
|
10198
10130
|
} catch {
|
|
10199
10131
|
return null;
|
|
10200
10132
|
}
|
|
@@ -10205,7 +10137,7 @@ function spawnDetached(argv, cwd, env, logPath) {
|
|
|
10205
10137
|
} catch {
|
|
10206
10138
|
return null;
|
|
10207
10139
|
} finally {
|
|
10208
|
-
|
|
10140
|
+
closeSync(fd);
|
|
10209
10141
|
}
|
|
10210
10142
|
}
|
|
10211
10143
|
function defaultStretchItemSeams() {
|
|
@@ -13159,48 +13091,7 @@ var cancel_default = createEpicCancelCommand();
|
|
|
13159
13091
|
|
|
13160
13092
|
// src/commands/epic/close.ts
|
|
13161
13093
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
13162
|
-
import { join as
|
|
13163
|
-
|
|
13164
|
-
// src/board/epic-template.ts
|
|
13165
|
-
import { existsSync as existsSync8, readFileSync as readFileSync18 } from "fs";
|
|
13166
|
-
import { dirname as dirname8, join as join25 } from "path";
|
|
13167
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
13168
|
-
var MODULE_DIR2 = dirname8(fileURLToPath2(import.meta.url));
|
|
13169
|
-
var EPIC_TEMPLATE_FILE = "epic.md";
|
|
13170
|
-
var CRITERIA_PLACEHOLDERS = Object.freeze([
|
|
13171
|
-
"- Placeholder: one line per thing that makes this epic finished," + " written so a check against main can tell whether it holds."
|
|
13172
|
-
]);
|
|
13173
|
-
var PLACEHOLDER_REASON = "the line is still the epic template's placeholder, so there is nothing to check";
|
|
13174
|
-
function epicTemplateSource(moduleDir = MODULE_DIR2) {
|
|
13175
|
-
return join25(moduleDir, TEMPLATES_DIRNAME, EPIC_TEMPLATE_FILE);
|
|
13176
|
-
}
|
|
13177
|
-
function readEpicTemplate(moduleDir = MODULE_DIR2) {
|
|
13178
|
-
const source = epicTemplateSource(moduleDir);
|
|
13179
|
-
if (!existsSync8(source)) {
|
|
13180
|
-
throw new Error(`epic template: the epic issue template is missing: no file at ${source}`);
|
|
13181
|
-
}
|
|
13182
|
-
return readFileSync18(source, "utf8");
|
|
13183
|
-
}
|
|
13184
|
-
function placeholderCriteria(criteria) {
|
|
13185
|
-
if (criteria === null)
|
|
13186
|
-
return Object.freeze([]);
|
|
13187
|
-
const held = criteria.split(/\r\n?|\n/u).map((line) => line.trim()).filter((line) => CRITERIA_PLACEHOLDERS.includes(line));
|
|
13188
|
-
return Object.freeze(held.map((text) => Object.freeze({ text, reason: PLACEHOLDER_REASON })));
|
|
13189
|
-
}
|
|
13190
|
-
function renderEpicBody(template = readEpicTemplate()) {
|
|
13191
|
-
const read = readEpicBody(template);
|
|
13192
|
-
if (read.criteria === null) {
|
|
13193
|
-
throw new Error("epic template: the template carries no acceptance criteria section with a placeholder under it");
|
|
13194
|
-
}
|
|
13195
|
-
const missing = CRITERIA_PLACEHOLDERS.length - placeholderCriteria(read.criteria).length;
|
|
13196
|
-
if (missing > 0) {
|
|
13197
|
-
throw new Error(`epic template: the acceptance criteria section has lost ${String(missing)} of its placeholder lines`);
|
|
13198
|
-
}
|
|
13199
|
-
if (read.lines.length > 0) {
|
|
13200
|
-
throw new Error(`epic template: the template carries ${String(read.lines.length)} checklist lines; a new epic has none`);
|
|
13201
|
-
}
|
|
13202
|
-
return template;
|
|
13203
|
-
}
|
|
13094
|
+
import { join as join26 } from "path";
|
|
13204
13095
|
|
|
13205
13096
|
// src/effort/epic-cost.ts
|
|
13206
13097
|
var MEMBERSHIP_NOTE = "cost follows membership at close time: it counts the sessions of the issues in the epic now, " + "so work on an issue moved out is not counted and work on an issue moved in is";
|
|
@@ -13269,211 +13160,9 @@ function renderEpicCost(cost, estimate) {
|
|
|
13269
13160
|
];
|
|
13270
13161
|
}
|
|
13271
13162
|
|
|
13272
|
-
// src/epic/verify-plan.ts
|
|
13273
|
-
import { existsSync as existsSync9, readFileSync as readFileSync19 } from "fs";
|
|
13274
|
-
import { dirname as dirname9, join as join26 } from "path";
|
|
13275
|
-
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
13276
|
-
var MODULE_DIR3 = dirname9(fileURLToPath3(import.meta.url));
|
|
13277
|
-
var VERIFY_PROMPT_FILE = "epic-verify-prompt.md";
|
|
13278
|
-
var VERIFY_BLOCK_FENCE = "rafa:verify";
|
|
13279
|
-
var VERIFY_PROMPT_SLOTS = ["EPIC_NUMBER", "EPIC_TITLE", "CRITERIA"];
|
|
13280
|
-
var SKIPPED_REASON = "the verification plan did not answer it";
|
|
13281
|
-
var FENCE2 = /^\s*(?:`{3,}|~{3,})/u;
|
|
13282
|
-
var LIST_ITEM = /^( {0,3})(?:[-*+]|\d{1,9}[.)])(?:\s|$)/u;
|
|
13283
|
-
var INDENTED = /^\s/u;
|
|
13284
|
-
var MIN_FENCE_LENGTH2 = 3;
|
|
13285
|
-
var VERIFY_KIND = VERIFY_BLOCK_FENCE.slice("rafa:".length);
|
|
13286
|
-
var SLOT_PATTERN = new RegExp(`\\{(${VERIFY_PROMPT_SLOTS.join("|")})\\}`, "gu");
|
|
13287
|
-
var ANSWER_KEYS = ["check", "uncheckable"];
|
|
13288
|
-
function opensCriterion(text, state) {
|
|
13289
|
-
const item = LIST_ITEM.exec(text);
|
|
13290
|
-
if (item !== null) {
|
|
13291
|
-
const indent = item[1]?.length ?? 0;
|
|
13292
|
-
state.topIndent ??= indent;
|
|
13293
|
-
return indent <= state.topIndent;
|
|
13294
|
-
}
|
|
13295
|
-
return state.afterBlank && !INDENTED.test(text);
|
|
13296
|
-
}
|
|
13297
|
-
function splitCriteria(criteria) {
|
|
13298
|
-
if (criteria === null)
|
|
13299
|
-
return Object.freeze([]);
|
|
13300
|
-
const gathered = [];
|
|
13301
|
-
const state = { fenced: false, afterBlank: false, topIndent: null };
|
|
13302
|
-
for (const text of criteria.split(/\r\n?|\n/u)) {
|
|
13303
|
-
const insideFence = state.fenced;
|
|
13304
|
-
if (FENCE2.test(text))
|
|
13305
|
-
state.fenced = !state.fenced;
|
|
13306
|
-
if (!insideFence && text.trim() === "") {
|
|
13307
|
-
state.afterBlank = true;
|
|
13308
|
-
gathered.at(-1)?.push(text);
|
|
13309
|
-
continue;
|
|
13310
|
-
}
|
|
13311
|
-
const current = gathered.at(-1);
|
|
13312
|
-
const opens = !insideFence && opensCriterion(text, state);
|
|
13313
|
-
if (current === undefined || opens) {
|
|
13314
|
-
gathered.push([text]);
|
|
13315
|
-
} else {
|
|
13316
|
-
current.push(text);
|
|
13317
|
-
}
|
|
13318
|
-
state.afterBlank = false;
|
|
13319
|
-
}
|
|
13320
|
-
const numbered = gathered.map((lines, index) => {
|
|
13321
|
-
const text = lines.join(`
|
|
13322
|
-
`).trim();
|
|
13323
|
-
return Object.freeze({ number: index + 1, text, placeholder: CRITERIA_PLACEHOLDERS.includes(text) });
|
|
13324
|
-
});
|
|
13325
|
-
return Object.freeze(numbered);
|
|
13326
|
-
}
|
|
13327
|
-
function criteriaToAsk(criteria) {
|
|
13328
|
-
return Object.freeze(criteria.filter((criterion) => !criterion.placeholder));
|
|
13329
|
-
}
|
|
13330
|
-
function verifyPromptCandidates(moduleDir = MODULE_DIR3) {
|
|
13331
|
-
return [join26(moduleDir, VERIFY_PROMPT_FILE), join26(dirname9(moduleDir), VERIFY_PROMPT_FILE)];
|
|
13332
|
-
}
|
|
13333
|
-
function readVerifyPrompt(moduleDir = MODULE_DIR3) {
|
|
13334
|
-
const candidates = verifyPromptCandidates(moduleDir);
|
|
13335
|
-
const found = candidates.find((candidate) => existsSync9(candidate));
|
|
13336
|
-
if (found === undefined) {
|
|
13337
|
-
throw new Error(`epic verify prompt: the verification prompt is missing: no file at ${candidates.join(" or ")}`);
|
|
13338
|
-
}
|
|
13339
|
-
return readFileSync19(found, "utf8");
|
|
13340
|
-
}
|
|
13341
|
-
function fenceFor2(text) {
|
|
13342
|
-
const longestRun = Math.max(0, ...(text.match(/`+/gu) ?? []).map((run) => run.length));
|
|
13343
|
-
return "`".repeat(Math.max(MIN_FENCE_LENGTH2, longestRun + 1));
|
|
13344
|
-
}
|
|
13345
|
-
function renderCriterion(criterion) {
|
|
13346
|
-
const fence = fenceFor2(criterion.text);
|
|
13347
|
-
return [`### Criterion ${String(criterion.number)}`, "", `${fence}text`, criterion.text, fence].join(`
|
|
13348
|
-
`);
|
|
13349
|
-
}
|
|
13350
|
-
function buildVerifyPrompt(template, input) {
|
|
13351
|
-
const missing = VERIFY_PROMPT_SLOTS.find((slot) => !template.includes(`{${slot}}`));
|
|
13352
|
-
if (missing !== undefined) {
|
|
13353
|
-
throw new Error(`epic verify prompt: the template carries no {${missing}} slot`);
|
|
13354
|
-
}
|
|
13355
|
-
const values = {
|
|
13356
|
-
EPIC_NUMBER: String(input.epic),
|
|
13357
|
-
EPIC_TITLE: input.title.replace(/\s+/gu, " ").trim(),
|
|
13358
|
-
CRITERIA: criteriaToAsk(input.criteria).map(renderCriterion).join(`
|
|
13359
|
-
|
|
13360
|
-
`)
|
|
13361
|
-
};
|
|
13362
|
-
return template.replace(SLOT_PATTERN, (_whole, slot) => values[slot]);
|
|
13363
|
-
}
|
|
13364
|
-
function isMapping3(value) {
|
|
13365
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13366
|
-
}
|
|
13367
|
-
function fieldOf2(mapping, key) {
|
|
13368
|
-
return Object.entries(mapping).find(([own]) => own === key)?.[1];
|
|
13369
|
-
}
|
|
13370
|
-
function describeValue3(value) {
|
|
13371
|
-
if (typeof value === "string")
|
|
13372
|
-
return JSON.stringify(value);
|
|
13373
|
-
if (value === null || value === undefined)
|
|
13374
|
-
return "nothing";
|
|
13375
|
-
if (Array.isArray(value))
|
|
13376
|
-
return "a list";
|
|
13377
|
-
if (typeof value === "object")
|
|
13378
|
-
return "a mapping";
|
|
13379
|
-
return `the ${typeof value} ${String(value)}`;
|
|
13380
|
-
}
|
|
13381
|
-
function messageOf4(error) {
|
|
13382
|
-
return error instanceof Error ? error.message : String(error);
|
|
13383
|
-
}
|
|
13384
|
-
function absent2(reason, block, text) {
|
|
13385
|
-
return Object.freeze({ present: false, reason, block, text });
|
|
13386
|
-
}
|
|
13387
|
-
function readEntry(item, field, asked) {
|
|
13388
|
-
if (!isMapping3(item))
|
|
13389
|
-
return { problem: `${field} is ${describeValue3(item)}, not a mapping`, number: null };
|
|
13390
|
-
const number = fieldOf2(item, "criterion");
|
|
13391
|
-
if (typeof number !== "number" || !Number.isInteger(number) || number < 1) {
|
|
13392
|
-
return { problem: `${field}.criterion is ${describeValue3(number)}, not a criterion number from 1`, number: null };
|
|
13393
|
-
}
|
|
13394
|
-
if (!asked.has(number)) {
|
|
13395
|
-
return { problem: `${field}.criterion ${String(number)} is no criterion the plan was asked about`, number: null };
|
|
13396
|
-
}
|
|
13397
|
-
const carried = ANSWER_KEYS.filter((key2) => fieldOf2(item, key2) !== undefined);
|
|
13398
|
-
const [key] = carried;
|
|
13399
|
-
if (carried.length !== 1 || key === undefined) {
|
|
13400
|
-
const count = carried.length === 0 ? "neither" : "both";
|
|
13401
|
-
return { problem: `${field} carries ${count} check and uncheckable`, number };
|
|
13402
|
-
}
|
|
13403
|
-
const value = fieldOf2(item, key);
|
|
13404
|
-
if (typeof value !== "string" || value.trim() === "") {
|
|
13405
|
-
return { problem: `${field}.${key} is ${describeValue3(value)}, not a non-blank string`, number };
|
|
13406
|
-
}
|
|
13407
|
-
return { answer: { number, key, text: value.trim() } };
|
|
13408
|
-
}
|
|
13409
|
-
function verdictFor(criterion, answer, problem) {
|
|
13410
|
-
if (criterion.placeholder) {
|
|
13411
|
-
return { kind: "uncheckable", criterion, reason: PLACEHOLDER_REASON, source: "placeholder" };
|
|
13412
|
-
}
|
|
13413
|
-
if (answer?.key === "check")
|
|
13414
|
-
return { kind: "check", criterion, check: answer.text };
|
|
13415
|
-
if (answer?.key === "uncheckable")
|
|
13416
|
-
return { kind: "uncheckable", criterion, reason: answer.text, source: "answer" };
|
|
13417
|
-
const reason = problem === undefined ? SKIPPED_REASON : `${SKIPPED_REASON}: its entry was dropped, as ${problem}`;
|
|
13418
|
-
return { kind: "uncheckable", criterion, reason, source: "skipped" };
|
|
13419
|
-
}
|
|
13420
|
-
function readVerdicts(items, criteria, block) {
|
|
13421
|
-
const asked = new Set(criteriaToAsk(criteria).map((criterion) => criterion.number));
|
|
13422
|
-
const answers = new Map;
|
|
13423
|
-
const problems = new Map;
|
|
13424
|
-
const issues = [];
|
|
13425
|
-
for (const [index, item] of items.entries()) {
|
|
13426
|
-
const field = `criteria[${String(index)}]`;
|
|
13427
|
-
const reading = readEntry(item, field, asked);
|
|
13428
|
-
if ("problem" in reading) {
|
|
13429
|
-
issues.push(Object.freeze({ field, text: `${reading.problem}; dropped` }));
|
|
13430
|
-
if (reading.number !== null && !problems.has(reading.number))
|
|
13431
|
-
problems.set(reading.number, reading.problem);
|
|
13432
|
-
continue;
|
|
13433
|
-
}
|
|
13434
|
-
if (answers.has(reading.answer.number)) {
|
|
13435
|
-
const text = `${field} answers criterion ${String(reading.answer.number)} a second time; dropped`;
|
|
13436
|
-
issues.push(Object.freeze({ field, text }));
|
|
13437
|
-
continue;
|
|
13438
|
-
}
|
|
13439
|
-
answers.set(reading.answer.number, reading.answer);
|
|
13440
|
-
}
|
|
13441
|
-
const verdicts = criteria.map((criterion) => Object.freeze(verdictFor(criterion, answers.get(criterion.number), problems.get(criterion.number))));
|
|
13442
|
-
return Object.freeze({
|
|
13443
|
-
present: true,
|
|
13444
|
-
verdicts: Object.freeze(verdicts),
|
|
13445
|
-
block,
|
|
13446
|
-
issues: Object.freeze(issues)
|
|
13447
|
-
});
|
|
13448
|
-
}
|
|
13449
|
-
function parseVerifyPlan(output, criteria) {
|
|
13450
|
-
const block = readRafaBlocks(output).filter((each) => each.kind === VERIFY_KIND).at(-1);
|
|
13451
|
-
if (block === undefined) {
|
|
13452
|
-
return absent2("no-block", null, `the session output holds no ${VERIFY_BLOCK_FENCE} block`);
|
|
13453
|
-
}
|
|
13454
|
-
const at = `${VERIFY_BLOCK_FENCE} block at line ${String(block.span.first)}`;
|
|
13455
|
-
if (!block.closed) {
|
|
13456
|
-
return absent2("unclosed-block", block, `${at} is never closed, so it is not read`);
|
|
13457
|
-
}
|
|
13458
|
-
let document;
|
|
13459
|
-
try {
|
|
13460
|
-
document = Bun.YAML.parse(block.body);
|
|
13461
|
-
} catch (error) {
|
|
13462
|
-
return absent2("malformed-block", block, `${at} is not valid YAML (${messageOf4(error)})`);
|
|
13463
|
-
}
|
|
13464
|
-
if (!isMapping3(document)) {
|
|
13465
|
-
return absent2("malformed-block", block, `${at} holds ${describeValue3(document)}, not a mapping`);
|
|
13466
|
-
}
|
|
13467
|
-
const listed2 = fieldOf2(document, "criteria") ?? [];
|
|
13468
|
-
if (!Array.isArray(listed2)) {
|
|
13469
|
-
return absent2("malformed-block", block, `${at} has criteria ${describeValue3(listed2)}, not a list`);
|
|
13470
|
-
}
|
|
13471
|
-
return readVerdicts(listed2, criteria, block);
|
|
13472
|
-
}
|
|
13473
|
-
|
|
13474
13163
|
// src/epic/verify-run.ts
|
|
13475
13164
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
13476
|
-
import { join as
|
|
13165
|
+
import { join as join25 } from "path";
|
|
13477
13166
|
var CHECK_TOOLS = ["Read", "Grep", "Glob", "Bash"];
|
|
13478
13167
|
var DEFAULT_VERIFY_REMOTE = "origin";
|
|
13479
13168
|
var CHECK_PROMPT_PREFIX = "# Epic acceptance check instructions";
|
|
@@ -13482,7 +13171,7 @@ var CHECK_RESULTS = ["pass", "fail"];
|
|
|
13482
13171
|
var WORKTREE_PREFIX = "epic-";
|
|
13483
13172
|
var VERDICT_KIND = VERDICT_BLOCK_FENCE.slice("rafa:".length);
|
|
13484
13173
|
function verifyWorktreePath(home, epic) {
|
|
13485
|
-
return
|
|
13174
|
+
return join25(home, WORKTREES_SUBDIR, `${WORKTREE_PREFIX}${String(epic)}`);
|
|
13486
13175
|
}
|
|
13487
13176
|
function fetchStep(remote) {
|
|
13488
13177
|
return { id: "fetch", args: ["fetch", remote] };
|
|
@@ -13513,7 +13202,7 @@ function checkFlags(sessionId) {
|
|
|
13513
13202
|
return [SESSION_ID_FLAG, sessionId, "--tools", CHECK_TOOLS.join(",")];
|
|
13514
13203
|
}
|
|
13515
13204
|
function renderCheckPrompt(input) {
|
|
13516
|
-
const fence =
|
|
13205
|
+
const fence = fenceFor(input.check);
|
|
13517
13206
|
return [
|
|
13518
13207
|
CHECK_PROMPT_PREFIX,
|
|
13519
13208
|
"",
|
|
@@ -13554,13 +13243,13 @@ function renderCheckPrompt(input) {
|
|
|
13554
13243
|
].join(`
|
|
13555
13244
|
`);
|
|
13556
13245
|
}
|
|
13557
|
-
function
|
|
13246
|
+
function isMapping3(value) {
|
|
13558
13247
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13559
13248
|
}
|
|
13560
|
-
function
|
|
13249
|
+
function fieldOf2(mapping, key) {
|
|
13561
13250
|
return Object.entries(mapping).find(([own]) => own === key)?.[1];
|
|
13562
13251
|
}
|
|
13563
|
-
function
|
|
13252
|
+
function describeValue3(value) {
|
|
13564
13253
|
if (typeof value === "string")
|
|
13565
13254
|
return JSON.stringify(value);
|
|
13566
13255
|
if (value === null || value === undefined)
|
|
@@ -13574,7 +13263,7 @@ function describeValue4(value) {
|
|
|
13574
13263
|
function isResultWord(value) {
|
|
13575
13264
|
return CHECK_RESULTS.some((word) => word === value);
|
|
13576
13265
|
}
|
|
13577
|
-
function
|
|
13266
|
+
function absent2(text, block) {
|
|
13578
13267
|
return Object.freeze({ present: false, text, block });
|
|
13579
13268
|
}
|
|
13580
13269
|
function readVerdictBody(block, at) {
|
|
@@ -13582,29 +13271,29 @@ function readVerdictBody(block, at) {
|
|
|
13582
13271
|
try {
|
|
13583
13272
|
document = Bun.YAML.parse(block.body);
|
|
13584
13273
|
} catch (error) {
|
|
13585
|
-
return
|
|
13274
|
+
return absent2(`${at} is not valid YAML (${messageOf(error)})`, block);
|
|
13586
13275
|
}
|
|
13587
|
-
if (!
|
|
13588
|
-
return
|
|
13276
|
+
if (!isMapping3(document)) {
|
|
13277
|
+
return absent2(`${at} holds ${describeValue3(document)}, not a mapping`, block);
|
|
13589
13278
|
}
|
|
13590
|
-
const result2 =
|
|
13279
|
+
const result2 = fieldOf2(document, "result");
|
|
13591
13280
|
if (!isResultWord(result2)) {
|
|
13592
|
-
return
|
|
13281
|
+
return absent2(`${at} has result ${describeValue3(result2)}, not ${CHECK_RESULTS.join(" or ")}`, block);
|
|
13593
13282
|
}
|
|
13594
|
-
const evidence =
|
|
13283
|
+
const evidence = fieldOf2(document, "evidence");
|
|
13595
13284
|
if (typeof evidence !== "string" || evidence.trim() === "") {
|
|
13596
|
-
return
|
|
13285
|
+
return absent2(`${at} has evidence ${describeValue3(evidence)}, not a non-blank string`, block);
|
|
13597
13286
|
}
|
|
13598
13287
|
return Object.freeze({ present: true, result: result2, evidence: evidence.trim(), block });
|
|
13599
13288
|
}
|
|
13600
13289
|
function parseCheckVerdict(output) {
|
|
13601
13290
|
const block = readRafaBlocks(output).filter((each) => each.kind === VERDICT_KIND).at(-1);
|
|
13602
13291
|
if (block === undefined) {
|
|
13603
|
-
return
|
|
13292
|
+
return absent2(`the session output holds no ${VERDICT_BLOCK_FENCE} block`, null);
|
|
13604
13293
|
}
|
|
13605
13294
|
const at = `${VERDICT_BLOCK_FENCE} block at line ${String(block.span.first)}`;
|
|
13606
13295
|
if (!block.closed)
|
|
13607
|
-
return
|
|
13296
|
+
return absent2(`${at} is never closed, so it is not read`, block);
|
|
13608
13297
|
return readVerdictBody(block, at);
|
|
13609
13298
|
}
|
|
13610
13299
|
function readCheck(check, sessionId, session) {
|
|
@@ -13764,7 +13453,7 @@ async function planVerification(input) {
|
|
|
13764
13453
|
return Object.freeze({ status: "planned", sessionId, verdicts: reading.verdicts, issues: reading.issues });
|
|
13765
13454
|
}
|
|
13766
13455
|
function closeTriageFile(root, epic) {
|
|
13767
|
-
return
|
|
13456
|
+
return join26(root, ".rafa", `epic-${String(epic)}-close`);
|
|
13768
13457
|
}
|
|
13769
13458
|
function failedCheckArtifact(epic, criterion) {
|
|
13770
13459
|
return `epic ${ref7(epic)} acceptance criterion: ${oneLine3(criterion.text)}`;
|
|
@@ -14367,13 +14056,13 @@ function createEpicPromoteCommand(seams = {}) {
|
|
|
14367
14056
|
var promote_default = createEpicPromoteCommand();
|
|
14368
14057
|
|
|
14369
14058
|
// src/commands/init.ts
|
|
14370
|
-
import { existsSync as
|
|
14059
|
+
import { existsSync as existsSync10, readFileSync as readFileSync21 } from "fs";
|
|
14371
14060
|
import { homedir as homedir3 } from "os";
|
|
14372
|
-
import { join as
|
|
14061
|
+
import { join as join30, relative as relative6, sep as sep3 } from "path";
|
|
14373
14062
|
|
|
14374
14063
|
// src/agents/vendorable.ts
|
|
14375
|
-
import { readdirSync as readdirSync4, readFileSync as
|
|
14376
|
-
import { isAbsolute as isAbsolute3, join as
|
|
14064
|
+
import { readdirSync as readdirSync4, readFileSync as readFileSync18 } from "fs";
|
|
14065
|
+
import { isAbsolute as isAbsolute3, join as join27 } from "path";
|
|
14377
14066
|
function planFiles(dir) {
|
|
14378
14067
|
let entries;
|
|
14379
14068
|
try {
|
|
@@ -14385,7 +14074,7 @@ function planFiles(dir) {
|
|
|
14385
14074
|
}
|
|
14386
14075
|
function readText3(path) {
|
|
14387
14076
|
try {
|
|
14388
|
-
return
|
|
14077
|
+
return readFileSync18(path, "utf8");
|
|
14389
14078
|
} catch {
|
|
14390
14079
|
return null;
|
|
14391
14080
|
}
|
|
@@ -14395,7 +14084,7 @@ function rafaHolds(roster, name2) {
|
|
|
14395
14084
|
return item?.holders.some((holder) => holder.source === "rafa") === true;
|
|
14396
14085
|
}
|
|
14397
14086
|
function vendorableAgents(scan) {
|
|
14398
|
-
const dir = isAbsolute3(scan.planDir) ? scan.planDir :
|
|
14087
|
+
const dir = isAbsolute3(scan.planDir) ? scan.planDir : join27(scan.repoRoot, scan.planDir);
|
|
14399
14088
|
const roots = {
|
|
14400
14089
|
repoRoot: scan.repoRoot,
|
|
14401
14090
|
home: scan.home,
|
|
@@ -14404,7 +14093,7 @@ function vendorableAgents(scan) {
|
|
|
14404
14093
|
const roster = resolveAgentRoster(roots, scan.settings);
|
|
14405
14094
|
const found = [];
|
|
14406
14095
|
for (const file of planFiles(dir)) {
|
|
14407
|
-
const path =
|
|
14096
|
+
const path = join27(dir, file);
|
|
14408
14097
|
const markdown = readText3(path);
|
|
14409
14098
|
if (markdown === null)
|
|
14410
14099
|
continue;
|
|
@@ -14430,13 +14119,13 @@ function vendorableAgentWarnings(agents, root) {
|
|
|
14430
14119
|
|
|
14431
14120
|
// src/project/gitignore.ts
|
|
14432
14121
|
import { createHash } from "crypto";
|
|
14433
|
-
import { existsSync as
|
|
14434
|
-
import { dirname as
|
|
14122
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync19, writeFileSync as writeFileSync6 } from "fs";
|
|
14123
|
+
import { dirname as dirname8, isAbsolute as isAbsolute4, join as join28 } from "path";
|
|
14435
14124
|
var GITIGNORE_FILE = ".gitignore";
|
|
14436
14125
|
var DIGEST_NAME = "tracking.digest";
|
|
14437
14126
|
var PRIVATE_TRIAGE = "triage/private";
|
|
14438
14127
|
var CACHE_DIR = "cache";
|
|
14439
|
-
var TRACKING_DIGEST_FILE =
|
|
14128
|
+
var TRACKING_DIGEST_FILE = join28(SCOPE_DIR, DIGEST_NAME);
|
|
14440
14129
|
var BLOCK_BEGIN = "# >>> rafa tracking: rafa rewrites the lines up to the end marker";
|
|
14441
14130
|
var BLOCK_END = "# <<< rafa tracking";
|
|
14442
14131
|
var SUB_PATHS = [
|
|
@@ -14525,13 +14214,13 @@ function attempt2(file, failure3, act) {
|
|
|
14525
14214
|
}
|
|
14526
14215
|
}
|
|
14527
14216
|
function readIfPresent2(file) {
|
|
14528
|
-
if (!
|
|
14217
|
+
if (!existsSync8(file))
|
|
14529
14218
|
return null;
|
|
14530
|
-
return attempt2(file, "cannot be read", () =>
|
|
14219
|
+
return attempt2(file, "cannot be read", () => readFileSync19(file, "utf8"));
|
|
14531
14220
|
}
|
|
14532
14221
|
function writeTrackingGitignore(root, flags) {
|
|
14533
14222
|
requireAbsolute(root);
|
|
14534
|
-
const file =
|
|
14223
|
+
const file = join28(root, GITIGNORE_FILE);
|
|
14535
14224
|
const text = readIfPresent2(file);
|
|
14536
14225
|
const next = withTrackingBlock(text, flags, file);
|
|
14537
14226
|
if (next === text)
|
|
@@ -14553,7 +14242,7 @@ function trackingDigest(flags) {
|
|
|
14553
14242
|
}
|
|
14554
14243
|
function exposureNotice(root) {
|
|
14555
14244
|
return [
|
|
14556
|
-
`tracking.all is true, so ${
|
|
14245
|
+
`tracking.all is true, so ${join28(root, GITIGNORE_FILE)} no longer ignores ${SCOPE_DIR}/` + " and a commit can carry what it holds, including:",
|
|
14557
14246
|
" - unpatched issues described in specs and plans",
|
|
14558
14247
|
" - effort rows with model names and token counts",
|
|
14559
14248
|
" - instincts that may quote error output",
|
|
@@ -14566,7 +14255,7 @@ function printWarning(message) {
|
|
|
14566
14255
|
}
|
|
14567
14256
|
function noticeTrackingChange(root, flags, print2 = printWarning) {
|
|
14568
14257
|
requireAbsolute(root);
|
|
14569
|
-
const digestFile =
|
|
14258
|
+
const digestFile = join28(root, TRACKING_DIGEST_FILE);
|
|
14570
14259
|
const recorded = `${trackingDigest(flags)}
|
|
14571
14260
|
`;
|
|
14572
14261
|
if (readIfPresent2(digestFile) === recorded) {
|
|
@@ -14575,7 +14264,7 @@ function noticeTrackingChange(root, flags, print2 = printWarning) {
|
|
|
14575
14264
|
if (flags.trackingAll)
|
|
14576
14265
|
print2(exposureNotice(root));
|
|
14577
14266
|
attempt2(digestFile, "cannot be written", () => {
|
|
14578
|
-
mkdirSync7(
|
|
14267
|
+
mkdirSync7(dirname8(digestFile), { recursive: true });
|
|
14579
14268
|
writeFileSync6(digestFile, recorded);
|
|
14580
14269
|
});
|
|
14581
14270
|
return { digestFile, changed: true, printed: flags.trackingAll };
|
|
@@ -14665,14 +14354,14 @@ async function promptForRoot(found, prompter, seams) {
|
|
|
14665
14354
|
}
|
|
14666
14355
|
|
|
14667
14356
|
// src/project/scaffold.ts
|
|
14668
|
-
import { existsSync as
|
|
14669
|
-
import { join as
|
|
14357
|
+
import { existsSync as existsSync9, lstatSync, mkdirSync as mkdirSync8, statSync as statSync7, writeFileSync as writeFileSync8 } from "fs";
|
|
14358
|
+
import { join as join29 } from "path";
|
|
14670
14359
|
|
|
14671
14360
|
// src/commands/init-release.ts
|
|
14672
14361
|
import { writeFileSync as writeFileSync7 } from "fs";
|
|
14673
14362
|
|
|
14674
14363
|
// src/release/setting.ts
|
|
14675
|
-
import { readFileSync as
|
|
14364
|
+
import { readFileSync as readFileSync20 } from "fs";
|
|
14676
14365
|
var RELEASE_ENABLED_SETTING = "release.enabled";
|
|
14677
14366
|
function releaseEnabledIn(text, path) {
|
|
14678
14367
|
return parseConfigText(text, path).values.releaseEnabled ?? null;
|
|
@@ -14681,7 +14370,7 @@ function readReleaseSetting(root) {
|
|
|
14681
14370
|
const path = configFilePath(root);
|
|
14682
14371
|
let text;
|
|
14683
14372
|
try {
|
|
14684
|
-
text =
|
|
14373
|
+
text = readFileSync20(path, "utf8");
|
|
14685
14374
|
} catch (error) {
|
|
14686
14375
|
return { enabled: null, text: "", problem: `${path} could not be read: ${messageOf(error)}` };
|
|
14687
14376
|
}
|
|
@@ -14900,6 +14589,13 @@ var CONFIG_SETTINGS_LINES = Object.freeze([
|
|
|
14900
14589
|
"# loop:",
|
|
14901
14590
|
`# settingSources: ${CONFIG_DEFAULTS.settingSources.join(",")} # a comma-separated subset of user, project, local`,
|
|
14902
14591
|
`# worktreeDir: ${CONFIG_DEFAULTS.loopWorktreeDir} # where a loop adds its worktrees, read from the project root`,
|
|
14592
|
+
`# retries: ${String(CONFIG_DEFAULTS.loopRetries)} # 1..3 | false, times in a row a run re-enters its loop after a retry-safe stop`,
|
|
14593
|
+
`# retriesOnContinue: ${String(CONFIG_DEFAULTS.loopRetriesOnContinue)} # 1..3 | false, the retries a --continue run opens when --retry is not typed`,
|
|
14594
|
+
"# continue:",
|
|
14595
|
+
`# criteria: ${CONFIG_DEFAULTS.loopContinueCriteria} # the project's own criteria for a --continue decision`,
|
|
14596
|
+
`# criteriaMode: ${CONFIG_DEFAULTS.loopContinueCriteriaMode} # extend | replace, how the project criteria meet the bundled base`,
|
|
14597
|
+
"# forceWrapUp:",
|
|
14598
|
+
`# maxNewFailures: ${String(CONFIG_DEFAULTS.loopForceWrapUpMaxNewFailures)} # 1..50 | false, new suite failures --force-wrap-up tolerates`,
|
|
14903
14599
|
"# wrapUp:",
|
|
14904
14600
|
`# retries: ${String(CONFIG_DEFAULTS.loopWrapUpRetries)} # 1..3 | false, wrap-up sessions rerun before rafa opens a missing PR itself`,
|
|
14905
14601
|
"# pr:",
|
|
@@ -14995,7 +14691,7 @@ class ScaffoldError extends Error {
|
|
|
14995
14691
|
}
|
|
14996
14692
|
function layoutOf2(base, tree) {
|
|
14997
14693
|
const scope = scopeAt(base);
|
|
14998
|
-
return { dirs: [scope.dir, ...tree.map((name2) =>
|
|
14694
|
+
return { dirs: [scope.dir, ...tree.map((name2) => join29(scope.dir, name2))], configFile: configFilePath(base) };
|
|
14999
14695
|
}
|
|
15000
14696
|
function occupied(path) {
|
|
15001
14697
|
return lstatSync(path, { throwIfNoEntry: false }) !== undefined;
|
|
@@ -15006,7 +14702,7 @@ function isDirectory2(path) {
|
|
|
15006
14702
|
function directoryConflict(dir) {
|
|
15007
14703
|
if (!occupied(dir) || isDirectory2(dir))
|
|
15008
14704
|
return null;
|
|
15009
|
-
return
|
|
14705
|
+
return existsSync9(dir) ? `${dir} is not a directory` : `${dir} is a link to nothing`;
|
|
15010
14706
|
}
|
|
15011
14707
|
function layoutConflicts(layout) {
|
|
15012
14708
|
const [scopeDir, ...tree] = layout.dirs;
|
|
@@ -15014,7 +14710,7 @@ function layoutConflicts(layout) {
|
|
|
15014
14710
|
if (opening !== null)
|
|
15015
14711
|
return [opening];
|
|
15016
14712
|
const dirs = tree.flatMap((dir) => directoryConflict(dir) ?? []);
|
|
15017
|
-
const file = occupied(layout.configFile) && !
|
|
14713
|
+
const file = occupied(layout.configFile) && !existsSync9(layout.configFile) ? [`${layout.configFile} is a link to nothing`] : [];
|
|
15018
14714
|
return [...dirs, ...file];
|
|
15019
14715
|
}
|
|
15020
14716
|
function scaffoldConflicts(root, home) {
|
|
@@ -15028,7 +14724,7 @@ function attempt3(path, failure3, act) {
|
|
|
15028
14724
|
}
|
|
15029
14725
|
}
|
|
15030
14726
|
function ensureDirectory(path) {
|
|
15031
|
-
if (
|
|
14727
|
+
if (existsSync9(path))
|
|
15032
14728
|
return { path, kind: "directory", change: "unchanged" };
|
|
15033
14729
|
attempt3(path, "cannot be created", () => {
|
|
15034
14730
|
mkdirSync8(path, { recursive: true });
|
|
@@ -15036,7 +14732,7 @@ function ensureDirectory(path) {
|
|
|
15036
14732
|
return { path, kind: "directory", change: "created" };
|
|
15037
14733
|
}
|
|
15038
14734
|
function ensureFile(path, text) {
|
|
15039
|
-
if (
|
|
14735
|
+
if (existsSync9(path))
|
|
15040
14736
|
return { path, kind: "file", change: "unchanged" };
|
|
15041
14737
|
attempt3(path, "cannot be written", () => {
|
|
15042
14738
|
writeFileSync8(path, text, { encoding: "utf8", flag: "wx" });
|
|
@@ -15181,9 +14877,9 @@ function resolvedConfig2(root, home, warn3) {
|
|
|
15181
14877
|
}
|
|
15182
14878
|
}
|
|
15183
14879
|
function checkGitignore(root, flags) {
|
|
15184
|
-
const file =
|
|
14880
|
+
const file = join30(root, GITIGNORE_FILE);
|
|
15185
14881
|
try {
|
|
15186
|
-
const text =
|
|
14882
|
+
const text = existsSync10(file) ? readFileSync21(file, "utf8") : null;
|
|
15187
14883
|
withTrackingBlock(text, flags, file);
|
|
15188
14884
|
} catch (error) {
|
|
15189
14885
|
const message = error instanceof GitignoreError ? error.message : `rafa init: ${file} cannot be read (${messageOf(error)})`;
|
|
@@ -15215,8 +14911,8 @@ function initialise(root, start2, home, context, entry) {
|
|
|
15215
14911
|
const resolved = resolvedConfig2(root.path, home, warn3);
|
|
15216
14912
|
const config = resolved.config;
|
|
15217
14913
|
checkGitignore(root.path, config);
|
|
15218
|
-
const configExisted =
|
|
15219
|
-
const digestExisted =
|
|
14914
|
+
const configExisted = existsSync10(configFilePath(root.path));
|
|
14915
|
+
const digestExisted = existsSync10(join30(root.path, TRACKING_DIGEST_FILE));
|
|
15220
14916
|
const project = writeProjectScope(root.path);
|
|
15221
14917
|
const tracking = applyTracking(root.path, config, warn3);
|
|
15222
14918
|
const writes = [...project, ...trackingWrites(tracking, digestExisted), ...writeUserScope(home)];
|
|
@@ -16102,8 +15798,8 @@ function createInstinctShowCommand() {
|
|
|
16102
15798
|
var show_default3 = createInstinctShowCommand();
|
|
16103
15799
|
|
|
16104
15800
|
// src/commands/issue/check.ts
|
|
16105
|
-
import { readdirSync as readdirSync5, readFileSync as
|
|
16106
|
-
import { join as
|
|
15801
|
+
import { readdirSync as readdirSync5, readFileSync as readFileSync22, statSync as statSync8 } from "fs";
|
|
15802
|
+
import { join as join31, resolve as resolve9 } from "path";
|
|
16107
15803
|
var CHECK_USAGE = "rafa issue check <n> [--stamp]";
|
|
16108
15804
|
var STAMP_FLAG = "stamp";
|
|
16109
15805
|
var ISSUE_NUMBER8 = /^[1-9]\d*$/u;
|
|
@@ -16139,7 +15835,7 @@ function copyNames(dir, issue) {
|
|
|
16139
15835
|
}
|
|
16140
15836
|
const prefix = `${boardId(issue)}-`;
|
|
16141
15837
|
const notes = notesFileName(issue);
|
|
16142
|
-
return names.filter((name2) => name2.startsWith(prefix) && name2.endsWith(SPEC_EXTENSION) && name2 !== notes).filter((name2) => name2.length > prefix.length + SPEC_EXTENSION.length).filter((name2) => statSync8(
|
|
15838
|
+
return names.filter((name2) => name2.startsWith(prefix) && name2.endsWith(SPEC_EXTENSION) && name2 !== notes).filter((name2) => name2.length > prefix.length + SPEC_EXTENSION.length).filter((name2) => statSync8(join31(dir, name2)).isFile()).sort();
|
|
16143
15839
|
}
|
|
16144
15840
|
function findSavedCopy(root, specsDir, issue) {
|
|
16145
15841
|
const names = copyNames(resolve9(root, specsDir), issue);
|
|
@@ -16149,11 +15845,11 @@ function findSavedCopy(root, specsDir, issue) {
|
|
|
16149
15845
|
if (names.length > 1) {
|
|
16150
15846
|
throw new CommandExit(1, [
|
|
16151
15847
|
`\u274C Issue #${String(issue)} has ${String(names.length)} saved copies under ${specsDir}; remove the stale one:`,
|
|
16152
|
-
...names.map((name2) => ` ${
|
|
15848
|
+
...names.map((name2) => ` ${join31(specsDir, name2)}`)
|
|
16153
15849
|
].join(`
|
|
16154
15850
|
`));
|
|
16155
15851
|
}
|
|
16156
|
-
const path =
|
|
15852
|
+
const path = join31(specsDir, only);
|
|
16157
15853
|
return { path, absolute: resolve9(root, path) };
|
|
16158
15854
|
}
|
|
16159
15855
|
function liveText(live) {
|
|
@@ -16202,7 +15898,7 @@ async function readReferences(absolute, issue, verify, stamp) {
|
|
|
16202
15898
|
return rows.map((row2) => checkedRef(row2, row2.stamp));
|
|
16203
15899
|
}
|
|
16204
15900
|
const once2 = memoiseVerifier(verify);
|
|
16205
|
-
const before = await readRefsText({ copy:
|
|
15901
|
+
const before = await readRefsText({ copy: readFileSync22(absolute, "utf8"), issue, verify: once2 });
|
|
16206
15902
|
const after = await restampCopyRefs({ path: absolute, issue, verify: once2 });
|
|
16207
15903
|
return before.rows.map((row2, index) => checkedRef(row2, after.rows[index]?.stamp ?? null));
|
|
16208
15904
|
}
|
|
@@ -16555,8 +16251,8 @@ function createIssueCreateCommand(seams = DEFAULT_ISSUE_SEAMS) {
|
|
|
16555
16251
|
var create_default = createIssueCreateCommand();
|
|
16556
16252
|
|
|
16557
16253
|
// src/commands/issue/edit-run.ts
|
|
16558
|
-
import { existsSync as
|
|
16559
|
-
import { join as
|
|
16254
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "fs";
|
|
16255
|
+
import { join as join33 } from "path";
|
|
16560
16256
|
|
|
16561
16257
|
// src/board/issue-edit-body.ts
|
|
16562
16258
|
var TRAILING_WHITESPACE = /\s+$/u;
|
|
@@ -16611,7 +16307,7 @@ function originalPartHolds(before, after, block) {
|
|
|
16611
16307
|
|
|
16612
16308
|
// src/board/issue-edit-state.ts
|
|
16613
16309
|
import { readdirSync as readdirSync6, statSync as statSync9 } from "fs";
|
|
16614
|
-
import { join as
|
|
16310
|
+
import { join as join32, resolve as resolve10 } from "path";
|
|
16615
16311
|
function isClaimed(labels) {
|
|
16616
16312
|
return labels.includes(CLAIMED_LABEL) || labels.includes(IN_DEVELOPMENT_LABEL);
|
|
16617
16313
|
}
|
|
@@ -16684,7 +16380,7 @@ function findSavedCopies(root, specsDir, issue) {
|
|
|
16684
16380
|
return [];
|
|
16685
16381
|
throw error;
|
|
16686
16382
|
}
|
|
16687
|
-
return names.filter((name2) => isSavedCopyName(name2, issue)).filter((name2) => statSync9(
|
|
16383
|
+
return names.filter((name2) => isSavedCopyName(name2, issue)).filter((name2) => statSync9(join32(dir, name2)).isFile()).sort().map((name2) => join32(specsDir, name2));
|
|
16688
16384
|
}
|
|
16689
16385
|
|
|
16690
16386
|
// src/board/issue-edit-text.ts
|
|
@@ -16708,7 +16404,7 @@ function requireEditText(input) {
|
|
|
16708
16404
|
var EDIT_USAGE = "rafa issue edit <n> (--append-file=<file> | --append=<text>) --reason=<text>" + " [--while-in-development] | (--replace-file=<file> [--title=<text>] | --title=<text>) [--dry-run]";
|
|
16709
16405
|
var EDIT_REFUSAL_EXIT = TRUST_REFUSAL_EXIT;
|
|
16710
16406
|
var EDIT_CONFLICT_EXIT = 1;
|
|
16711
|
-
var EDIT_SCRATCH_DIR =
|
|
16407
|
+
var EDIT_SCRATCH_DIR = join33(".rafa", "scratch");
|
|
16712
16408
|
var STDIN_PATH2 = "-";
|
|
16713
16409
|
var ISSUE_NUMBER9 = /^[1-9]\d*$/u;
|
|
16714
16410
|
var TRAILING_WHITESPACE2 = /\s+$/u;
|
|
@@ -16957,20 +16653,20 @@ function writeHeld(found, planned, reread) {
|
|
|
16957
16653
|
}
|
|
16958
16654
|
function conflictPaths(issue, stamp, attempt4) {
|
|
16959
16655
|
const suffix = attempt4 === 1 ? "" : `-${String(attempt4)}`;
|
|
16960
|
-
const name2 = (side) =>
|
|
16656
|
+
const name2 = (side) => join33(EDIT_SCRATCH_DIR, `${boardId(issue)}-edit-${side}-${stamp}${suffix}.md`);
|
|
16961
16657
|
return { before: name2("before"), after: name2("after") };
|
|
16962
16658
|
}
|
|
16963
16659
|
function saveConflictBodies(root, issue, now, before, after) {
|
|
16964
|
-
mkdirSync9(
|
|
16660
|
+
mkdirSync9(join33(root, EDIT_SCRATCH_DIR), { recursive: true });
|
|
16965
16661
|
const stamp = fileStamp(now);
|
|
16966
16662
|
let attempt4 = 1;
|
|
16967
16663
|
let paths = conflictPaths(issue, stamp, attempt4);
|
|
16968
|
-
while (
|
|
16664
|
+
while (existsSync11(join33(root, paths.before)) || existsSync11(join33(root, paths.after))) {
|
|
16969
16665
|
attempt4 += 1;
|
|
16970
16666
|
paths = conflictPaths(issue, stamp, attempt4);
|
|
16971
16667
|
}
|
|
16972
|
-
writeFileSync9(
|
|
16973
|
-
writeFileSync9(
|
|
16668
|
+
writeFileSync9(join33(root, paths.before), before, { flag: "wx" });
|
|
16669
|
+
writeFileSync9(join33(root, paths.after), after, { flag: "wx" });
|
|
16974
16670
|
return paths;
|
|
16975
16671
|
}
|
|
16976
16672
|
function heldOutcome(request, state) {
|
|
@@ -17496,7 +17192,7 @@ var wrapped = wrapPhaseZeroCommand({
|
|
|
17496
17192
|
subject: "loop",
|
|
17497
17193
|
action: "start",
|
|
17498
17194
|
summary: "run a plan task by task, then wrap up, open the PR and wait for CI",
|
|
17499
|
-
description: "Walks the tracker of a plan one task at a time, each in a Claude Code session whose work" + " is committed once it exits, and retries blocked tasks first. After the last task a wrap-up" + " session promotes findings, syncs with main, pushes and opens or updates the PR, and the loop" + " then waits on its checks, spending repair sessions on a red or conflicting PR. With no" + " `--plan` it runs `PLAN.md` in `plan.dir`, `.rafa/plans` unless the config names another, or" + " `PLAN.md` at the project root when that one does not exist. Before any session it checks the" + " prerequisites the config and the plan's `PREREQUISITES-<stub>.md` name, halting when a required" + " one fails and naming each failed optional one known-missing in every task prompt, and warns once" + " for each migration the effort store holds that this rafa does not know and that is additive. It" + " refuses to start while `RAFA_EFFORT_DIR` is set, since a loop records to the project's own" + " store. Started on" + " `main` or `master` it offers to create the plan's `feat/<stub>` from the latest" + " `origin/<base>` and run there, `--create-branch` answering that without asking, and refuses" + " the run when the offer is not taken. `--as-worktree` runs the plan in a worktree of its own on" + " that branch instead, leaving the main checkout as it is, and is refused beside" + " `--create-branch`. Each run writes its session record to `.rafa/runs/<session-id>.json`:" + " the plan, the branch, the pid, the start, the state and the running task, and under `--roadmap`" + " the hop away, when one is. It refuses a plan whose" + " record names another branch, and a plan a session is still running. `rafa loop stop`, `pause`," + " `resume`, `status` and `list` reach the run through that record. A run holds its terminal: until" + " phase 6 it refuses `--detached`. With `--runtime` the whole run goes on in that installed rafa," + " never in a `src/` directory.",
|
|
17195
|
+
description: "Walks the tracker of a plan one task at a time, each in a Claude Code session whose work" + " is committed once it exits, and retries blocked tasks first. After the last task a wrap-up" + " session promotes findings, syncs with main, pushes and opens or updates the PR, and the loop" + " then waits on its checks, spending repair sessions on a red or conflicting PR. With no" + " `--plan` it runs `PLAN.md` in `plan.dir`, `.rafa/plans` unless the config names another, or" + " `PLAN.md` at the project root when that one does not exist. Before any session it checks the" + " prerequisites the config and the plan's `PREREQUISITES-<stub>.md` name, halting when a required" + " one fails and naming each failed optional one known-missing in every task prompt, and warns once" + " for each migration the effort store holds that this rafa does not know and that is additive. It" + " refuses to start while `RAFA_EFFORT_DIR` is set, since a loop records to the project's own" + " store. Started on" + " `main` or `master` it offers to create the plan's `feat/<stub>` from the latest" + " `origin/<base>` and run there, `--create-branch` answering that without asking, and refuses" + " the run when the offer is not taken. `--as-worktree` runs the plan in a worktree of its own on" + " that branch instead, leaving the main checkout as it is, and is refused beside" + " `--create-branch`. Each run writes its session record to `.rafa/runs/<session-id>.json`:" + " the plan, the branch, the pid, the start, the state and the running task, and under `--roadmap`" + " the hop away, when one is. It refuses a plan whose" + " record names another branch, and a plan a session is still running. `rafa loop stop`, `pause`," + " `resume`, `status` and `list` reach the run through that record. With `--retry` or" + " `loop.retries` it goes back into its loop instead of stopping, at most that many times in a row," + " after a red suite step, a task session that exited nonzero, or one that left neither a report nor" + " a commit; a later task done, neither the stopped one nor a repair, starts the count over. With `--continue` a stop that would end the run is handed to a decision instead: retry the" + " task with a new approach, stop with exit code 20, jump over it or defer it until a later task is" + " done; a run left with only passed-over tasks ends with exit code 22 and no wrap-up unless" + " `--force-wrap-up`, and under `--output=json` a decision the line does not name ends the run with" + " exit code 21 and the decision prompt. A run holds its terminal: until" + " phase 6 it refuses `--detached`. With `--runtime` the whole run goes on in that installed rafa," + " never in a `src/` directory.",
|
|
17500
17196
|
args: [],
|
|
17501
17197
|
flags: [
|
|
17502
17198
|
{
|
|
@@ -17542,6 +17238,36 @@ var wrapped = wrapPhaseZeroCommand({
|
|
|
17542
17238
|
type: "number",
|
|
17543
17239
|
default: DEFAULT_CI_ATTEMPTS
|
|
17544
17240
|
},
|
|
17241
|
+
{
|
|
17242
|
+
name: "retry",
|
|
17243
|
+
description: "Goes back into the loop instead of stopping, at most this many times in a row, 1 to 3," + " after a red suite step, a task session that exited nonzero but not on its budget, or one that" + " left neither a report nor a commit. The count starts over once a later task is done, neither" + " the stopped one nor a repair. A report that blocks its task, a refused commit, a moved" + " checkout and an interrupt still stop the run. Outranks `loop.retries` in" + " `.rafa/config.yaml`, `false` unless the config names a count; any other value is refused" + " before the run starts.",
|
|
17244
|
+
type: "number"
|
|
17245
|
+
},
|
|
17246
|
+
{
|
|
17247
|
+
name: "continue",
|
|
17248
|
+
description: "Hands a stop that would end the run to a decision instead: a report that holds its task at" + " once, and a retry-safe stop once its retries are spent. One read-only decision session picks" + " `retry` (with a new approach), `stop`, `jump` (pass the task over this run) or `defer` (pass" + " it over until a later task is done), by the bundled criteria and `loop.continue.criteria`." + " The retries are `loop.retriesOnContinue` unless `--retry` names a count.",
|
|
17249
|
+
type: "boolean"
|
|
17250
|
+
},
|
|
17251
|
+
{
|
|
17252
|
+
name: "decide",
|
|
17253
|
+
description: "Names the decision on the line, `retry`, `stop`, `jump` or `defer`, applied once to the first" + " decision point the run meets, so no decision session is spawned for it. Needs `--continue`.",
|
|
17254
|
+
type: "string"
|
|
17255
|
+
},
|
|
17256
|
+
{
|
|
17257
|
+
name: "approach",
|
|
17258
|
+
description: "The new approach a `--decide=retry` hands the task's next session; required by it and" + " read beside nothing else.",
|
|
17259
|
+
type: "string"
|
|
17260
|
+
},
|
|
17261
|
+
{
|
|
17262
|
+
name: "after",
|
|
17263
|
+
description: "The tracker line, counted from 1, of the task a `--decide=defer` waits on; required by it" + " and read beside nothing else.",
|
|
17264
|
+
type: "number"
|
|
17265
|
+
},
|
|
17266
|
+
{
|
|
17267
|
+
name: "force-wrap-up",
|
|
17268
|
+
description: "Wraps up a `--continue` run left with only passed-over tasks anyway, as a draft pull request" + " listing them, once the pre-wrap-up suite step finds no more new failures than" + " `loop.forceWrapUp.maxNewFailures` tolerates. Needs `--continue`.",
|
|
17269
|
+
type: "boolean"
|
|
17270
|
+
},
|
|
17545
17271
|
{
|
|
17546
17272
|
name: "create-branch",
|
|
17547
17273
|
description: "On `main` or `master`, creates `feat/<plan-stub>` from the latest `origin/<base>`" + " and runs the plan there without asking, or switches to that branch when it already" + " exists. Refuses rather than move when a tracked file is modified, the fetch fails or the" + " base has diverged from its remote.",
|
|
@@ -17588,7 +17314,7 @@ var wrapped = wrapPhaseZeroCommand({
|
|
|
17588
17314
|
outputs: ["text", "json", "events"],
|
|
17589
17315
|
spends: {
|
|
17590
17316
|
when: "always",
|
|
17591
|
-
what: "one session per task, one for the wrap-up and up to `loop.wrapUp.retries` more when it opens no pull request,
|
|
17317
|
+
what: "one session per task, one for the wrap-up and up to `loop.wrapUp.retries` more when it opens no pull request," + " repair sessions while CI is red, the sessions of up to `--retry` (`loop.retries`) more passes of the loop" + " in a row after the stops it retries, and under `--continue` one read-only decision session per decision"
|
|
17592
17318
|
}
|
|
17593
17319
|
}, start);
|
|
17594
17320
|
var loopStart = Object.freeze({
|
|
@@ -18829,7 +18555,7 @@ var wrapped2 = wrapPhaseZeroCommand({
|
|
|
18829
18555
|
var create_default2 = endingWith(wrapped2);
|
|
18830
18556
|
|
|
18831
18557
|
// src/commands/plan/risk.ts
|
|
18832
|
-
import { readFileSync as
|
|
18558
|
+
import { readFileSync as readFileSync23 } from "fs";
|
|
18833
18559
|
import { resolve as resolve11 } from "path";
|
|
18834
18560
|
var COMMAND6 = "rafa plan risk";
|
|
18835
18561
|
var USAGE34 = "rafa plan risk [<plan>] [--strict]";
|
|
@@ -18857,7 +18583,7 @@ function strictRefusal(report3) {
|
|
|
18857
18583
|
}
|
|
18858
18584
|
async function readRisk(path, project, config, context, seams) {
|
|
18859
18585
|
const makeRunners = seams.runners ?? spawningRunners;
|
|
18860
|
-
return assessPlanRisk({ path, text:
|
|
18586
|
+
return assessPlanRisk({ path, text: readFileSync23(path, "utf8") }, {
|
|
18861
18587
|
repoRoot: project.root,
|
|
18862
18588
|
home: project.home,
|
|
18863
18589
|
settingSources: config.settingSources,
|
|
@@ -18940,8 +18666,8 @@ function createPlanRiskCommand(seams = {}) {
|
|
|
18940
18666
|
var risk_default = createPlanRiskCommand();
|
|
18941
18667
|
|
|
18942
18668
|
// src/commands/plan/show.ts
|
|
18943
|
-
import { readFileSync as
|
|
18944
|
-
import { join as
|
|
18669
|
+
import { readFileSync as readFileSync24 } from "fs";
|
|
18670
|
+
import { join as join34 } from "path";
|
|
18945
18671
|
var USAGE35 = "rafa plan show <stub> [--tracker]";
|
|
18946
18672
|
var COMMAND7 = "rafa plan show";
|
|
18947
18673
|
function readTrackerFlag(value) {
|
|
@@ -18959,10 +18685,10 @@ function showPlan(plans, stub, tracker) {
|
|
|
18959
18685
|
throw new CommandExit(1, `\u274C "${stub}" is no plan stub: a stub is letters, digits, ".", "_" and "-"`);
|
|
18960
18686
|
}
|
|
18961
18687
|
const name2 = planFileName(stub, tracker);
|
|
18962
|
-
const file =
|
|
18688
|
+
const file = join34(plans.path, name2);
|
|
18963
18689
|
if (!isFile(file))
|
|
18964
|
-
throw new CommandExit(1, missingText(stub, tracker,
|
|
18965
|
-
const model = parsePlan(
|
|
18690
|
+
throw new CommandExit(1, missingText(stub, tracker, join34(plans.label, name2)));
|
|
18691
|
+
const model = parsePlan(readFileSync24(file, "utf8"));
|
|
18966
18692
|
const { header } = model;
|
|
18967
18693
|
return {
|
|
18968
18694
|
stub,
|
|
@@ -18985,7 +18711,7 @@ function taskLine(task) {
|
|
|
18985
18711
|
return ` ${checkbox(task.status)} ${task.text}`;
|
|
18986
18712
|
}
|
|
18987
18713
|
function renderShownPlan(shown, dirLabel) {
|
|
18988
|
-
const relative9 =
|
|
18714
|
+
const relative9 = join34(dirLabel, planFileName(shown.stub, shown.tracker));
|
|
18989
18715
|
const fileLabel = shown.tracker ? "Tracker" : "File";
|
|
18990
18716
|
const lines = [`Plan: ${shown.stub}`, `${fileLabel}: ${relative9}`];
|
|
18991
18717
|
if (shown.header.issue !== null)
|
|
@@ -19981,7 +19707,7 @@ async function refreshProjectAfterMerge(options) {
|
|
|
19981
19707
|
|
|
19982
19708
|
// src/commands/pr/merge-loop-worktree.ts
|
|
19983
19709
|
import { copyFileSync as copyFileSync3, mkdirSync as mkdirSync10, realpathSync as realpathSync3, statSync as statSync10 } from "fs";
|
|
19984
|
-
import { dirname as
|
|
19710
|
+
import { dirname as dirname9, isAbsolute as isAbsolute6, join as join35, relative as relative9, resolve as resolve12, sep as sep4 } from "path";
|
|
19985
19711
|
var REFUSAL_PREFIX = "rafa pr merge refuses";
|
|
19986
19712
|
var INDENT4 = " ";
|
|
19987
19713
|
var LIVE_STATES = new Set(["running", "paused"]);
|
|
@@ -19991,7 +19717,7 @@ function defaultLoopWorktreeSeams(mainCheckout) {
|
|
|
19991
19717
|
gitAt: createGitRunner,
|
|
19992
19718
|
modifiedAt: (path) => statSync10(path, { throwIfNoEntry: false })?.mtime ?? null,
|
|
19993
19719
|
copyFile: (from, to) => {
|
|
19994
|
-
mkdirSync10(
|
|
19720
|
+
mkdirSync10(dirname9(to), { recursive: true });
|
|
19995
19721
|
copyFileSync3(from, to);
|
|
19996
19722
|
},
|
|
19997
19723
|
realPath: (path) => {
|
|
@@ -20026,7 +19752,7 @@ function freeLoopWorktree(seams, reading, holder) {
|
|
|
20026
19752
|
const files = [];
|
|
20027
19753
|
for (const name2 of planFileNames(holder.stub)) {
|
|
20028
19754
|
const from = resolve12(holder.path, reading.planDir, name2);
|
|
20029
|
-
const to =
|
|
19755
|
+
const to = join35(into, name2);
|
|
20030
19756
|
try {
|
|
20031
19757
|
files.push({ name: name2, from, to, outcome: copyPlanFile(seams, from, to) });
|
|
20032
19758
|
} catch (error) {
|
|
@@ -20281,7 +20007,7 @@ function workflowNamesBase(workflowText, base) {
|
|
|
20281
20007
|
return readWorkflow(document, base) !== false;
|
|
20282
20008
|
}
|
|
20283
20009
|
function readWorkflow(document, base) {
|
|
20284
|
-
if (!
|
|
20010
|
+
if (!isPlainObject(document) || !("on" in document))
|
|
20285
20011
|
return UNKNOWN;
|
|
20286
20012
|
const on = document.on;
|
|
20287
20013
|
if (typeof on === "string")
|
|
@@ -20291,7 +20017,7 @@ function readWorkflow(document, base) {
|
|
|
20291
20017
|
return UNKNOWN;
|
|
20292
20018
|
return on.includes(PULL_REQUEST_EVENT);
|
|
20293
20019
|
}
|
|
20294
|
-
if (!
|
|
20020
|
+
if (!isPlainObject(on))
|
|
20295
20021
|
return UNKNOWN;
|
|
20296
20022
|
if (!(PULL_REQUEST_EVENT in on))
|
|
20297
20023
|
return false;
|
|
@@ -20300,7 +20026,7 @@ function readWorkflow(document, base) {
|
|
|
20300
20026
|
function readPullRequestTrigger(trigger, base) {
|
|
20301
20027
|
if (trigger === null || trigger === undefined)
|
|
20302
20028
|
return true;
|
|
20303
|
-
if (!
|
|
20029
|
+
if (!isPlainObject(trigger))
|
|
20304
20030
|
return UNKNOWN;
|
|
20305
20031
|
const branches = trigger.branches;
|
|
20306
20032
|
const ignored = trigger["branches-ignore"];
|
|
@@ -20401,7 +20127,7 @@ function regexSourceOf(pattern) {
|
|
|
20401
20127
|
function escapeRegex(char) {
|
|
20402
20128
|
return char.replace(REGEX_SPECIAL, "\\$&");
|
|
20403
20129
|
}
|
|
20404
|
-
function
|
|
20130
|
+
function isPlainObject(value) {
|
|
20405
20131
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20406
20132
|
}
|
|
20407
20133
|
|
|
@@ -20995,7 +20721,7 @@ var FOLLOW_UP_TASKS = Object.freeze({
|
|
|
20995
20721
|
"ci-test": "A test failed. Read the excerpt below, reproduce the named test" + " locally, and fix the implementation rather than the assertion unless the" + " assertion is itself wrong. Run the gates and push.",
|
|
20996
20722
|
"ci-other": "A step nothing recognised failed. Read the excerpt below, work out" + " from the step name what that job does, and fix it; there is no pinned plan" + " for this class, so nothing has been assumed about the fix."
|
|
20997
20723
|
});
|
|
20998
|
-
var
|
|
20724
|
+
var MIN_FENCE_LENGTH2 = 3;
|
|
20999
20725
|
function isUsableCap(value) {
|
|
21000
20726
|
return value !== undefined && Number.isInteger(value) && value > 0;
|
|
21001
20727
|
}
|
|
@@ -21010,7 +20736,7 @@ function excerptLines(evidence, maxLines) {
|
|
|
21010
20736
|
}
|
|
21011
20737
|
function fencedBlock(body, language) {
|
|
21012
20738
|
const runs = Array.from(body.matchAll(/`+/g), (run) => run[0].length);
|
|
21013
|
-
const fence = "`".repeat(Math.max(
|
|
20739
|
+
const fence = "`".repeat(Math.max(MIN_FENCE_LENGTH2, ...runs.map((length) => length + 1)));
|
|
21014
20740
|
const text = body.endsWith(`
|
|
21015
20741
|
`) || body === "" ? body : `${body}
|
|
21016
20742
|
`;
|
|
@@ -21110,7 +20836,7 @@ function findTriageComment(comments) {
|
|
|
21110
20836
|
function read(value) {
|
|
21111
20837
|
return { value, problem: null };
|
|
21112
20838
|
}
|
|
21113
|
-
function
|
|
20839
|
+
function absent3() {
|
|
21114
20840
|
return { value: null, problem: null };
|
|
21115
20841
|
}
|
|
21116
20842
|
function unusable(key, value, expected) {
|
|
@@ -21119,7 +20845,7 @@ function unusable(key, value, expected) {
|
|
|
21119
20845
|
function readText4(fields, key) {
|
|
21120
20846
|
const value = fields[key];
|
|
21121
20847
|
if (value === undefined)
|
|
21122
|
-
return
|
|
20848
|
+
return absent3();
|
|
21123
20849
|
if (typeof value !== "string")
|
|
21124
20850
|
return unusable(key, value, `text; write it quoted, as ${key}: "..."`);
|
|
21125
20851
|
const trimmed = value.trim();
|
|
@@ -21128,19 +20854,19 @@ function readText4(fields, key) {
|
|
|
21128
20854
|
function readBoolean(fields, key) {
|
|
21129
20855
|
const value = fields[key];
|
|
21130
20856
|
if (value === undefined)
|
|
21131
|
-
return
|
|
20857
|
+
return absent3();
|
|
21132
20858
|
return typeof value === "boolean" ? read(value) : unusable(key, value, "true or false");
|
|
21133
20859
|
}
|
|
21134
20860
|
function readCount(fields, key) {
|
|
21135
20861
|
const value = fields[key];
|
|
21136
20862
|
if (value === undefined)
|
|
21137
|
-
return
|
|
20863
|
+
return absent3();
|
|
21138
20864
|
return typeof value === "number" && Number.isInteger(value) && value >= 0 ? read(value) : unusable(key, value, "a whole number from 0");
|
|
21139
20865
|
}
|
|
21140
20866
|
function readPaths(fields, key) {
|
|
21141
20867
|
const value = fields[key];
|
|
21142
20868
|
if (value === undefined)
|
|
21143
|
-
return
|
|
20869
|
+
return absent3();
|
|
21144
20870
|
if (!Array.isArray(value))
|
|
21145
20871
|
return unusable(key, value, "a list of quoted paths");
|
|
21146
20872
|
const paths = value.filter((item) => typeof item === "string" && item.trim() !== "");
|
|
@@ -22340,10 +22066,10 @@ function withTaskBudget(plan2, usd) {
|
|
|
22340
22066
|
}
|
|
22341
22067
|
|
|
22342
22068
|
// src/pr/plans/load.ts
|
|
22343
|
-
import { existsSync as
|
|
22344
|
-
import { dirname as
|
|
22345
|
-
import { fileURLToPath as
|
|
22346
|
-
var
|
|
22069
|
+
import { existsSync as existsSync12, readFileSync as readFileSync25 } from "fs";
|
|
22070
|
+
import { dirname as dirname10, join as join36 } from "path";
|
|
22071
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
22072
|
+
var MODULE_DIR2 = dirname10(fileURLToPath2(import.meta.url));
|
|
22347
22073
|
var PINNED_PLANS_DIRNAME = "plans";
|
|
22348
22074
|
var PINNED_PLAN_CLASSES = Object.freeze([
|
|
22349
22075
|
...SIMPLE_TRIAGE_CLASSES,
|
|
@@ -22358,22 +22084,22 @@ function hasPinnedPlan(triageClass) {
|
|
|
22358
22084
|
function pinnedPlanCandidates(moduleDir, triageClass) {
|
|
22359
22085
|
const name2 = pinnedPlanFileName(triageClass);
|
|
22360
22086
|
return [
|
|
22361
|
-
|
|
22362
|
-
|
|
22087
|
+
join36(moduleDir, PINNED_PLANS_DIRNAME, name2),
|
|
22088
|
+
join36(moduleDir, name2)
|
|
22363
22089
|
];
|
|
22364
22090
|
}
|
|
22365
22091
|
function readPinnedPlan(triageClass, lookup = {}) {
|
|
22366
22092
|
if (!hasPinnedPlan(triageClass)) {
|
|
22367
22093
|
throw new Error(`No pinned resolve plan ships for ${triageClass}; ` + `one ships for ${PINNED_PLAN_CLASSES.join(", ")}`);
|
|
22368
22094
|
}
|
|
22369
|
-
const candidates = pinnedPlanCandidates(lookup.moduleDir ??
|
|
22370
|
-
const found = candidates.find((candidate) =>
|
|
22095
|
+
const candidates = pinnedPlanCandidates(lookup.moduleDir ?? MODULE_DIR2, triageClass);
|
|
22096
|
+
const found = candidates.find((candidate) => existsSync12(candidate));
|
|
22371
22097
|
if (found === undefined) {
|
|
22372
22098
|
throw new Error(`The pinned resolve plan for ${triageClass} is missing: ` + `no file at ${candidates.join(" or ")}`);
|
|
22373
22099
|
}
|
|
22374
|
-
return
|
|
22100
|
+
return readFileSync25(found, "utf8");
|
|
22375
22101
|
}
|
|
22376
|
-
var
|
|
22102
|
+
var SLOT_PATTERN = /\{[A-Z][A-Z0-9_]*\}/g;
|
|
22377
22103
|
var CONFLICT_SENTENCE_SLOT = "CONFLICT_SENTENCE";
|
|
22378
22104
|
var CONFLICT_FILES_SLOT = "CONFLICT_FILES";
|
|
22379
22105
|
var NO_CONFLICT_FILES = "the paths `git status` reports as conflicted";
|
|
@@ -22383,7 +22109,7 @@ var FAILING_LOG_EXCERPT_LINES = FOLLOW_UP_EXCERPT_LINES;
|
|
|
22383
22109
|
var NO_FAILING_LOG = "No failing-job log was carried into this plan. Read it yourself with" + " `gh run view <run-id> --log-failed` before changing anything, and say that" + " the excerpt was missing rather than guessing what failed.";
|
|
22384
22110
|
function fillPinnedPlan(template, values) {
|
|
22385
22111
|
const missing = [];
|
|
22386
|
-
const filled = template.replaceAll(
|
|
22112
|
+
const filled = template.replaceAll(SLOT_PATTERN, (token) => {
|
|
22387
22113
|
const name2 = token.slice(1, -1);
|
|
22388
22114
|
const value = values[name2];
|
|
22389
22115
|
if (value === undefined) {
|
|
@@ -22514,19 +22240,19 @@ function readAttemptRepeat(input) {
|
|
|
22514
22240
|
|
|
22515
22241
|
// src/commands/pr/resolve-loop.ts
|
|
22516
22242
|
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync10 } from "fs";
|
|
22517
|
-
import { join as
|
|
22518
|
-
var RESOLVE_SUBDIR =
|
|
22243
|
+
import { join as join37 } from "path";
|
|
22244
|
+
var RESOLVE_SUBDIR = join37(".rafa", "resolve");
|
|
22519
22245
|
var RUN_PREFIX = "pr-";
|
|
22520
22246
|
var ATTEMPT_PREFIX = "attempt-";
|
|
22521
22247
|
var LOOP_WORDS = Object.freeze(["loop", "start"]);
|
|
22522
22248
|
var CHILD_OUTPUT = "text";
|
|
22523
22249
|
function resolveRunDir(home, number, attempt4) {
|
|
22524
|
-
return
|
|
22250
|
+
return join37(home, RESOLVE_SUBDIR, `${RUN_PREFIX}${number}`, `${ATTEMPT_PREFIX}${attempt4}`);
|
|
22525
22251
|
}
|
|
22526
22252
|
function writeResolvePlan(write) {
|
|
22527
22253
|
const dir = resolveRunDir(write.home, write.number, write.attempt);
|
|
22528
22254
|
mkdirSync11(dir, { recursive: true });
|
|
22529
|
-
const path =
|
|
22255
|
+
const path = join37(dir, pinnedPlanFileName(write.triageClass));
|
|
22530
22256
|
writeFileSync10(path, write.plan, "utf8");
|
|
22531
22257
|
return path;
|
|
22532
22258
|
}
|
|
@@ -22567,8 +22293,8 @@ async function runResolveLoop(run, seams = {}) {
|
|
|
22567
22293
|
}
|
|
22568
22294
|
|
|
22569
22295
|
// src/pr/triage/version-convert.ts
|
|
22570
|
-
import { mkdirSync as mkdirSync12, readFileSync as
|
|
22571
|
-
import { dirname as
|
|
22296
|
+
import { mkdirSync as mkdirSync12, readFileSync as readFileSync26, writeFileSync as writeFileSync11 } from "fs";
|
|
22297
|
+
import { dirname as dirname11, join as join38, posix as posix2 } from "path";
|
|
22572
22298
|
var FALLBACK_PLAN_PREFIX = "pr-";
|
|
22573
22299
|
var UNUSABLE_PLAN_CHARACTERS = /[^A-Za-z0-9._-]+/g;
|
|
22574
22300
|
var UNUSABLE_PLAN_START = /^[^A-Za-z0-9]+/;
|
|
@@ -22680,7 +22406,7 @@ function planConversion(input, problems) {
|
|
|
22680
22406
|
}
|
|
22681
22407
|
let branchVersionText;
|
|
22682
22408
|
try {
|
|
22683
|
-
branchVersionText =
|
|
22409
|
+
branchVersionText = readFileSync26(join38(input.worktree, settings.releaseVersionFile), "utf8");
|
|
22684
22410
|
} catch (error) {
|
|
22685
22411
|
return refused2(`${settings.releaseVersionFile} could not be read in the worktree: ${messageOf(error)}`, problems);
|
|
22686
22412
|
}
|
|
@@ -22706,9 +22432,9 @@ function writeConversion(input, plan2) {
|
|
|
22706
22432
|
[input.settings.releaseChangelog, plan2.changelogText]
|
|
22707
22433
|
];
|
|
22708
22434
|
for (const [path, text] of writes) {
|
|
22709
|
-
const target =
|
|
22435
|
+
const target = join38(input.worktree, path);
|
|
22710
22436
|
try {
|
|
22711
|
-
mkdirSync12(
|
|
22437
|
+
mkdirSync12(dirname11(target), { recursive: true });
|
|
22712
22438
|
writeFileSync11(target, text);
|
|
22713
22439
|
} catch (error) {
|
|
22714
22440
|
return `${path} could not be written in the worktree, which may hold part of the conversion: ${messageOf(error)}`;
|
|
@@ -23707,9 +23433,9 @@ function tagSettle(worktree, mode, delivered) {
|
|
|
23707
23433
|
}
|
|
23708
23434
|
|
|
23709
23435
|
// src/release/settle-worktree.ts
|
|
23710
|
-
import { existsSync as
|
|
23436
|
+
import { existsSync as existsSync13, mkdtempSync as mkdtempSync2, realpathSync as realpathSync4, rmSync as rmSync3 } from "fs";
|
|
23711
23437
|
import { tmpdir as tmpdir2 } from "os";
|
|
23712
|
-
import { join as
|
|
23438
|
+
import { join as join39 } from "path";
|
|
23713
23439
|
var SETTLE_SCRATCH_PREFIX = "rafa-settle-";
|
|
23714
23440
|
var WORKTREE_DIRECTORY = "base";
|
|
23715
23441
|
function removeScratch(git, scratch, path) {
|
|
@@ -23726,14 +23452,14 @@ function removeScratch(git, scratch, path) {
|
|
|
23726
23452
|
problems.push(`the worktree record of ${path} could not be pruned: ${gitSaid(pruned)}`);
|
|
23727
23453
|
}
|
|
23728
23454
|
}
|
|
23729
|
-
if (problems.length === 0 &&
|
|
23455
|
+
if (problems.length === 0 && existsSync13(scratch)) {
|
|
23730
23456
|
problems.push(`the scratch directory ${scratch} is still there`);
|
|
23731
23457
|
}
|
|
23732
23458
|
return problems.length === 0 ? null : problems.join("; ");
|
|
23733
23459
|
}
|
|
23734
23460
|
function makeScratch(root) {
|
|
23735
23461
|
try {
|
|
23736
|
-
return realpathSync4(mkdtempSync2(
|
|
23462
|
+
return realpathSync4(mkdtempSync2(join39(root, SETTLE_SCRATCH_PREFIX)));
|
|
23737
23463
|
} catch (error) {
|
|
23738
23464
|
return { ok: false, problem: `no scratch directory could be made under ${root}: ${messageOf(error)}`, leftover: null };
|
|
23739
23465
|
}
|
|
@@ -23755,7 +23481,7 @@ function addWorktree(options) {
|
|
|
23755
23481
|
const scratch = makeScratch(options.scratchRoot ?? tmpdir2());
|
|
23756
23482
|
if (typeof scratch !== "string")
|
|
23757
23483
|
return scratch;
|
|
23758
|
-
const path =
|
|
23484
|
+
const path = join39(scratch, WORKTREE_DIRECTORY);
|
|
23759
23485
|
const added = git(["worktree", "add", "--detach", path, commit]);
|
|
23760
23486
|
if (!added.ok) {
|
|
23761
23487
|
return {
|
|
@@ -24144,8 +23870,8 @@ function createReleaseSettleCommand(seams = DEFAULT_RELEASE_SETTLE_SEAMS) {
|
|
|
24144
23870
|
var settle_default = createReleaseSettleCommand();
|
|
24145
23871
|
|
|
24146
23872
|
// src/commands/release/tag.ts
|
|
24147
|
-
import { readFileSync as
|
|
24148
|
-
import { join as
|
|
23873
|
+
import { readFileSync as readFileSync27 } from "fs";
|
|
23874
|
+
import { join as join40 } from "path";
|
|
24149
23875
|
|
|
24150
23876
|
// src/release/tag-push.ts
|
|
24151
23877
|
var LOCAL_REMOTE = ".";
|
|
@@ -24221,13 +23947,13 @@ function readBranch2(git) {
|
|
|
24221
23947
|
}
|
|
24222
23948
|
function textOf(path) {
|
|
24223
23949
|
try {
|
|
24224
|
-
return
|
|
23950
|
+
return readFileSync27(path, "utf8");
|
|
24225
23951
|
} catch {
|
|
24226
23952
|
return null;
|
|
24227
23953
|
}
|
|
24228
23954
|
}
|
|
24229
23955
|
function readVersion(root, configured) {
|
|
24230
|
-
const resolved =
|
|
23956
|
+
const resolved = join40(root, configured);
|
|
24231
23957
|
const text = textOf(resolved);
|
|
24232
23958
|
if (text === null) {
|
|
24233
23959
|
return {
|
|
@@ -24241,7 +23967,7 @@ function readVersion(root, configured) {
|
|
|
24241
23967
|
return version2 === null ? { path: configured, text, version: null, problem: `${resolved} declares no version this can read` } : { path: configured, text, version: version2, problem: null };
|
|
24242
23968
|
}
|
|
24243
23969
|
function readNewestRelease(root, configured) {
|
|
24244
|
-
const resolved =
|
|
23970
|
+
const resolved = join40(root, configured);
|
|
24245
23971
|
const text = textOf(resolved);
|
|
24246
23972
|
if (text === null) {
|
|
24247
23973
|
return { path: configured, version: null, problem: `the changelog could not be read at ${resolved}` };
|
|
@@ -24525,16 +24251,16 @@ var roadmap_default = createRoadmapCommand();
|
|
|
24525
24251
|
|
|
24526
24252
|
// src/commands/skill/backfill.ts
|
|
24527
24253
|
import { statSync as statSync12 } from "fs";
|
|
24528
|
-
import { join as
|
|
24254
|
+
import { join as join45, resolve as resolve15 } from "path";
|
|
24529
24255
|
|
|
24530
24256
|
// src/backfill/backup.ts
|
|
24531
|
-
import { copyFileSync as copyFileSync4, existsSync as
|
|
24532
|
-
import { dirname as
|
|
24257
|
+
import { copyFileSync as copyFileSync4, existsSync as existsSync14, mkdirSync as mkdirSync13 } from "fs";
|
|
24258
|
+
import { dirname as dirname12, isAbsolute as isAbsolute7, join as join42, relative as relative10, resolve as resolve13, sep as sep5 } from "path";
|
|
24533
24259
|
|
|
24534
24260
|
// src/backfill/proposal-file.ts
|
|
24535
|
-
import { readdirSync as readdirSync7, readFileSync as
|
|
24536
|
-
import { join as
|
|
24537
|
-
var BACKFILL_PATH =
|
|
24261
|
+
import { readdirSync as readdirSync7, readFileSync as readFileSync28 } from "fs";
|
|
24262
|
+
import { join as join41 } from "path";
|
|
24263
|
+
var BACKFILL_PATH = join41(".rafa", "backfill");
|
|
24538
24264
|
var PROPOSAL_FILE_PREFIX = "proposals-";
|
|
24539
24265
|
var PROPOSAL_FILE_EXTENSION = ".yaml";
|
|
24540
24266
|
var SHA256_PATTERN = /^[0-9a-f]{64}$/;
|
|
@@ -24560,7 +24286,7 @@ var PROPOSAL_FILE_HEADER = [
|
|
|
24560
24286
|
].join(`
|
|
24561
24287
|
`);
|
|
24562
24288
|
function proposalPath(dir, batch) {
|
|
24563
|
-
return
|
|
24289
|
+
return join41(dir, `${PROPOSAL_FILE_PREFIX}${String(batch).padStart(2, "0")}${PROPOSAL_FILE_EXTENSION}`);
|
|
24564
24290
|
}
|
|
24565
24291
|
function isProposalFileName(name2) {
|
|
24566
24292
|
return name2.startsWith(PROPOSAL_FILE_PREFIX) && name2.endsWith(PROPOSAL_FILE_EXTENSION);
|
|
@@ -24696,9 +24422,9 @@ function readProposalFiles(dir) {
|
|
|
24696
24422
|
return [];
|
|
24697
24423
|
}
|
|
24698
24424
|
return names.filter((name2) => isProposalFileName(name2)).sort((left, right) => left.localeCompare(right)).map((name2) => {
|
|
24699
|
-
const path =
|
|
24425
|
+
const path = join41(dir, name2);
|
|
24700
24426
|
try {
|
|
24701
|
-
return { path, result: parseProposalFile(
|
|
24427
|
+
return { path, result: parseProposalFile(readFileSync28(path, "utf8")) };
|
|
24702
24428
|
} catch (error) {
|
|
24703
24429
|
return { path, result: unreadable2(`the file cannot be read (${error instanceof Error ? error.message : String(error)})`) };
|
|
24704
24430
|
}
|
|
@@ -24706,10 +24432,10 @@ function readProposalFiles(dir) {
|
|
|
24706
24432
|
}
|
|
24707
24433
|
|
|
24708
24434
|
// src/backfill/backup.ts
|
|
24709
|
-
var BACKUP_PATH =
|
|
24435
|
+
var BACKUP_PATH = join42(BACKFILL_PATH, "backup");
|
|
24710
24436
|
var BACKUP_KINDS = ["copied", "kept", "tracked", "outside", "missing"];
|
|
24711
24437
|
function backupDirectory(base) {
|
|
24712
|
-
return
|
|
24438
|
+
return join42(base, BACKUP_PATH);
|
|
24713
24439
|
}
|
|
24714
24440
|
function isUnder(root, path) {
|
|
24715
24441
|
const step = relative10(resolve13(root), resolve13(path));
|
|
@@ -24718,7 +24444,7 @@ function isUnder(root, path) {
|
|
|
24718
24444
|
function backupPathFor(path, root, backupDir) {
|
|
24719
24445
|
if (!isUnder(root, path))
|
|
24720
24446
|
return null;
|
|
24721
|
-
return
|
|
24447
|
+
return join42(backupDir, relative10(resolve13(root), resolve13(path)));
|
|
24722
24448
|
}
|
|
24723
24449
|
function backupFile(path, options) {
|
|
24724
24450
|
if (options.repoRoot !== null && isUnder(options.repoRoot, path)) {
|
|
@@ -24727,11 +24453,11 @@ function backupFile(path, options) {
|
|
|
24727
24453
|
const backup = backupPathFor(path, options.root, options.backupDir);
|
|
24728
24454
|
if (backup === null)
|
|
24729
24455
|
return { path, kind: "outside", backup: null };
|
|
24730
|
-
if (!
|
|
24456
|
+
if (!existsSync14(path))
|
|
24731
24457
|
return { path, kind: "missing", backup: null };
|
|
24732
|
-
if (
|
|
24458
|
+
if (existsSync14(backup))
|
|
24733
24459
|
return { path, kind: "kept", backup };
|
|
24734
|
-
mkdirSync13(
|
|
24460
|
+
mkdirSync13(dirname12(backup), { recursive: true });
|
|
24735
24461
|
copyFileSync4(path, backup);
|
|
24736
24462
|
return { path, kind: "copied", backup };
|
|
24737
24463
|
}
|
|
@@ -24754,7 +24480,7 @@ function countBackups(results) {
|
|
|
24754
24480
|
}
|
|
24755
24481
|
|
|
24756
24482
|
// src/backfill/derive.ts
|
|
24757
|
-
import { readFileSync as
|
|
24483
|
+
import { readFileSync as readFileSync29, writeFileSync as writeFileSync12 } from "fs";
|
|
24758
24484
|
import { basename as basename7 } from "path";
|
|
24759
24485
|
var DERIVED_FIELDS = ["stack", "paths", "when_to_use"];
|
|
24760
24486
|
function renderWhenToUse(trigger, prevents) {
|
|
@@ -24880,7 +24606,7 @@ function planFile(entry, options) {
|
|
|
24880
24606
|
}
|
|
24881
24607
|
let original;
|
|
24882
24608
|
try {
|
|
24883
|
-
original =
|
|
24609
|
+
original = readFileSync29(entry.path, "utf8");
|
|
24884
24610
|
} catch (error) {
|
|
24885
24611
|
return inert(entry, "skipped", `the file cannot be read (${error instanceof Error ? error.message : String(error)})`);
|
|
24886
24612
|
}
|
|
@@ -24924,7 +24650,7 @@ function planDerivation(root, options) {
|
|
|
24924
24650
|
function applyFile(action, options) {
|
|
24925
24651
|
if (action.text === null || action.original === null)
|
|
24926
24652
|
return action;
|
|
24927
|
-
const current =
|
|
24653
|
+
const current = readFileSync29(action.path, "utf8");
|
|
24928
24654
|
if (current !== action.original) {
|
|
24929
24655
|
return {
|
|
24930
24656
|
...action,
|
|
@@ -24955,7 +24681,7 @@ function applyDerivation(plan2, options) {
|
|
|
24955
24681
|
}
|
|
24956
24682
|
|
|
24957
24683
|
// src/backfill/proposal-batch.ts
|
|
24958
|
-
import { readFileSync as
|
|
24684
|
+
import { readFileSync as readFileSync30 } from "fs";
|
|
24959
24685
|
import { relative as relative11 } from "path";
|
|
24960
24686
|
|
|
24961
24687
|
// src/demote/report.ts
|
|
@@ -25254,7 +24980,7 @@ function readCandidate(root, entry) {
|
|
|
25254
24980
|
return null;
|
|
25255
24981
|
let text;
|
|
25256
24982
|
try {
|
|
25257
|
-
text =
|
|
24983
|
+
text = readFileSync30(entry.path, "utf8");
|
|
25258
24984
|
} catch {
|
|
25259
24985
|
return null;
|
|
25260
24986
|
}
|
|
@@ -25360,8 +25086,8 @@ function parseSessionAnswer(stdout) {
|
|
|
25360
25086
|
}
|
|
25361
25087
|
|
|
25362
25088
|
// src/backfill/propose.ts
|
|
25363
|
-
import { mkdirSync as mkdirSync14, readFileSync as
|
|
25364
|
-
import { join as
|
|
25089
|
+
import { mkdirSync as mkdirSync14, readFileSync as readFileSync31, writeFileSync as writeFileSync13 } from "fs";
|
|
25090
|
+
import { join as join43, resolve as resolve14 } from "path";
|
|
25365
25091
|
var PROPOSAL_ACTION_KINDS = [
|
|
25366
25092
|
"applied",
|
|
25367
25093
|
"unchanged",
|
|
@@ -25510,7 +25236,7 @@ function writeRow(path, row2, original, options) {
|
|
|
25510
25236
|
};
|
|
25511
25237
|
}
|
|
25512
25238
|
function applyRow(root, row2, options) {
|
|
25513
|
-
const path =
|
|
25239
|
+
const path = join43(root, ...row2.path.split("/"));
|
|
25514
25240
|
if (row2.status === UNANSWERED_ROW) {
|
|
25515
25241
|
return inert2(path, row2, "unanswered", row2.note ?? "the row carries no answer");
|
|
25516
25242
|
}
|
|
@@ -25519,7 +25245,7 @@ function applyRow(root, row2, options) {
|
|
|
25519
25245
|
}
|
|
25520
25246
|
let original;
|
|
25521
25247
|
try {
|
|
25522
|
-
original =
|
|
25248
|
+
original = readFileSync31(path, "utf8");
|
|
25523
25249
|
} catch {
|
|
25524
25250
|
return inert2(path, row2, "refused", "the file the row names is gone");
|
|
25525
25251
|
}
|
|
@@ -25547,7 +25273,7 @@ function applyProposals(files, root, options) {
|
|
|
25547
25273
|
for (const file of files) {
|
|
25548
25274
|
const refusal19 = fileRefusal(file, root);
|
|
25549
25275
|
for (const row2 of file.rows) {
|
|
25550
|
-
const action = refusal19 === null ? applyRow(root, row2, options) : inert2(
|
|
25276
|
+
const action = refusal19 === null ? applyRow(root, row2, options) : inert2(join43(root, ...row2.path.split("/")), row2, "refused", refusal19);
|
|
25551
25277
|
actions.push(action);
|
|
25552
25278
|
if (row2.trigger !== null && action.kind !== "refused" && action.kind !== "unanswered") {
|
|
25553
25279
|
triggers[row2.name] = row2.trigger;
|
|
@@ -25558,13 +25284,13 @@ function applyProposals(files, root, options) {
|
|
|
25558
25284
|
}
|
|
25559
25285
|
|
|
25560
25286
|
// src/demote/select.ts
|
|
25561
|
-
import { readdirSync as readdirSync8, readFileSync as
|
|
25562
|
-
import { basename as basename8, dirname as
|
|
25287
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync32, realpathSync as realpathSync5, statSync as statSync11 } from "fs";
|
|
25288
|
+
import { basename as basename8, dirname as dirname13, join as join44 } from "path";
|
|
25563
25289
|
var SKILLS_DIRECTORY = "skills";
|
|
25564
25290
|
var CLAUDE_DIRECTORY = ".claude";
|
|
25565
25291
|
var AUTO_EXTRACTED_ORIGIN = "auto-extracted";
|
|
25566
|
-
var DEMOTED_PATH =
|
|
25567
|
-
var INSTINCTS_PATH =
|
|
25292
|
+
var DEMOTED_PATH = join44(".rafa", "demoted");
|
|
25293
|
+
var INSTINCTS_PATH = join44(".rafa", "instincts");
|
|
25568
25294
|
var REPORT_FILE = "report.md";
|
|
25569
25295
|
function realOrSelf(path) {
|
|
25570
25296
|
try {
|
|
@@ -25583,18 +25309,18 @@ function samePath(left, right) {
|
|
|
25583
25309
|
function resolveDemotionScope(dir, home) {
|
|
25584
25310
|
if (basename8(dir) !== SKILLS_DIRECTORY)
|
|
25585
25311
|
return null;
|
|
25586
|
-
const claude =
|
|
25312
|
+
const claude = dirname13(dir);
|
|
25587
25313
|
if (basename8(claude) !== CLAUDE_DIRECTORY)
|
|
25588
25314
|
return null;
|
|
25589
|
-
const base =
|
|
25590
|
-
const demotedDir =
|
|
25315
|
+
const base = dirname13(claude);
|
|
25316
|
+
const demotedDir = join44(base, DEMOTED_PATH);
|
|
25591
25317
|
return {
|
|
25592
25318
|
scope: samePath(base, home) ? "user" : "project",
|
|
25593
25319
|
dir,
|
|
25594
25320
|
base,
|
|
25595
25321
|
demotedDir,
|
|
25596
|
-
instinctsDir:
|
|
25597
|
-
reportPath:
|
|
25322
|
+
instinctsDir: join44(base, INSTINCTS_PATH),
|
|
25323
|
+
reportPath: join44(demotedDir, REPORT_FILE)
|
|
25598
25324
|
};
|
|
25599
25325
|
}
|
|
25600
25326
|
function entryKind(path) {
|
|
@@ -25620,7 +25346,7 @@ function readSelected(absolute, path, entries) {
|
|
|
25620
25346
|
let text;
|
|
25621
25347
|
let mtime;
|
|
25622
25348
|
try {
|
|
25623
|
-
text =
|
|
25349
|
+
text = readFileSync32(absolute, "utf8");
|
|
25624
25350
|
mtime = statSync11(absolute).mtime.toISOString();
|
|
25625
25351
|
} catch {
|
|
25626
25352
|
return null;
|
|
@@ -25636,14 +25362,14 @@ function selectsLearned(text, scope) {
|
|
|
25636
25362
|
return origin === AUTO_EXTRACTED_ORIGIN;
|
|
25637
25363
|
}
|
|
25638
25364
|
function selectLearned(scope) {
|
|
25639
|
-
const dir =
|
|
25365
|
+
const dir = join44(scope.dir, LEARNED_DIRECTORY);
|
|
25640
25366
|
if (entryKind(dir) !== "directory")
|
|
25641
25367
|
return [];
|
|
25642
25368
|
const selected = [];
|
|
25643
25369
|
for (const name2 of visibleNames(dir)) {
|
|
25644
25370
|
if (!name2.endsWith(MARKDOWN_EXTENSION) || name2 === MARKDOWN_EXTENSION)
|
|
25645
25371
|
continue;
|
|
25646
|
-
const absolute =
|
|
25372
|
+
const absolute = join44(dir, name2);
|
|
25647
25373
|
if (entryKind(absolute) !== "file")
|
|
25648
25374
|
continue;
|
|
25649
25375
|
const file = readSelected(absolute, `${LEARNED_DIRECTORY}/${name2}`, undefined);
|
|
@@ -25657,10 +25383,10 @@ function selectSkillFiles(scope) {
|
|
|
25657
25383
|
for (const name2 of visibleNames(scope.dir)) {
|
|
25658
25384
|
if (name2 === LEARNED_DIRECTORY)
|
|
25659
25385
|
continue;
|
|
25660
|
-
const skillDir =
|
|
25386
|
+
const skillDir = join44(scope.dir, name2);
|
|
25661
25387
|
if (entryKind(skillDir) !== "directory")
|
|
25662
25388
|
continue;
|
|
25663
|
-
const absolute =
|
|
25389
|
+
const absolute = join44(skillDir, SKILL_FILE);
|
|
25664
25390
|
if (entryKind(absolute) !== "file")
|
|
25665
25391
|
continue;
|
|
25666
25392
|
const file = readSelected(absolute, `${name2}/${SKILL_FILE}`, visibleNames(skillDir));
|
|
@@ -25845,7 +25571,7 @@ function reviewedProposals(dir) {
|
|
|
25845
25571
|
return read2.flatMap((entry) => entry.result.file === null ? [] : [entry.result.file]);
|
|
25846
25572
|
}
|
|
25847
25573
|
function rowPaths(files, root) {
|
|
25848
|
-
return files.flatMap((file) => file.status !== REVIEWED_FILE ? [] : file.rows.filter((row2) => row2.status === ANSWERED_ROW).map((row2) =>
|
|
25574
|
+
return files.flatMap((file) => file.status !== REVIEWED_FILE ? [] : file.rows.filter((row2) => row2.status === ANSWERED_ROW).map((row2) => join45(root, ...row2.path.split("/"))));
|
|
25849
25575
|
}
|
|
25850
25576
|
function runApply(context, scope, backfillDir, projectRoot2) {
|
|
25851
25577
|
const options = checkOptions(context, projectRoot2);
|
|
@@ -25891,7 +25617,7 @@ async function runBackfill(context, seams) {
|
|
|
25891
25617
|
const dir = readBackfillDirectory(context.args, seams.cwd);
|
|
25892
25618
|
const projectRoot2 = readConsumerRoot(context.flags["project"], seams.cwd);
|
|
25893
25619
|
const scope = backfillScopeOf(dir, projectOf11(context).home);
|
|
25894
|
-
const backfillDir =
|
|
25620
|
+
const backfillDir = join45(scope.base, BACKFILL_PATH);
|
|
25895
25621
|
if (mode === "propose") {
|
|
25896
25622
|
await runPropose(context, scope, backfillDir, seams);
|
|
25897
25623
|
return;
|
|
@@ -26005,13 +25731,13 @@ function createSkillCheckCommand(seams = DEFAULT_CHECK_SEAMS) {
|
|
|
26005
25731
|
var check_default3 = createSkillCheckCommand();
|
|
26006
25732
|
|
|
26007
25733
|
// src/commands/skill/demote.ts
|
|
26008
|
-
import { existsSync as
|
|
26009
|
-
import { dirname as
|
|
25734
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync16, readFileSync as readFileSync34, statSync as statSync14, writeFileSync as writeFileSync15 } from "fs";
|
|
25735
|
+
import { dirname as dirname15, resolve as resolve16 } from "path";
|
|
26010
25736
|
|
|
26011
25737
|
// src/demote/apply.ts
|
|
26012
|
-
import { copyFileSync as copyFileSync5, existsSync as
|
|
25738
|
+
import { copyFileSync as copyFileSync5, existsSync as existsSync15, mkdirSync as mkdirSync15, mkdtempSync as mkdtempSync3, readdirSync as readdirSync9, readFileSync as readFileSync33, renameSync as renameSync2, rmSync as rmSync4, statSync as statSync13, unlinkSync, writeFileSync as writeFileSync14 } from "fs";
|
|
26013
25739
|
import { tmpdir as tmpdir3 } from "os";
|
|
26014
|
-
import { dirname as
|
|
25740
|
+
import { dirname as dirname14, join as join46 } from "path";
|
|
26015
25741
|
var DEMOTION_ACTION_KINDS = [
|
|
26016
25742
|
"demoted",
|
|
26017
25743
|
"kept",
|
|
@@ -26032,13 +25758,13 @@ function learnedSkillName(path) {
|
|
|
26032
25758
|
return base.slice(0, -MARKDOWN_EXTENSION.length);
|
|
26033
25759
|
}
|
|
26034
25760
|
function sourcePath(scope, path) {
|
|
26035
|
-
return
|
|
25761
|
+
return join46(scope.dir, ...path.split("/"));
|
|
26036
25762
|
}
|
|
26037
25763
|
function demotedPath(scope, path) {
|
|
26038
|
-
return
|
|
25764
|
+
return join46(scope.demotedDir, ...path.split("/"));
|
|
26039
25765
|
}
|
|
26040
25766
|
function promotedPath(scope, path) {
|
|
26041
|
-
return
|
|
25767
|
+
return join46(scope.dir, learnedSkillName(path), SKILL_FILE);
|
|
26042
25768
|
}
|
|
26043
25769
|
function takenInstinctIds(dir) {
|
|
26044
25770
|
let names;
|
|
@@ -26051,7 +25777,7 @@ function takenInstinctIds(dir) {
|
|
|
26051
25777
|
}
|
|
26052
25778
|
function readText5(path) {
|
|
26053
25779
|
try {
|
|
26054
|
-
return statSync13(path).isFile() ?
|
|
25780
|
+
return statSync13(path).isFile() ? readFileSync33(path, "utf8") : null;
|
|
26055
25781
|
} catch {
|
|
26056
25782
|
return null;
|
|
26057
25783
|
}
|
|
@@ -26079,7 +25805,7 @@ function planKept(scope, row2, file) {
|
|
|
26079
25805
|
return inert3(row2.path, "procedure", "kept", "procedure-shaped: left where it is, for the backfill");
|
|
26080
25806
|
}
|
|
26081
25807
|
const to = promotedPath(scope, row2.path);
|
|
26082
|
-
if (
|
|
25808
|
+
if (existsSync15(to) || existsSync15(dirname14(to))) {
|
|
26083
25809
|
return inert3(row2.path, "procedure", "refused", `kept as a skill, but ${to} is already there`);
|
|
26084
25810
|
}
|
|
26085
25811
|
return {
|
|
@@ -26093,7 +25819,7 @@ function planKept(scope, row2, file) {
|
|
|
26093
25819
|
};
|
|
26094
25820
|
}
|
|
26095
25821
|
function checkCandidate(dir, id2, text, pathDirs) {
|
|
26096
|
-
const path =
|
|
25822
|
+
const path = join46(dir, `${id2}${MARKDOWN_EXTENSION}`);
|
|
26097
25823
|
writeFileSync14(path, text, "utf8");
|
|
26098
25824
|
const report5 = checkFile(path, "instinct", { projectRoot: null, pathDirs });
|
|
26099
25825
|
return failureLines2(report5.issues);
|
|
@@ -26114,11 +25840,11 @@ function planDemoted(scope, row2, file, context) {
|
|
|
26114
25840
|
if (failures.length > 0) {
|
|
26115
25841
|
return inert3(row2.path, "observation", "refused", `the record ${id2} fails the checker \u2014 ${failures.join("; ")}`);
|
|
26116
25842
|
}
|
|
26117
|
-
const destination =
|
|
25843
|
+
const destination = join46(scope.instinctsDir, `${id2}${MARKDOWN_EXTENSION}`);
|
|
26118
25844
|
const kept = demotedPath(scope, row2.path);
|
|
26119
|
-
if (
|
|
25845
|
+
if (existsSync15(destination))
|
|
26120
25846
|
return inert3(row2.path, "observation", "refused", `${destination} is already there`);
|
|
26121
|
-
if (
|
|
25847
|
+
if (existsSync15(kept))
|
|
26122
25848
|
return inert3(row2.path, "observation", "refused", `${kept} is already there`);
|
|
26123
25849
|
context.taken.push(id2);
|
|
26124
25850
|
return {
|
|
@@ -26161,7 +25887,7 @@ function countActions(actions) {
|
|
|
26161
25887
|
return counts;
|
|
26162
25888
|
}
|
|
26163
25889
|
function planDemotion(report5, scope, seams = DEFAULT_APPLY_SEAMS) {
|
|
26164
|
-
const temp = mkdtempSync3(
|
|
25890
|
+
const temp = mkdtempSync3(join46(tmpdir3(), "rafa-demote-"));
|
|
26165
25891
|
const taken = [...takenInstinctIds(scope.instinctsDir)];
|
|
26166
25892
|
try {
|
|
26167
25893
|
const actions = report5.rows.map((row2) => planRow(scope, row2, { temp, taken, seams }));
|
|
@@ -26171,7 +25897,7 @@ function planDemotion(report5, scope, seams = DEFAULT_APPLY_SEAMS) {
|
|
|
26171
25897
|
}
|
|
26172
25898
|
}
|
|
26173
25899
|
function moveFile(move3) {
|
|
26174
|
-
mkdirSync15(
|
|
25900
|
+
mkdirSync15(dirname14(move3.to), { recursive: true });
|
|
26175
25901
|
try {
|
|
26176
25902
|
renameSync2(move3.from, move3.to);
|
|
26177
25903
|
} catch {
|
|
@@ -26182,7 +25908,7 @@ function moveFile(move3) {
|
|
|
26182
25908
|
function applyDemotion(plan2) {
|
|
26183
25909
|
for (const action of plan2.actions) {
|
|
26184
25910
|
if (action.write !== null) {
|
|
26185
|
-
mkdirSync15(
|
|
25911
|
+
mkdirSync15(dirname14(action.write.path), { recursive: true });
|
|
26186
25912
|
writeFileSync14(action.write.path, action.write.text, "utf8");
|
|
26187
25913
|
}
|
|
26188
25914
|
if (action.move !== null)
|
|
@@ -26280,9 +26006,9 @@ function verdictLine2(report5) {
|
|
|
26280
26006
|
return `${String(report5.rows.length)} file(s): ${parts.join(", ")}`;
|
|
26281
26007
|
}
|
|
26282
26008
|
function previousReport(path, context) {
|
|
26283
|
-
if (!
|
|
26009
|
+
if (!existsSync16(path))
|
|
26284
26010
|
return null;
|
|
26285
|
-
const parsed = parseDemotionReport(
|
|
26011
|
+
const parsed = parseDemotionReport(readFileSync34(path, "utf8"));
|
|
26286
26012
|
if (parsed.report !== null)
|
|
26287
26013
|
return parsed.report;
|
|
26288
26014
|
context.output.warn(`the report already at ${path} does not parse, so no override in it is carried forward:` + ` ${parsed.issues.map((issue2) => `line ${String(issue2.line)} ${issue2.code}`).join(", ")}`);
|
|
@@ -26291,7 +26017,7 @@ function previousReport(path, context) {
|
|
|
26291
26017
|
function runWrite(context, scope) {
|
|
26292
26018
|
const files = selectSources(scope);
|
|
26293
26019
|
const report5 = buildDemotionReport(files, previousReport(scope.reportPath, context));
|
|
26294
|
-
mkdirSync16(
|
|
26020
|
+
mkdirSync16(dirname15(scope.reportPath), { recursive: true });
|
|
26295
26021
|
writeFileSync15(scope.reportPath, writeDemotionReport(report5), "utf8");
|
|
26296
26022
|
const result2 = {
|
|
26297
26023
|
applied: false,
|
|
@@ -26315,10 +26041,10 @@ function runWrite(context, scope) {
|
|
|
26315
26041
|
context.output.info(line);
|
|
26316
26042
|
}
|
|
26317
26043
|
function reviewedReport(scope) {
|
|
26318
|
-
if (!
|
|
26044
|
+
if (!existsSync16(scope.reportPath)) {
|
|
26319
26045
|
throw new CommandExit(1, `\u274C No report at ${scope.reportPath}; run "rafa skill demote ${scope.dir}" first, then review it`);
|
|
26320
26046
|
}
|
|
26321
|
-
const parsed = parseDemotionReport(
|
|
26047
|
+
const parsed = parseDemotionReport(readFileSync34(scope.reportPath, "utf8"));
|
|
26322
26048
|
if (parsed.report === null) {
|
|
26323
26049
|
const lines = parsed.issues.map((issue2) => ` line ${String(issue2.line)} ${issue2.code}: ${issue2.message}`);
|
|
26324
26050
|
throw new CommandExit(1, [`\u274C ${scope.reportPath} does not parse:`, ...lines].join(`
|
|
@@ -26691,7 +26417,7 @@ function statusData(sections) {
|
|
|
26691
26417
|
}
|
|
26692
26418
|
|
|
26693
26419
|
// src/status/sections.ts
|
|
26694
|
-
import { existsSync as
|
|
26420
|
+
import { existsSync as existsSync17 } from "fs";
|
|
26695
26421
|
|
|
26696
26422
|
// src/status/blocked-count.ts
|
|
26697
26423
|
async function labelsCount(options) {
|
|
@@ -26951,7 +26677,7 @@ function nextOfPlace(current, epic, walk) {
|
|
|
26951
26677
|
return epic?.members.some((member) => member.number === line.issue) === true ? line.issue : null;
|
|
26952
26678
|
}
|
|
26953
26679
|
function hasBoards(root, listing2) {
|
|
26954
|
-
if (
|
|
26680
|
+
if (existsSync17(positionFilePath(root)))
|
|
26955
26681
|
return true;
|
|
26956
26682
|
return listing2.some((issue2) => issue2.state === "OPEN" && issue2.labels.includes(ROADMAP_LABEL));
|
|
26957
26683
|
}
|
|
@@ -27126,8 +26852,8 @@ function createStatusCommand(seams = DEFAULT_STATUS_SEAMS) {
|
|
|
27126
26852
|
var status_default4 = createStatusCommand();
|
|
27127
26853
|
|
|
27128
26854
|
// src/commands/stretch/end.ts
|
|
27129
|
-
import { existsSync as
|
|
27130
|
-
import { dirname as
|
|
26855
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync17, readFileSync as readFileSync35, writeFileSync as writeFileSync16 } from "fs";
|
|
26856
|
+
import { dirname as dirname16, join as join47 } from "path";
|
|
27131
26857
|
var COMMAND_NAME19 = "rafa stretch end";
|
|
27132
26858
|
var STRETCH_END_USAGE = "rafa stretch end [--dry-run]";
|
|
27133
26859
|
var REPORT_FILE2 = "report.md";
|
|
@@ -27135,10 +26861,10 @@ var BODY_FILE = "pr-body.md";
|
|
|
27135
26861
|
var REFUSED_EXIT10 = 1;
|
|
27136
26862
|
var FAILED_EXIT6 = 2;
|
|
27137
26863
|
function reportPath(root, n) {
|
|
27138
|
-
return
|
|
26864
|
+
return join47(stretchFolder(root, n), REPORT_FILE2);
|
|
27139
26865
|
}
|
|
27140
26866
|
function bodyPath(root, n) {
|
|
27141
|
-
return
|
|
26867
|
+
return join47(stretchFolder(root, n), BODY_FILE);
|
|
27142
26868
|
}
|
|
27143
26869
|
function endTitle(n) {
|
|
27144
26870
|
return `Stretch ${String(n)}`;
|
|
@@ -27174,11 +26900,11 @@ function requireStretchBase2(prBase) {
|
|
|
27174
26900
|
}
|
|
27175
26901
|
function readReport(root, n) {
|
|
27176
26902
|
const path = reportPath(root, n);
|
|
27177
|
-
if (!
|
|
26903
|
+
if (!existsSync18(path)) {
|
|
27178
26904
|
throw refusal19(`there is no ${path}: write the stretch report first, since it is the pull request's body. Nothing was run.`);
|
|
27179
26905
|
}
|
|
27180
26906
|
try {
|
|
27181
|
-
return
|
|
26907
|
+
return readFileSync35(path, "utf8");
|
|
27182
26908
|
} catch (error) {
|
|
27183
26909
|
throw refusal19(`${path} could not be read: ${messageOf(error)}. Nothing was run.`);
|
|
27184
26910
|
}
|
|
@@ -27191,11 +26917,11 @@ function recordText(record, name2, path) {
|
|
|
27191
26917
|
}
|
|
27192
26918
|
function readStretchRecord(root, n) {
|
|
27193
26919
|
const path = stretchRecordPath(root, n);
|
|
27194
|
-
if (!
|
|
26920
|
+
if (!existsSync18(path))
|
|
27195
26921
|
return null;
|
|
27196
26922
|
let value;
|
|
27197
26923
|
try {
|
|
27198
|
-
value = JSON.parse(
|
|
26924
|
+
value = JSON.parse(readFileSync35(path, "utf8"));
|
|
27199
26925
|
} catch (error) {
|
|
27200
26926
|
throw refusal19(`${path} could not be read as JSON: ${messageOf(error)}. Nothing was run.`);
|
|
27201
26927
|
}
|
|
@@ -27240,7 +26966,7 @@ function putBack(context, input, merged2) {
|
|
|
27240
26966
|
const path = configFilePath(input.root);
|
|
27241
26967
|
let edit;
|
|
27242
26968
|
try {
|
|
27243
|
-
edit = withConfigSetting(
|
|
26969
|
+
edit = withConfigSetting(readFileSync35(path, "utf8"), PR_BASE_KEY, value, path);
|
|
27244
26970
|
} catch (error) {
|
|
27245
26971
|
const why = error instanceof ConfigSetRefusal ? `${PR_BASE_KEY} cannot be set: ${error.message}` : `${path} could not be read: ${messageOf(error)}`;
|
|
27246
26972
|
throw refusal19(`${why}. Nothing was set.`);
|
|
@@ -27277,7 +27003,7 @@ async function openEnd(context, input, body, seams) {
|
|
|
27277
27003
|
return;
|
|
27278
27004
|
}
|
|
27279
27005
|
try {
|
|
27280
|
-
mkdirSync17(
|
|
27006
|
+
mkdirSync17(dirname16(path), { recursive: true });
|
|
27281
27007
|
writeFileSync16(path, body, "utf8");
|
|
27282
27008
|
} catch (error) {
|
|
27283
27009
|
throw failure4(`${path} could not be written: ${messageOf(error)}. No pull request was opened.`);
|
|
@@ -27362,8 +27088,8 @@ function createUpdateStub(spec) {
|
|
|
27362
27088
|
var board_default = createUpdateStub({ action: "board", summary: "apply the board's newest setup and its migrations", issue: 717 });
|
|
27363
27089
|
|
|
27364
27090
|
// src/project/lock.ts
|
|
27365
|
-
import { existsSync as
|
|
27366
|
-
import { join as
|
|
27091
|
+
import { existsSync as existsSync19, lstatSync as lstatSync2, readFileSync as readFileSync36, writeFileSync as writeFileSync17 } from "fs";
|
|
27092
|
+
import { join as join48 } from "path";
|
|
27367
27093
|
var LOCK_FILE = "rafa.lock";
|
|
27368
27094
|
var LOCKFILE_VERSION = 1;
|
|
27369
27095
|
|
|
@@ -27371,7 +27097,7 @@ class ProjectLockError extends Error {
|
|
|
27371
27097
|
name = "ProjectLockError";
|
|
27372
27098
|
}
|
|
27373
27099
|
function lockPath(root) {
|
|
27374
|
-
return
|
|
27100
|
+
return join48(root, LOCK_FILE);
|
|
27375
27101
|
}
|
|
27376
27102
|
function projectLockText(version2) {
|
|
27377
27103
|
const lock = { lockfileVersion: LOCKFILE_VERSION, rafa: version2 };
|
|
@@ -27404,14 +27130,14 @@ function lockOf(value) {
|
|
|
27404
27130
|
}
|
|
27405
27131
|
function readProjectLock(root) {
|
|
27406
27132
|
const path = lockPath(root);
|
|
27407
|
-
if (!
|
|
27133
|
+
if (!existsSync19(path)) {
|
|
27408
27134
|
if (isLink(path))
|
|
27409
27135
|
refuse10("is a link to nothing");
|
|
27410
27136
|
return null;
|
|
27411
27137
|
}
|
|
27412
27138
|
let text;
|
|
27413
27139
|
try {
|
|
27414
|
-
text =
|
|
27140
|
+
text = readFileSync36(path, "utf8");
|
|
27415
27141
|
} catch (error) {
|
|
27416
27142
|
refuse10(`could not be read: ${messageOf(error)}`);
|
|
27417
27143
|
}
|
|
@@ -27428,11 +27154,11 @@ function writeProjectLock(root, version2) {
|
|
|
27428
27154
|
}
|
|
27429
27155
|
|
|
27430
27156
|
// src/project/update-current.ts
|
|
27431
|
-
import { existsSync as
|
|
27432
|
-
import { join as
|
|
27157
|
+
import { existsSync as existsSync20 } from "fs";
|
|
27158
|
+
import { join as join49 } from "path";
|
|
27433
27159
|
var DEPRECATIONS = Object.freeze([]);
|
|
27434
27160
|
function missingFolders(root) {
|
|
27435
|
-
return PROJECT_TREE.map((name2) =>
|
|
27161
|
+
return PROJECT_TREE.map((name2) => join49(SCOPE_DIR, name2)).filter((relative12) => !existsSync20(join49(root, relative12)));
|
|
27436
27162
|
}
|
|
27437
27163
|
async function readBoard3(access) {
|
|
27438
27164
|
if (access.gh === null)
|
|
@@ -27485,7 +27211,7 @@ class UpdateStepError extends Error {
|
|
|
27485
27211
|
}
|
|
27486
27212
|
}
|
|
27487
27213
|
function foldersNowThere(plan2) {
|
|
27488
|
-
return plan2.folders.filter((relative12) =>
|
|
27214
|
+
return plan2.folders.filter((relative12) => existsSync20(join49(plan2.root, relative12)));
|
|
27489
27215
|
}
|
|
27490
27216
|
function writeFolders(plan2) {
|
|
27491
27217
|
if (plan2.folders.length === 0)
|