@open-tomato/rafa 0.19.0 → 0.20.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 +23 -4
- package/dist/bundled/skills/dev-planner/SKILL.md +7 -0
- package/dist/cli.js +2017 -1047
- package/dist/{describe-cenk70n5.js → describe-0tefrkk7.js} +3 -3
- package/dist/effort/store/index.js +4 -4
- package/dist/{index-ca0fccvr.js → index-02fx0mzf.js} +3922 -3173
- package/dist/{index-09p41s0n.js → index-21qkxk63.js} +2 -2
- package/dist/{index-vg7ycs94.js → index-28jzpyks.js} +1 -1
- package/dist/{index-c5cecsga.js → index-4a45ffqh.js} +2 -2
- package/dist/{index-gb51x34c.js → index-afersvp3.js} +25 -4
- package/dist/{index-cedghpva.js → index-pmkgvtfe.js} +5 -1
- package/dist/{index-pqrpcfaz.js → index-twbp38kz.js} +45 -38
- package/dist/{index-mh5hyw8g.js → index-zhh1h3h9.js} +463 -312
- package/dist/index.js +7 -7
- package/dist/plan/index.js +3 -3
- package/dist/plan-prompt.md +2 -0
- package/package.json +1 -1
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
SESSION_ID_FLAG,
|
|
35
35
|
SKILL_FILE as SKILL_FILE2,
|
|
36
36
|
SKILL_SIGNALS,
|
|
37
|
+
SKILL_USE_CLI_VERSION,
|
|
37
38
|
SPEC_BLOCKED_LABEL,
|
|
38
39
|
SPEC_EXTENSION,
|
|
39
40
|
SPEC_LABEL,
|
|
@@ -148,6 +149,7 @@ import {
|
|
|
148
149
|
previousDir,
|
|
149
150
|
projectRoot,
|
|
150
151
|
provenanceBlock,
|
|
152
|
+
rankCandidates,
|
|
151
153
|
readAgentDirectory,
|
|
152
154
|
readAuthorTrust,
|
|
153
155
|
readBlockedBy,
|
|
@@ -156,7 +158,6 @@ import {
|
|
|
156
158
|
readChoice,
|
|
157
159
|
readChoiceFlag,
|
|
158
160
|
readCopyRefs,
|
|
159
|
-
readInventoryFrontmatter,
|
|
160
161
|
readManifestVersion,
|
|
161
162
|
readMergeRefusal,
|
|
162
163
|
readNextState,
|
|
@@ -164,6 +165,7 @@ import {
|
|
|
164
165
|
readOpenPull,
|
|
165
166
|
readPlanChanges,
|
|
166
167
|
readPlans,
|
|
168
|
+
readRankCandidate,
|
|
167
169
|
readRecords,
|
|
168
170
|
readRefsText,
|
|
169
171
|
readRequiredFlag,
|
|
@@ -225,7 +227,7 @@ import {
|
|
|
225
227
|
versionLine,
|
|
226
228
|
waitForChecks,
|
|
227
229
|
writeSession
|
|
228
|
-
} from "./index-
|
|
230
|
+
} from "./index-02fx0mzf.js";
|
|
229
231
|
import {
|
|
230
232
|
PROBE_TIMEOUT_MS,
|
|
231
233
|
findNextTask,
|
|
@@ -239,7 +241,7 @@ import {
|
|
|
239
241
|
runPreflight,
|
|
240
242
|
splitBlockerComment,
|
|
241
243
|
trackerPathFor
|
|
242
|
-
} from "./index-
|
|
244
|
+
} from "./index-21qkxk63.js";
|
|
243
245
|
import {
|
|
244
246
|
ACTION_HEADING,
|
|
245
247
|
CAUSE_HEADING,
|
|
@@ -252,6 +254,7 @@ import {
|
|
|
252
254
|
ISSUE_TYPES,
|
|
253
255
|
MARKDOWN_EXTENSION,
|
|
254
256
|
SKILL_FILE,
|
|
257
|
+
SQLITE_MIGRATIONS,
|
|
255
258
|
allRecords,
|
|
256
259
|
claudeArgs,
|
|
257
260
|
createGhRunner,
|
|
@@ -260,6 +263,7 @@ import {
|
|
|
260
263
|
gitRemoteUrl,
|
|
261
264
|
instinctProject,
|
|
262
265
|
mergeFrontmatter,
|
|
266
|
+
migrateSchema,
|
|
263
267
|
moduleOfLabels,
|
|
264
268
|
normalizeRemote,
|
|
265
269
|
readFrontmatter,
|
|
@@ -275,7 +279,7 @@ import {
|
|
|
275
279
|
toHeldRecords,
|
|
276
280
|
typeOfLabels,
|
|
277
281
|
writeFrontmatter
|
|
278
|
-
} from "./index-
|
|
282
|
+
} from "./index-afersvp3.js";
|
|
279
283
|
import {
|
|
280
284
|
CONFIG_DEFAULTS,
|
|
281
285
|
CONFIG_FILE,
|
|
@@ -289,7 +293,7 @@ import {
|
|
|
289
293
|
readItemBytes,
|
|
290
294
|
readRafaBlocks,
|
|
291
295
|
resolveTiers
|
|
292
|
-
} from "./index-
|
|
296
|
+
} from "./index-twbp38kz.js";
|
|
293
297
|
import {
|
|
294
298
|
promotable
|
|
295
299
|
} from "./index-d6d0942q.js";
|
|
@@ -297,10 +301,10 @@ import {
|
|
|
297
301
|
createCommandRegistry,
|
|
298
302
|
describeRegistry,
|
|
299
303
|
mountKey
|
|
300
|
-
} from "./index-
|
|
304
|
+
} from "./index-4a45ffqh.js";
|
|
301
305
|
import {
|
|
302
306
|
CommandExit
|
|
303
|
-
} from "./index-
|
|
307
|
+
} from "./index-28jzpyks.js";
|
|
304
308
|
import {
|
|
305
309
|
MERGE_METHODS,
|
|
306
310
|
RELEASE_AUTO,
|
|
@@ -312,7 +316,7 @@ import {
|
|
|
312
316
|
isSkillTier,
|
|
313
317
|
messageOf,
|
|
314
318
|
parseBudgetUsd
|
|
315
|
-
} from "./index-
|
|
319
|
+
} from "./index-pmkgvtfe.js";
|
|
316
320
|
import {
|
|
317
321
|
triggerKey
|
|
318
322
|
} from "./index-wp8c28fd.js";
|
|
@@ -2287,148 +2291,6 @@ async function checkQuotes(matches, files) {
|
|
|
2287
2291
|
return { kept, dropped: matches.length - kept.length };
|
|
2288
2292
|
}
|
|
2289
2293
|
|
|
2290
|
-
// src/inventory/search/rank.ts
|
|
2291
|
-
import { readFileSync as readFileSync5 } from "fs";
|
|
2292
|
-
var SEARCH_LIMIT = 12;
|
|
2293
|
-
var MIN_WORD_LENGTH = 2;
|
|
2294
|
-
var MIN_PREFIX_LENGTH = 4;
|
|
2295
|
-
var FIELD_WEIGHTS = {
|
|
2296
|
-
tags: 4,
|
|
2297
|
-
prevents: 3,
|
|
2298
|
-
whenToUse: 3,
|
|
2299
|
-
description: 2,
|
|
2300
|
-
body: 1
|
|
2301
|
-
};
|
|
2302
|
-
var FIELDS = ["tags", "prevents", "whenToUse", "description", "body"];
|
|
2303
|
-
var STOP_WORDS = new Set([
|
|
2304
|
-
"a",
|
|
2305
|
-
"about",
|
|
2306
|
-
"an",
|
|
2307
|
-
"and",
|
|
2308
|
-
"any",
|
|
2309
|
-
"are",
|
|
2310
|
-
"as",
|
|
2311
|
-
"at",
|
|
2312
|
-
"be",
|
|
2313
|
-
"by",
|
|
2314
|
-
"can",
|
|
2315
|
-
"could",
|
|
2316
|
-
"do",
|
|
2317
|
-
"does",
|
|
2318
|
-
"for",
|
|
2319
|
-
"from",
|
|
2320
|
-
"has",
|
|
2321
|
-
"have",
|
|
2322
|
-
"how",
|
|
2323
|
-
"if",
|
|
2324
|
-
"in",
|
|
2325
|
-
"into",
|
|
2326
|
-
"is",
|
|
2327
|
-
"it",
|
|
2328
|
-
"its",
|
|
2329
|
-
"me",
|
|
2330
|
-
"my",
|
|
2331
|
-
"of",
|
|
2332
|
-
"on",
|
|
2333
|
-
"or",
|
|
2334
|
-
"should",
|
|
2335
|
-
"so",
|
|
2336
|
-
"that",
|
|
2337
|
-
"the",
|
|
2338
|
-
"their",
|
|
2339
|
-
"there",
|
|
2340
|
-
"this",
|
|
2341
|
-
"to",
|
|
2342
|
-
"use",
|
|
2343
|
-
"was",
|
|
2344
|
-
"we",
|
|
2345
|
-
"what",
|
|
2346
|
-
"when",
|
|
2347
|
-
"where",
|
|
2348
|
-
"which",
|
|
2349
|
-
"who",
|
|
2350
|
-
"why",
|
|
2351
|
-
"will",
|
|
2352
|
-
"with",
|
|
2353
|
-
"would",
|
|
2354
|
-
"you",
|
|
2355
|
-
"your",
|
|
2356
|
-
"agent",
|
|
2357
|
-
"agents",
|
|
2358
|
-
"skill",
|
|
2359
|
-
"skills"
|
|
2360
|
-
]);
|
|
2361
|
-
function wordsOf(text) {
|
|
2362
|
-
return text.toLowerCase().match(/[\p{L}\p{N}]+/gu) ?? [];
|
|
2363
|
-
}
|
|
2364
|
-
function questionWords(question) {
|
|
2365
|
-
const kept = wordsOf(question).filter((word) => word.length >= MIN_WORD_LENGTH && !STOP_WORDS.has(word));
|
|
2366
|
-
return [...new Set(kept)];
|
|
2367
|
-
}
|
|
2368
|
-
function wordsMatch(word, other) {
|
|
2369
|
-
if (word === other)
|
|
2370
|
-
return true;
|
|
2371
|
-
const [shorter, longer] = word.length <= other.length ? [word, other] : [other, word];
|
|
2372
|
-
return shorter.length >= MIN_PREFIX_LENGTH && longer.startsWith(shorter);
|
|
2373
|
-
}
|
|
2374
|
-
function fieldWords(candidate) {
|
|
2375
|
-
const { record } = candidate;
|
|
2376
|
-
const texts = {
|
|
2377
|
-
tags: record.tags.join(" "),
|
|
2378
|
-
prevents: record.prevents ?? "",
|
|
2379
|
-
whenToUse: record.whenToUse ?? "",
|
|
2380
|
-
description: candidate.description ?? "",
|
|
2381
|
-
body: candidate.body
|
|
2382
|
-
};
|
|
2383
|
-
return new Map(FIELDS.map((field) => [field, [...new Set(wordsOf(texts[field]))]]));
|
|
2384
|
-
}
|
|
2385
|
-
function scoreCandidate(candidate, words) {
|
|
2386
|
-
const byField = fieldWords(candidate);
|
|
2387
|
-
const matchedWords = new Set;
|
|
2388
|
-
const matchedFields = new Set;
|
|
2389
|
-
let score = 0;
|
|
2390
|
-
for (const word of words) {
|
|
2391
|
-
for (const field of FIELDS) {
|
|
2392
|
-
const found = (byField.get(field) ?? []).some((other) => wordsMatch(word, other));
|
|
2393
|
-
if (!found)
|
|
2394
|
-
continue;
|
|
2395
|
-
score += FIELD_WEIGHTS[field];
|
|
2396
|
-
matchedWords.add(word);
|
|
2397
|
-
matchedFields.add(field);
|
|
2398
|
-
}
|
|
2399
|
-
}
|
|
2400
|
-
return {
|
|
2401
|
-
record: candidate.record,
|
|
2402
|
-
score,
|
|
2403
|
-
words: words.filter((word) => matchedWords.has(word)),
|
|
2404
|
-
fields: FIELDS.filter((field) => matchedFields.has(field))
|
|
2405
|
-
};
|
|
2406
|
-
}
|
|
2407
|
-
function rankCandidates(question, candidates, limit = SEARCH_LIMIT) {
|
|
2408
|
-
const words = questionWords(question);
|
|
2409
|
-
if (words.length === 0)
|
|
2410
|
-
return [];
|
|
2411
|
-
return candidates.map((candidate) => scoreCandidate(candidate, words)).filter((ranked) => ranked.score > 0).sort((a, b) => b.score - a.score).slice(0, limit);
|
|
2412
|
-
}
|
|
2413
|
-
function readRankCandidate(record, read = (path) => readFileSync5(path, "utf8")) {
|
|
2414
|
-
let text;
|
|
2415
|
-
try {
|
|
2416
|
-
text = read(record.path);
|
|
2417
|
-
} catch {
|
|
2418
|
-
return {
|
|
2419
|
-
record,
|
|
2420
|
-
description: record.summary === "" ? null : record.summary,
|
|
2421
|
-
body: ""
|
|
2422
|
-
};
|
|
2423
|
-
}
|
|
2424
|
-
const document = readFrontmatterDocument(text);
|
|
2425
|
-
return {
|
|
2426
|
-
record,
|
|
2427
|
-
description: readInventoryFrontmatter(document?.data ?? null).description,
|
|
2428
|
-
body: document?.body ?? text
|
|
2429
|
-
};
|
|
2430
|
-
}
|
|
2431
|
-
|
|
2432
2294
|
// src/inventory/search/scratch.ts
|
|
2433
2295
|
import { copyFileSync, mkdirSync, mkdtempSync, rmSync } from "fs";
|
|
2434
2296
|
import { tmpdir } from "os";
|
|
@@ -2851,7 +2713,7 @@ function createAgentShowCommand(seams = DEFAULT_AGENT_SHOW_SEAMS) {
|
|
|
2851
2713
|
var show_default = createAgentShowCommand();
|
|
2852
2714
|
|
|
2853
2715
|
// src/commands/agent/vendor.ts
|
|
2854
|
-
import { copyFileSync as copyFileSync2, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as
|
|
2716
|
+
import { copyFileSync as copyFileSync2, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync5, writeFileSync } from "fs";
|
|
2855
2717
|
import { basename as basename2, join as join6 } from "path";
|
|
2856
2718
|
var USAGE4 = "rafa agent vendor <name>... [--force]";
|
|
2857
2719
|
var NOTHING_WRITTEN = "Nothing was written.";
|
|
@@ -2938,7 +2800,7 @@ function planCopies(names, project, force, entry) {
|
|
|
2938
2800
|
function copyOne(copy, date) {
|
|
2939
2801
|
try {
|
|
2940
2802
|
copyFileSync2(copy.from, copy.to);
|
|
2941
|
-
writeFileSync(copy.to, withSourceHeader(
|
|
2803
|
+
writeFileSync(copy.to, withSourceHeader(readFileSync5(copy.to, "utf8"), copy.from, date), "utf8");
|
|
2942
2804
|
} catch (error) {
|
|
2943
2805
|
throw new CommandExit(1, `\u274C ${USAGE4}: agent "${copy.name}" could not be written to ${copy.to}: ${String(error)}`);
|
|
2944
2806
|
}
|
|
@@ -4287,7 +4149,7 @@ import { statSync as statSync5 } from "fs";
|
|
|
4287
4149
|
import { join as join10 } from "path";
|
|
4288
4150
|
|
|
4289
4151
|
// src/board/setup-config.ts
|
|
4290
|
-
import { readFileSync as
|
|
4152
|
+
import { readFileSync as readFileSync6 } from "fs";
|
|
4291
4153
|
function roadmapIssueIn(text, path) {
|
|
4292
4154
|
return parseConfigText(text, path).values.roadmapIssue ?? null;
|
|
4293
4155
|
}
|
|
@@ -4295,7 +4157,7 @@ function readRoadmapSetting(root) {
|
|
|
4295
4157
|
const path = configFilePath(root);
|
|
4296
4158
|
let text;
|
|
4297
4159
|
try {
|
|
4298
|
-
text =
|
|
4160
|
+
text = readFileSync6(path, "utf8");
|
|
4299
4161
|
} catch (error) {
|
|
4300
4162
|
return { issue: null, text: "", problem: `${path} could not be read: ${messageOf(error)}` };
|
|
4301
4163
|
}
|
|
@@ -4344,7 +4206,7 @@ function withRoadmapIssue(text, issue) {
|
|
|
4344
4206
|
}
|
|
4345
4207
|
|
|
4346
4208
|
// src/board/setup.ts
|
|
4347
|
-
import { existsSync as existsSync4, lstatSync, mkdirSync as mkdirSync3, readFileSync as
|
|
4209
|
+
import { existsSync as existsSync4, lstatSync, mkdirSync as mkdirSync3, readFileSync as readFileSync7, statSync as statSync4, writeFileSync as writeFileSync2 } from "fs";
|
|
4348
4210
|
import { dirname, join as join9 } from "path";
|
|
4349
4211
|
import { fileURLToPath } from "url";
|
|
4350
4212
|
var PREFIX = "board setup";
|
|
@@ -4479,7 +4341,7 @@ function readSpecTemplate(moduleDir = MODULE_DIR) {
|
|
|
4479
4341
|
if (!existsSync4(source)) {
|
|
4480
4342
|
throw new Error(`${PREFIX}: the spec issue template is missing: no file at ${source}`);
|
|
4481
4343
|
}
|
|
4482
|
-
return
|
|
4344
|
+
return readFileSync7(source, "utf8");
|
|
4483
4345
|
}
|
|
4484
4346
|
function writeSpecTemplate(root, moduleDir = MODULE_DIR) {
|
|
4485
4347
|
const path = join9(root, SPEC_TEMPLATE_PATH);
|
|
@@ -6439,7 +6301,7 @@ function writeInstall(context, install) {
|
|
|
6439
6301
|
}
|
|
6440
6302
|
|
|
6441
6303
|
// src/commands/doctor-refs.ts
|
|
6442
|
-
import { readdirSync, readFileSync as
|
|
6304
|
+
import { readdirSync, readFileSync as readFileSync8, statSync as statSync8 } from "fs";
|
|
6443
6305
|
import { join as join16, resolve as resolve5 } from "path";
|
|
6444
6306
|
function issueCheckCommand(issue) {
|
|
6445
6307
|
return `rafa issue check ${String(issue)}`;
|
|
@@ -6509,7 +6371,7 @@ async function readCopy(file, input, verify) {
|
|
|
6509
6371
|
const path = join16(input.specsDir, file.name);
|
|
6510
6372
|
const empty = { issue: file.issue, path, suspect: 0, dangling: 0, unknown: 0 };
|
|
6511
6373
|
try {
|
|
6512
|
-
const copy =
|
|
6374
|
+
const copy = readFileSync8(resolve5(input.root, path), "utf8");
|
|
6513
6375
|
const { rows } = await readRefsText({ copy, issue: file.issue, verify: await verify() });
|
|
6514
6376
|
const states = rows.map((row) => row.state);
|
|
6515
6377
|
return Object.freeze({
|
|
@@ -6801,14 +6663,14 @@ function renderBoard(board) {
|
|
|
6801
6663
|
}
|
|
6802
6664
|
|
|
6803
6665
|
// src/commands/doctor-tiers.ts
|
|
6804
|
-
import { readFileSync as
|
|
6666
|
+
import { readFileSync as readFileSync9, realpathSync as realpathSync4 } from "fs";
|
|
6805
6667
|
import { basename as basename5, dirname as dirname2 } from "path";
|
|
6806
6668
|
var TIERS_SECTION_TITLE = "Skill tiers";
|
|
6807
6669
|
var CLAUDE_VERSION_TIMEOUT_MS = 1e4;
|
|
6808
6670
|
var VERSION_PATTERN = /^\s*(\d+\.\d+\.\d+)/;
|
|
6809
6671
|
function readTextFile(path) {
|
|
6810
6672
|
try {
|
|
6811
|
-
return
|
|
6673
|
+
return readFileSync9(path, "utf8");
|
|
6812
6674
|
} catch {
|
|
6813
6675
|
return null;
|
|
6814
6676
|
}
|
|
@@ -6895,12 +6757,18 @@ function cliVersionRows(installed, pinned = SERVE_CLI_VERSION) {
|
|
|
6895
6757
|
}
|
|
6896
6758
|
return [row("cli-version", "warn", name2, `${installed} is installed, and skill delivery was probed against ${pinned}`, 'run the delivery probe again (context/inventory.md, "Serving") before trusting SERVE_CLI_VERSION')];
|
|
6897
6759
|
}
|
|
6760
|
+
function skillUseVersionRows(installed, pinned = SKILL_USE_CLI_VERSION) {
|
|
6761
|
+
if (installed === null || installed === pinned)
|
|
6762
|
+
return [];
|
|
6763
|
+
return [row("skill-use-version", "warn", "Claude Code", `${installed} is installed, and the skill-use collector reads logs of ${pinned}, ` + "so skill_invocations stores the skill counts of the sessions it logs as unknown", "record the skill-use fixture again under the installed version (src/effort/skill-use.ts) before moving SKILL_USE_CLI_VERSION")];
|
|
6764
|
+
}
|
|
6898
6765
|
function doctorTierRows(inventory, installed, readers = {}) {
|
|
6899
6766
|
const readText2 = readers.readText ?? readTextFile;
|
|
6900
6767
|
return [
|
|
6901
6768
|
...collisionRows(inventory.resolution.collisions),
|
|
6902
6769
|
...unreviewedRows(inventory.records, readText2),
|
|
6903
6770
|
...cliVersionRows(installed),
|
|
6771
|
+
...skillUseVersionRows(installed),
|
|
6904
6772
|
...copyRows(inventory.resolution.items, readers.realPath ?? realPathOf),
|
|
6905
6773
|
...noProvenanceRows(inventory, readText2)
|
|
6906
6774
|
];
|
|
@@ -7256,7 +7124,7 @@ var collect_default = wrapPhaseZeroCommand({
|
|
|
7256
7124
|
subject: "effort",
|
|
7257
7125
|
action: "collect",
|
|
7258
7126
|
summary: "collect session and commit rows into the effort store",
|
|
7259
|
-
description: "Reads the Claude Code session logs of this repo and its commit history, and appends every" + " session and commit the effort store does not hold yet to the store `store` in" + " `.rafa/config.yaml` selects. A run over an unchanged history appends nothing. An unrecognised" + " argument, a `--since` that is no date and a config the loop cannot run on are each refused," + " one line per problem.",
|
|
7127
|
+
description: "Reads the Claude Code session logs of this repo and its commit history, and appends every" + " session and commit the effort store does not hold yet to the store `store` in" + " `.rafa/config.yaml` selects, then counts the skills each appended session invoked into" + " `effort.sqlite`. A run over an unchanged history appends nothing. An unrecognised" + " argument, a `--since` that is no date and a config the loop cannot run on are each refused," + " one line per problem.",
|
|
7260
7128
|
args: [],
|
|
7261
7129
|
flags: [
|
|
7262
7130
|
{
|
|
@@ -7272,10 +7140,15 @@ var collect_default = wrapPhaseZeroCommand({
|
|
|
7272
7140
|
},
|
|
7273
7141
|
{
|
|
7274
7142
|
name: "sessions",
|
|
7275
|
-
description: "Collects session rows; `--no-sessions` skips them. Refused beside `--no-git`," + " which would leave nothing to collect.",
|
|
7143
|
+
description: "Collects session rows; `--no-sessions` skips them. Refused beside `--no-git`," + " which would leave nothing to collect, unless `--skills` is given.",
|
|
7276
7144
|
type: "boolean",
|
|
7277
7145
|
default: true
|
|
7278
7146
|
},
|
|
7147
|
+
{
|
|
7148
|
+
name: "skills",
|
|
7149
|
+
description: "Counts the `Skill` calls of every session the store already holds, not only the ones" + " this run appends. Lifts the refusal of `--no-git` beside `--no-sessions`.",
|
|
7150
|
+
type: "boolean"
|
|
7151
|
+
},
|
|
7279
7152
|
{
|
|
7280
7153
|
name: "verbose",
|
|
7281
7154
|
description: "Prints what each half found before the summary: the logs and plan stubs it read," + " each session read, and the commits parsed.",
|
|
@@ -7295,6 +7168,275 @@ var collect_default = wrapPhaseZeroCommand({
|
|
|
7295
7168
|
outputs: ["text", "json"]
|
|
7296
7169
|
}, collect);
|
|
7297
7170
|
|
|
7171
|
+
// src/effort/store/fix-schema.ts
|
|
7172
|
+
import { existsSync as existsSync5, renameSync, rmSync as rmSync2 } from "fs";
|
|
7173
|
+
import { Database } from "bun:sqlite";
|
|
7174
|
+
class SchemaFixRefusal extends Error {
|
|
7175
|
+
constructor(message) {
|
|
7176
|
+
super(message);
|
|
7177
|
+
this.name = "SchemaFixRefusal";
|
|
7178
|
+
}
|
|
7179
|
+
}
|
|
7180
|
+
var LIVE = "live";
|
|
7181
|
+
function quoted(name2) {
|
|
7182
|
+
return `"${name2.replaceAll('"', '""')}"`;
|
|
7183
|
+
}
|
|
7184
|
+
function tableNames(db, schema) {
|
|
7185
|
+
return db.query(`SELECT name FROM ${schema}.sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%' ORDER BY name`).all().map((row2) => row2.name);
|
|
7186
|
+
}
|
|
7187
|
+
function columnNames(db, schema, table) {
|
|
7188
|
+
return db.query("SELECT name FROM pragma_table_info(?, ?)").all(table, schema).map((row2) => row2.name);
|
|
7189
|
+
}
|
|
7190
|
+
function count(db, sql) {
|
|
7191
|
+
return db.query(sql).get()?.n ?? 0;
|
|
7192
|
+
}
|
|
7193
|
+
function versionOf(path) {
|
|
7194
|
+
const db = new Database(path, { readonly: true });
|
|
7195
|
+
try {
|
|
7196
|
+
return db.query("PRAGMA user_version").get()?.user_version ?? 0;
|
|
7197
|
+
} finally {
|
|
7198
|
+
db.close();
|
|
7199
|
+
}
|
|
7200
|
+
}
|
|
7201
|
+
function refuseInFlight(path) {
|
|
7202
|
+
for (const suffix of ["-journal", "-wal"]) {
|
|
7203
|
+
if (existsSync5(`${path}${suffix}`)) {
|
|
7204
|
+
throw new SchemaFixRefusal(`${path}${suffix} is there, so a write is in flight or was interrupted; stop whatever uses the store` + " and open it once with rafa before repairing it");
|
|
7205
|
+
}
|
|
7206
|
+
}
|
|
7207
|
+
}
|
|
7208
|
+
function refuseRemoved(db, known, live) {
|
|
7209
|
+
for (const table of known) {
|
|
7210
|
+
if (!live.has(table)) {
|
|
7211
|
+
throw new SchemaFixRefusal(`the store holds no table ${table}, which this rafa writes; its newer schema is not additive`);
|
|
7212
|
+
}
|
|
7213
|
+
const liveColumns = new Set(columnNames(db, LIVE, table));
|
|
7214
|
+
const missing = columnNames(db, "main", table).filter((column) => !liveColumns.has(column));
|
|
7215
|
+
if (missing.length > 0) {
|
|
7216
|
+
throw new SchemaFixRefusal(`the store holds no column ${missing.map((column) => `${table}.${column}`).join(", ")}, which this rafa` + " writes; its newer schema is not additive");
|
|
7217
|
+
}
|
|
7218
|
+
}
|
|
7219
|
+
}
|
|
7220
|
+
function copyKnown(db, known) {
|
|
7221
|
+
db.transaction(() => {
|
|
7222
|
+
for (const table of known) {
|
|
7223
|
+
const columns2 = columnNames(db, "main", table).map(quoted).join(", ");
|
|
7224
|
+
db.run(`INSERT INTO main.${quoted(table)} (${columns2}) SELECT ${columns2} FROM ${LIVE}.${quoted(table)}`);
|
|
7225
|
+
}
|
|
7226
|
+
})();
|
|
7227
|
+
}
|
|
7228
|
+
function checkedCounts(db, known) {
|
|
7229
|
+
return known.map((table) => {
|
|
7230
|
+
const rows = count(db, `SELECT count(*) AS n FROM main.${quoted(table)}`);
|
|
7231
|
+
const liveRows = count(db, `SELECT count(*) AS n FROM ${LIVE}.${quoted(table)}`);
|
|
7232
|
+
if (rows !== liveRows) {
|
|
7233
|
+
throw new SchemaFixRefusal(`the rebuilt ${table} holds ${String(rows)} rows, the store ${String(liveRows)}`);
|
|
7234
|
+
}
|
|
7235
|
+
return { table, rows };
|
|
7236
|
+
});
|
|
7237
|
+
}
|
|
7238
|
+
function leftBehind(db, known, live) {
|
|
7239
|
+
const leftTables = live.filter((table) => !known.has(table)).map((table) => ({ table, rows: count(db, `SELECT count(*) AS n FROM ${LIVE}.${quoted(table)}`) }));
|
|
7240
|
+
const leftColumns = live.filter((table) => known.has(table)).flatMap((table) => {
|
|
7241
|
+
const kept = new Set(columnNames(db, "main", table));
|
|
7242
|
+
return columnNames(db, LIVE, table).filter((column) => !kept.has(column)).map((column) => ({
|
|
7243
|
+
table,
|
|
7244
|
+
column,
|
|
7245
|
+
values: count(db, `SELECT count(*) AS n FROM ${LIVE}.${quoted(table)} WHERE ${quoted(column)} IS NOT NULL`)
|
|
7246
|
+
}));
|
|
7247
|
+
});
|
|
7248
|
+
return { leftTables, leftColumns };
|
|
7249
|
+
}
|
|
7250
|
+
function refuseCorrupt(db) {
|
|
7251
|
+
const answer = db.query("PRAGMA main.integrity_check").get()?.integrity_check;
|
|
7252
|
+
if (answer !== "ok")
|
|
7253
|
+
throw new SchemaFixRefusal(`the rebuilt store failed integrity_check: ${answer ?? "no answer"}`);
|
|
7254
|
+
}
|
|
7255
|
+
function buildParallel(path, parallelPath, migrations) {
|
|
7256
|
+
const db = new Database(parallelPath, { create: true, readwrite: true });
|
|
7257
|
+
try {
|
|
7258
|
+
migrateSchema(db, parallelPath, migrations);
|
|
7259
|
+
db.run(`ATTACH DATABASE ? AS ${LIVE}`, [path]);
|
|
7260
|
+
const known = tableNames(db, "main");
|
|
7261
|
+
const live = tableNames(db, LIVE);
|
|
7262
|
+
refuseRemoved(db, known, new Set(live));
|
|
7263
|
+
copyKnown(db, known);
|
|
7264
|
+
const kept = checkedCounts(db, known);
|
|
7265
|
+
const left = leftBehind(db, new Set(known), live);
|
|
7266
|
+
db.run(`DETACH DATABASE ${LIVE}`);
|
|
7267
|
+
refuseCorrupt(db);
|
|
7268
|
+
return { kept, ...left };
|
|
7269
|
+
} finally {
|
|
7270
|
+
db.close();
|
|
7271
|
+
}
|
|
7272
|
+
}
|
|
7273
|
+
function removeParallel(parallelPath) {
|
|
7274
|
+
rmSync2(parallelPath, { force: true });
|
|
7275
|
+
rmSync2(`${parallelPath}-journal`, { force: true });
|
|
7276
|
+
}
|
|
7277
|
+
function swapIn(path, parallelPath, backupPath) {
|
|
7278
|
+
renameSync(path, backupPath);
|
|
7279
|
+
try {
|
|
7280
|
+
renameSync(parallelPath, path);
|
|
7281
|
+
} catch (error) {
|
|
7282
|
+
renameSync(backupPath, path);
|
|
7283
|
+
throw error;
|
|
7284
|
+
}
|
|
7285
|
+
}
|
|
7286
|
+
function freshPaths(path, version2, stamp) {
|
|
7287
|
+
const parallelPath = `${path}.fix-${stamp}`;
|
|
7288
|
+
const backupPath = `${path}.v${String(version2)}-${stamp}.bak`;
|
|
7289
|
+
for (const taken of [parallelPath, backupPath]) {
|
|
7290
|
+
if (existsSync5(taken))
|
|
7291
|
+
throw new SchemaFixRefusal(`${taken} is already there; move it aside or pass another stamp`);
|
|
7292
|
+
}
|
|
7293
|
+
return { parallelPath, backupPath };
|
|
7294
|
+
}
|
|
7295
|
+
function fixStoreSchema(options) {
|
|
7296
|
+
const { path, dryRun, stamp } = options;
|
|
7297
|
+
const migrations = options.migrations ?? SQLITE_MIGRATIONS;
|
|
7298
|
+
const knownVersion = migrations.length;
|
|
7299
|
+
const nothing = { kept: [], leftTables: [], leftColumns: [], backupPath: null };
|
|
7300
|
+
if (!existsSync5(path))
|
|
7301
|
+
return { path, status: "missing", storeVersion: null, knownVersion, ...nothing };
|
|
7302
|
+
refuseInFlight(path);
|
|
7303
|
+
const storeVersion = versionOf(path);
|
|
7304
|
+
if (storeVersion === knownVersion)
|
|
7305
|
+
return { path, status: "current", storeVersion, knownVersion, ...nothing };
|
|
7306
|
+
if (storeVersion < knownVersion)
|
|
7307
|
+
return { path, status: "behind", storeVersion, knownVersion, ...nothing };
|
|
7308
|
+
const { parallelPath, backupPath } = freshPaths(path, storeVersion, stamp);
|
|
7309
|
+
let built;
|
|
7310
|
+
try {
|
|
7311
|
+
built = buildParallel(path, parallelPath, migrations);
|
|
7312
|
+
} catch (error) {
|
|
7313
|
+
removeParallel(parallelPath);
|
|
7314
|
+
throw error;
|
|
7315
|
+
}
|
|
7316
|
+
if (dryRun) {
|
|
7317
|
+
removeParallel(parallelPath);
|
|
7318
|
+
return { path, status: "would-rebuild", storeVersion, knownVersion, ...built, backupPath: null };
|
|
7319
|
+
}
|
|
7320
|
+
swapIn(path, parallelPath, backupPath);
|
|
7321
|
+
return { path, status: "rebuilt", storeVersion, knownVersion, ...built, backupPath };
|
|
7322
|
+
}
|
|
7323
|
+
|
|
7324
|
+
// src/commands/effort/fix-schema.ts
|
|
7325
|
+
var COMMAND_NAME5 = "rafa effort fix-schema";
|
|
7326
|
+
var FIX_SCHEMA_USAGE = "rafa effort fix-schema [--dry-run]";
|
|
7327
|
+
var DRY_RUN_FLAG2 = "dry-run";
|
|
7328
|
+
function fileStamp(date) {
|
|
7329
|
+
return date.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
|
|
7330
|
+
}
|
|
7331
|
+
function refuseLiveLoop(root, isAlive) {
|
|
7332
|
+
let records;
|
|
7333
|
+
try {
|
|
7334
|
+
records = readSessions(root, isAlive === undefined ? {} : { isAlive });
|
|
7335
|
+
} catch (error) {
|
|
7336
|
+
throw new CommandExit(1, `\u274C ${COMMAND_NAME5}: the loop's run records cannot be read, so a live loop cannot be ruled out: ${String(error)}`);
|
|
7337
|
+
}
|
|
7338
|
+
const live = records.find((record) => record.state === "running" || record.state === "paused");
|
|
7339
|
+
if (live === undefined)
|
|
7340
|
+
return;
|
|
7341
|
+
throw new CommandExit(1, `\u274C ${COMMAND_NAME5}: loop session ${live.sessionId} on ${live.branch} is ${live.state} and writes the store;` + ` stop it with \`rafa loop stop -s ${live.sessionId}\` first. \`--dry-run\` runs beside it.`);
|
|
7342
|
+
}
|
|
7343
|
+
function rebuildLines(result) {
|
|
7344
|
+
const rows = result.kept.reduce((sum, table) => sum + table.rows, 0);
|
|
7345
|
+
const kept = result.kept.map((table) => `${table.table} ${String(table.rows)}`).join(", ");
|
|
7346
|
+
const left = [
|
|
7347
|
+
...result.leftTables.map((table) => `table ${table.table} (${String(table.rows)} rows)`),
|
|
7348
|
+
...result.leftColumns.map((column) => `column ${column.table}.${column.column} (${String(column.values)} values)`)
|
|
7349
|
+
];
|
|
7350
|
+
return [
|
|
7351
|
+
`${result.path} is at schema version ${String(result.storeVersion)}, past the ${String(result.knownVersion)} this rafa knows.`,
|
|
7352
|
+
`Keeps ${String(result.kept.length)} tables, ${String(rows)} rows: ${kept}.`,
|
|
7353
|
+
left.length === 0 ? "Leaves nothing behind." : `Leaves behind, kept only in the backup: ${left.join("; ")}.`
|
|
7354
|
+
];
|
|
7355
|
+
}
|
|
7356
|
+
function renderFixSchema(result) {
|
|
7357
|
+
switch (result.status) {
|
|
7358
|
+
case "missing":
|
|
7359
|
+
return [`No effort store at ${result.path}: nothing to repair.`];
|
|
7360
|
+
case "current":
|
|
7361
|
+
return [`\u2705 ${result.path} is at schema version ${String(result.knownVersion)}, the one this rafa knows: nothing to repair.`];
|
|
7362
|
+
case "behind":
|
|
7363
|
+
return [
|
|
7364
|
+
`${result.path} is at schema version ${String(result.storeVersion)}, behind the ${String(result.knownVersion)} this rafa` + " knows; the next command that opens it migrates it. Nothing to repair."
|
|
7365
|
+
];
|
|
7366
|
+
case "would-rebuild":
|
|
7367
|
+
return [
|
|
7368
|
+
...rebuildLines(result),
|
|
7369
|
+
`\uD83D\uDD0D Dry run: the rebuild at version ${String(result.knownVersion)} was built, checked (row counts, integrity_check)` + " and deleted. Run without `--dry-run` to swap it in."
|
|
7370
|
+
];
|
|
7371
|
+
case "rebuilt":
|
|
7372
|
+
return [
|
|
7373
|
+
...rebuildLines(result),
|
|
7374
|
+
`\u2705 Rebuilt at version ${String(result.knownVersion)}. The original is kept whole at ${String(result.backupPath)};` + " rename it back to undo."
|
|
7375
|
+
];
|
|
7376
|
+
}
|
|
7377
|
+
}
|
|
7378
|
+
function runFixSchema(context, seams) {
|
|
7379
|
+
expectNoArgument(context.args, FIX_SCHEMA_USAGE);
|
|
7380
|
+
const dryRun = readSwitch(DRY_RUN_FLAG2, context.flags[DRY_RUN_FLAG2], `Usage: ${FIX_SCHEMA_USAGE}`);
|
|
7381
|
+
if (context.project === null)
|
|
7382
|
+
throw new Error(`${COMMAND_NAME5} runs inside a project, and was handed none`);
|
|
7383
|
+
const root = context.project.root;
|
|
7384
|
+
if (!dryRun)
|
|
7385
|
+
refuseLiveLoop(root, seams.isAlive);
|
|
7386
|
+
let result;
|
|
7387
|
+
try {
|
|
7388
|
+
result = fixStoreSchema({
|
|
7389
|
+
path: sqliteStorePath(root),
|
|
7390
|
+
dryRun,
|
|
7391
|
+
stamp: fileStamp((seams.now ?? (() => new Date))())
|
|
7392
|
+
});
|
|
7393
|
+
} catch (error) {
|
|
7394
|
+
if (error instanceof SchemaFixRefusal)
|
|
7395
|
+
throw new CommandExit(1, `\u274C ${COMMAND_NAME5}: ${error.message}`);
|
|
7396
|
+
throw error;
|
|
7397
|
+
}
|
|
7398
|
+
if (context.outputMode === "json") {
|
|
7399
|
+
context.output.result(result);
|
|
7400
|
+
return;
|
|
7401
|
+
}
|
|
7402
|
+
for (const line of renderFixSchema(result))
|
|
7403
|
+
context.output.info(line);
|
|
7404
|
+
}
|
|
7405
|
+
function createFixSchemaCommand(seams = {}) {
|
|
7406
|
+
const command = {
|
|
7407
|
+
name: "effort fix-schema",
|
|
7408
|
+
subject: "effort",
|
|
7409
|
+
action: "fix-schema",
|
|
7410
|
+
summary: "rebuild an effort store a newer rafa migrated at the version this rafa knows, keeping the original",
|
|
7411
|
+
description: "Repairs `.rafa/effort/effort.sqlite` when it is past the schema version this rafa knows, which" + " happens when newer code opens it, such as a plan's own branch code run while an older installed rafa" + " drives the loop. It builds a parallel store beside it at this rafa's version, copies every table and" + " column this rafa knows, checks the row counts and SQLite's integrity_check, and lists what only the" + " newer schema holds. Then it renames the original to `effort.sqlite.v<version>-<stamp>.bak`, whole, and" + " moves the rebuild into its place. A store at or behind this version, or no store, is left alone. It" + " refuses, changing nothing, while a loop session under the project is running or paused, while a" + " journal beside the store shows a write in flight, and when the newer schema lacks a table or column" + " this rafa writes. With `--output=json` the outcome is the data of the terminal result event. Starts no" + " session.",
|
|
7412
|
+
args: [],
|
|
7413
|
+
flags: [
|
|
7414
|
+
{
|
|
7415
|
+
name: DRY_RUN_FLAG2,
|
|
7416
|
+
description: "Build and check the rebuild, print what it keeps and leaves behind, then delete it. The" + " live store is only read, so this runs beside a live loop and can be repeated.",
|
|
7417
|
+
type: "boolean"
|
|
7418
|
+
}
|
|
7419
|
+
],
|
|
7420
|
+
examples: [
|
|
7421
|
+
{
|
|
7422
|
+
cmd: "rafa effort fix-schema --dry-run",
|
|
7423
|
+
note: "Prints what a rebuild would keep and leave behind, changing nothing."
|
|
7424
|
+
},
|
|
7425
|
+
{
|
|
7426
|
+
cmd: "rafa effort fix-schema",
|
|
7427
|
+
note: "Swaps the rebuild in and prints where the original was kept."
|
|
7428
|
+
}
|
|
7429
|
+
],
|
|
7430
|
+
outputs: ["text", "json"],
|
|
7431
|
+
run: async (context) => {
|
|
7432
|
+
runFixSchema(context, seams);
|
|
7433
|
+
await Promise.resolve();
|
|
7434
|
+
}
|
|
7435
|
+
};
|
|
7436
|
+
return Object.freeze(command);
|
|
7437
|
+
}
|
|
7438
|
+
var fix_schema_default = createFixSchemaCommand();
|
|
7439
|
+
|
|
7298
7440
|
// src/commands/effort/report.ts
|
|
7299
7441
|
var report_default = wrapPhaseZeroCommand({
|
|
7300
7442
|
name: "effort report",
|
|
@@ -7335,12 +7477,12 @@ var report_default = wrapPhaseZeroCommand({
|
|
|
7335
7477
|
}, report);
|
|
7336
7478
|
|
|
7337
7479
|
// src/commands/init.ts
|
|
7338
|
-
import { existsSync as
|
|
7480
|
+
import { existsSync as existsSync8, readFileSync as readFileSync14 } from "fs";
|
|
7339
7481
|
import { homedir } from "os";
|
|
7340
7482
|
import { join as join21, relative as relative6, sep as sep4 } from "path";
|
|
7341
7483
|
|
|
7342
7484
|
// src/agents/vendorable.ts
|
|
7343
|
-
import { readdirSync as readdirSync2, readFileSync as
|
|
7485
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync10 } from "fs";
|
|
7344
7486
|
import { isAbsolute as isAbsolute5, join as join17 } from "path";
|
|
7345
7487
|
function planFiles(dir) {
|
|
7346
7488
|
let entries;
|
|
@@ -7353,7 +7495,7 @@ function planFiles(dir) {
|
|
|
7353
7495
|
}
|
|
7354
7496
|
function readText2(path) {
|
|
7355
7497
|
try {
|
|
7356
|
-
return
|
|
7498
|
+
return readFileSync10(path, "utf8");
|
|
7357
7499
|
} catch {
|
|
7358
7500
|
return null;
|
|
7359
7501
|
}
|
|
@@ -7398,7 +7540,7 @@ function vendorableAgentWarnings(agents, root) {
|
|
|
7398
7540
|
|
|
7399
7541
|
// src/project/gitignore.ts
|
|
7400
7542
|
import { createHash } from "crypto";
|
|
7401
|
-
import { existsSync as
|
|
7543
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync11, writeFileSync as writeFileSync3 } from "fs";
|
|
7402
7544
|
import { dirname as dirname3, isAbsolute as isAbsolute6, join as join18 } from "path";
|
|
7403
7545
|
var GITIGNORE_FILE = ".gitignore";
|
|
7404
7546
|
var DIGEST_NAME = "tracking.digest";
|
|
@@ -7485,9 +7627,9 @@ function attempt(file, failure3, act) {
|
|
|
7485
7627
|
}
|
|
7486
7628
|
}
|
|
7487
7629
|
function readIfPresent2(file) {
|
|
7488
|
-
if (!
|
|
7630
|
+
if (!existsSync6(file))
|
|
7489
7631
|
return null;
|
|
7490
|
-
return attempt(file, "cannot be read", () =>
|
|
7632
|
+
return attempt(file, "cannot be read", () => readFileSync11(file, "utf8"));
|
|
7491
7633
|
}
|
|
7492
7634
|
function writeTrackingGitignore(root, flags) {
|
|
7493
7635
|
requireAbsolute(root);
|
|
@@ -7550,7 +7692,7 @@ import { resolve as resolve8 } from "path";
|
|
|
7550
7692
|
|
|
7551
7693
|
// src/project/roots.ts
|
|
7552
7694
|
import { spawnSync } from "child_process";
|
|
7553
|
-
import { accessSync, constants, readFileSync as
|
|
7695
|
+
import { accessSync, constants, readFileSync as readFileSync12, statSync as statSync9 } from "fs";
|
|
7554
7696
|
import { isAbsolute as isAbsolute7, join as join19, resolve as resolve7 } from "path";
|
|
7555
7697
|
var REFUSED_ROOTS = Object.freeze([
|
|
7556
7698
|
{ path: "/", why: "is the filesystem root" },
|
|
@@ -7571,7 +7713,7 @@ var PACKAGE_JSON = "package.json";
|
|
|
7571
7713
|
var NOT_A_REPOSITORY = "fatal: not a git repository (or any ";
|
|
7572
7714
|
var DISK_ROOTS_FILE_SYSTEM = Object.freeze({
|
|
7573
7715
|
...DISK_FILE_SYSTEM,
|
|
7574
|
-
readFile: (path) =>
|
|
7716
|
+
readFile: (path) => readFileSync12(path, "utf8"),
|
|
7575
7717
|
isDirectory: (path) => statSync9(path).isDirectory(),
|
|
7576
7718
|
assertWritable: (path) => accessSync(path, constants.W_OK)
|
|
7577
7719
|
});
|
|
@@ -7763,10 +7905,10 @@ function namedRoot(typed, start2, source, seams) {
|
|
|
7763
7905
|
return chosen(fs.realpath(path), source);
|
|
7764
7906
|
}
|
|
7765
7907
|
function numberedCandidate(digits, found) {
|
|
7766
|
-
const
|
|
7908
|
+
const count2 = found.candidates.length;
|
|
7767
7909
|
const candidate = found.candidates[Number(digits) - 1];
|
|
7768
7910
|
if (candidate === undefined) {
|
|
7769
|
-
return problem(`no candidate is numbered ${digits}; type 1 to ${String(
|
|
7911
|
+
return problem(`no candidate is numbered ${digits}; type 1 to ${String(count2)}, or a path`);
|
|
7770
7912
|
}
|
|
7771
7913
|
return candidate.refusal === null ? chosen(candidate.path, candidate.source) : problem(candidate.refusal.reason);
|
|
7772
7914
|
}
|
|
@@ -7796,7 +7938,7 @@ async function promptForRoot(found, prompter, seams) {
|
|
|
7796
7938
|
}
|
|
7797
7939
|
|
|
7798
7940
|
// src/project/scaffold.ts
|
|
7799
|
-
import { existsSync as
|
|
7941
|
+
import { existsSync as existsSync7, lstatSync as lstatSync2, mkdirSync as mkdirSync5, statSync as statSync10, writeFileSync as writeFileSync4 } from "fs";
|
|
7800
7942
|
import { join as join20 } from "path";
|
|
7801
7943
|
var PROJECT_TREE = Object.freeze(["specs", "plans", "runs", "effort", "instincts"]);
|
|
7802
7944
|
var USER_TREE = Object.freeze(["instincts"]);
|
|
@@ -7857,7 +7999,10 @@ var CONFIG_SETTINGS_LINES = Object.freeze([
|
|
|
7857
7999
|
"# skills: {} # name: false turns a skill off; name: project | rafa | user pins its tier",
|
|
7858
8000
|
"# agents: {} # name: false turns an agent off; name: project | rafa | user pins its tier",
|
|
7859
8001
|
"# routing:",
|
|
7860
|
-
...DEFAULT_ROUTES.map(([shape, agent]) => `# ${shape}: ${agent}`)
|
|
8002
|
+
...DEFAULT_ROUTES.map(([shape, agent]) => `# ${shape}: ${agent}`),
|
|
8003
|
+
"# task:",
|
|
8004
|
+
`# skills: ${CONFIG_DEFAULTS.taskSkills} # planner | tag | none, the resolver that picks a task's skills`,
|
|
8005
|
+
`# lessons: ${CONFIG_DEFAULTS.taskLessons} # on | off, whether blessed lessons join a task's prompt`
|
|
7861
8006
|
]);
|
|
7862
8007
|
var VERSION_LINE = `version: ${String(CONFIG_DEFAULTS.version)}`;
|
|
7863
8008
|
var PROJECT_HEADER = Object.freeze([
|
|
@@ -7906,7 +8051,7 @@ function isDirectory2(path) {
|
|
|
7906
8051
|
function directoryConflict(dir) {
|
|
7907
8052
|
if (!occupied(dir) || isDirectory2(dir))
|
|
7908
8053
|
return null;
|
|
7909
|
-
return
|
|
8054
|
+
return existsSync7(dir) ? `${dir} is not a directory` : `${dir} is a link to nothing`;
|
|
7910
8055
|
}
|
|
7911
8056
|
function layoutConflicts(layout) {
|
|
7912
8057
|
const [scopeDir, ...tree] = layout.dirs;
|
|
@@ -7914,7 +8059,7 @@ function layoutConflicts(layout) {
|
|
|
7914
8059
|
if (opening !== null)
|
|
7915
8060
|
return [opening];
|
|
7916
8061
|
const dirs = tree.flatMap((dir) => directoryConflict(dir) ?? []);
|
|
7917
|
-
const file = occupied(layout.configFile) && !
|
|
8062
|
+
const file = occupied(layout.configFile) && !existsSync7(layout.configFile) ? [`${layout.configFile} is a link to nothing`] : [];
|
|
7918
8063
|
return [...dirs, ...file];
|
|
7919
8064
|
}
|
|
7920
8065
|
function scaffoldConflicts(root, home) {
|
|
@@ -7928,7 +8073,7 @@ function attempt2(path, failure3, act) {
|
|
|
7928
8073
|
}
|
|
7929
8074
|
}
|
|
7930
8075
|
function ensureDirectory(path) {
|
|
7931
|
-
if (
|
|
8076
|
+
if (existsSync7(path))
|
|
7932
8077
|
return { path, kind: "directory", change: "unchanged" };
|
|
7933
8078
|
attempt2(path, "cannot be created", () => {
|
|
7934
8079
|
mkdirSync5(path, { recursive: true });
|
|
@@ -7936,7 +8081,7 @@ function ensureDirectory(path) {
|
|
|
7936
8081
|
return { path, kind: "directory", change: "created" };
|
|
7937
8082
|
}
|
|
7938
8083
|
function ensureFile(path, text) {
|
|
7939
|
-
if (
|
|
8084
|
+
if (existsSync7(path))
|
|
7940
8085
|
return { path, kind: "file", change: "unchanged" };
|
|
7941
8086
|
attempt2(path, "cannot be written", () => {
|
|
7942
8087
|
writeFileSync4(path, text, { encoding: "utf8", flag: "wx" });
|
|
@@ -7959,7 +8104,7 @@ function writeUserScope(home) {
|
|
|
7959
8104
|
import { writeFileSync as writeFileSync5 } from "fs";
|
|
7960
8105
|
|
|
7961
8106
|
// src/release/setting.ts
|
|
7962
|
-
import { readFileSync as
|
|
8107
|
+
import { readFileSync as readFileSync13 } from "fs";
|
|
7963
8108
|
var RELEASE_ENABLED_SETTING = "release.enabled";
|
|
7964
8109
|
function releaseEnabledIn(text, path) {
|
|
7965
8110
|
return parseConfigText(text, path).values.releaseEnabled ?? null;
|
|
@@ -7968,7 +8113,7 @@ function readReleaseSetting(root) {
|
|
|
7968
8113
|
const path = configFilePath(root);
|
|
7969
8114
|
let text;
|
|
7970
8115
|
try {
|
|
7971
|
-
text =
|
|
8116
|
+
text = readFileSync13(path, "utf8");
|
|
7972
8117
|
} catch (error) {
|
|
7973
8118
|
return { enabled: null, text: "", problem: `${path} could not be read: ${messageOf(error)}` };
|
|
7974
8119
|
}
|
|
@@ -8245,7 +8390,7 @@ function resolvedConfig2(root, home, warn) {
|
|
|
8245
8390
|
function checkGitignore(root, flags) {
|
|
8246
8391
|
const file = join21(root, GITIGNORE_FILE);
|
|
8247
8392
|
try {
|
|
8248
|
-
const text =
|
|
8393
|
+
const text = existsSync8(file) ? readFileSync14(file, "utf8") : null;
|
|
8249
8394
|
withTrackingBlock(text, flags, file);
|
|
8250
8395
|
} catch (error) {
|
|
8251
8396
|
const message = error instanceof GitignoreError ? error.message : `rafa init: ${file} cannot be read (${messageOf(error)})`;
|
|
@@ -8276,8 +8421,8 @@ function initialise(root, start2, home, context, entry) {
|
|
|
8276
8421
|
checkConflicts(root.path, home);
|
|
8277
8422
|
const config = resolvedConfig2(root.path, home, warn);
|
|
8278
8423
|
checkGitignore(root.path, config);
|
|
8279
|
-
const configExisted =
|
|
8280
|
-
const digestExisted =
|
|
8424
|
+
const configExisted = existsSync8(configFilePath(root.path));
|
|
8425
|
+
const digestExisted = existsSync8(join21(root.path, TRACKING_DIGEST_FILE));
|
|
8281
8426
|
const project = writeProjectScope(root.path);
|
|
8282
8427
|
const tracking = applyTracking(root.path, config, warn);
|
|
8283
8428
|
const writes = [...project, ...trackingWrites(tracking, digestExisted), ...writeUserScope(home)];
|
|
@@ -9100,7 +9245,7 @@ function createInstinctShowCommand() {
|
|
|
9100
9245
|
var show_default2 = createInstinctShowCommand();
|
|
9101
9246
|
|
|
9102
9247
|
// src/commands/issue/check.ts
|
|
9103
|
-
import { readdirSync as readdirSync3, readFileSync as
|
|
9248
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync15, statSync as statSync11 } from "fs";
|
|
9104
9249
|
import { join as join22, resolve as resolve10 } from "path";
|
|
9105
9250
|
var CHECK_USAGE = "rafa issue check <n> [--stamp]";
|
|
9106
9251
|
var STAMP_FLAG = "stamp";
|
|
@@ -9177,7 +9322,7 @@ function checkedRefLine(ref) {
|
|
|
9177
9322
|
}
|
|
9178
9323
|
function countLine(references) {
|
|
9179
9324
|
const noun = references.length === 1 ? "reference" : "references";
|
|
9180
|
-
const counts = STATE_ORDER.map((state) => [state, references.filter((ref) => ref.state === state).length]).filter(([,
|
|
9325
|
+
const counts = STATE_ORDER.map((state) => [state, references.filter((ref) => ref.state === state).length]).filter(([, count2]) => count2 > 0).map(([state, count2]) => `${String(count2)} ${state}`);
|
|
9181
9326
|
return counts.length === 0 ? "No references." : `${String(references.length)} ${noun}: ${counts.join(", ")}`;
|
|
9182
9327
|
}
|
|
9183
9328
|
function renderCheck2(result) {
|
|
@@ -9196,7 +9341,7 @@ async function readReferences(absolute, issue, verify, stamp) {
|
|
|
9196
9341
|
return rows.map((row2) => checkedRef(row2, row2.stamp));
|
|
9197
9342
|
}
|
|
9198
9343
|
const once = memoiseVerifier(verify);
|
|
9199
|
-
const before = await readRefsText({ copy:
|
|
9344
|
+
const before = await readRefsText({ copy: readFileSync15(absolute, "utf8"), issue, verify: once });
|
|
9200
9345
|
const after = await restampCopyRefs({ path: absolute, issue, verify: once });
|
|
9201
9346
|
return before.rows.map((row2, index) => checkedRef(row2, after.rows[index]?.stamp ?? null));
|
|
9202
9347
|
}
|
|
@@ -10603,6 +10748,11 @@ var wrapped = wrapPhaseZeroCommand({
|
|
|
10603
10748
|
description: "How much of the plan each task session is handed: `full`, `stage` or `task`." + " Outranks `plan.inject` in `.rafa/config.yaml`. The wrap-up is handed the whole plan.",
|
|
10604
10749
|
type: "string"
|
|
10605
10750
|
},
|
|
10751
|
+
{
|
|
10752
|
+
name: "skills-resolver",
|
|
10753
|
+
description: "The resolver that picks the skills each task session is handed: `planner`, `tag`" + " or `none`. Outranks `task.skills` in `.rafa/config.yaml` for this run only.",
|
|
10754
|
+
type: "string"
|
|
10755
|
+
},
|
|
10606
10756
|
{
|
|
10607
10757
|
name: "runtime",
|
|
10608
10758
|
description: "The installed rafa the run goes on in: a version under `~/.rafa/runtime/`, or a path" + " against the working directory to a `cli.js` or the directory holding it. Refused inside the" + " `src/` of the working directory or the project root. Typed after `loop start`.",
|
|
@@ -11082,7 +11232,7 @@ function fastForwardBase(git, plan2) {
|
|
|
11082
11232
|
|
|
11083
11233
|
// src/commands/next.ts
|
|
11084
11234
|
var NEXT_USAGE = "rafa next [--dry-run] [--yes[=<action ids>]]";
|
|
11085
|
-
var
|
|
11235
|
+
var DRY_RUN_FLAG3 = "dry-run";
|
|
11086
11236
|
var STATE_MARK = "\uD83D\uDCCD";
|
|
11087
11237
|
var PROPOSAL_MARK = "\uD83D\uDC49";
|
|
11088
11238
|
var STOP_MARK = "\u23F9";
|
|
@@ -11103,7 +11253,7 @@ function dryRunLine(dryRun) {
|
|
|
11103
11253
|
if (dryRun === "no-terminal") {
|
|
11104
11254
|
return `${STOP_MARK} There is no terminal to answer on, so nothing ran; run rafa next where you can answer,` + ` or type --${YES_FLAG}=${BARE_YES_ACTIONS.join(",")} to allow those steps unasked.`;
|
|
11105
11255
|
}
|
|
11106
|
-
return `${STOP_MARK} --${
|
|
11256
|
+
return `${STOP_MARK} --${DRY_RUN_FLAG3}: nothing ran.`;
|
|
11107
11257
|
}
|
|
11108
11258
|
function stopLine(stop, state, ceiling, dryRun) {
|
|
11109
11259
|
if (stop === "dry-run")
|
|
@@ -11199,14 +11349,14 @@ function lineRefusal2(problem2) {
|
|
|
11199
11349
|
Usage: ${NEXT_USAGE}`);
|
|
11200
11350
|
}
|
|
11201
11351
|
function readDryRun(flags) {
|
|
11202
|
-
const value = flags[
|
|
11352
|
+
const value = flags[DRY_RUN_FLAG3];
|
|
11203
11353
|
if (value === undefined)
|
|
11204
11354
|
return false;
|
|
11205
11355
|
if (typeof value === "boolean")
|
|
11206
11356
|
return value;
|
|
11207
11357
|
if (value === "true" || value === "false")
|
|
11208
11358
|
return value === "true";
|
|
11209
|
-
throw lineRefusal2(`--${
|
|
11359
|
+
throw lineRefusal2(`--${DRY_RUN_FLAG3} takes no value, and read "${value}" as one`);
|
|
11210
11360
|
}
|
|
11211
11361
|
function dryRunOf(flag, ceiling, hasTerminal) {
|
|
11212
11362
|
if (flag)
|
|
@@ -11258,7 +11408,7 @@ async function runNext(context, seams) {
|
|
|
11258
11408
|
var YES_ID_LIST = YES_ACTIONS.join(", ");
|
|
11259
11409
|
var NEXT_FLAGS = Object.freeze([
|
|
11260
11410
|
{
|
|
11261
|
-
name:
|
|
11411
|
+
name: DRY_RUN_FLAG3,
|
|
11262
11412
|
description: "Print where the project stands and what to do about it, and stop without asking or running it." + " A run with no terminal to answer on and no --yes does this whether or not the flag is typed.",
|
|
11263
11413
|
type: "boolean"
|
|
11264
11414
|
},
|
|
@@ -11395,7 +11545,7 @@ var wrapped2 = wrapPhaseZeroCommand({
|
|
|
11395
11545
|
var create_default2 = endingWith(wrapped2);
|
|
11396
11546
|
|
|
11397
11547
|
// src/commands/plan/risk.ts
|
|
11398
|
-
import { readFileSync as
|
|
11548
|
+
import { readFileSync as readFileSync16 } from "fs";
|
|
11399
11549
|
import { resolve as resolve11 } from "path";
|
|
11400
11550
|
var COMMAND2 = "rafa plan risk";
|
|
11401
11551
|
var USAGE22 = "rafa plan risk [<plan>] [--strict]";
|
|
@@ -11423,7 +11573,7 @@ function strictRefusal(report2) {
|
|
|
11423
11573
|
}
|
|
11424
11574
|
async function readRisk(path, project, config, context, seams) {
|
|
11425
11575
|
const makeRunners = seams.runners ?? spawningRunners;
|
|
11426
|
-
return assessPlanRisk({ path, text:
|
|
11576
|
+
return assessPlanRisk({ path, text: readFileSync16(path, "utf8") }, {
|
|
11427
11577
|
repoRoot: project.root,
|
|
11428
11578
|
home: project.home,
|
|
11429
11579
|
settingSources: config.settingSources,
|
|
@@ -11506,7 +11656,7 @@ function createPlanRiskCommand(seams = {}) {
|
|
|
11506
11656
|
var risk_default = createPlanRiskCommand();
|
|
11507
11657
|
|
|
11508
11658
|
// src/commands/plan/show.ts
|
|
11509
|
-
import { readFileSync as
|
|
11659
|
+
import { readFileSync as readFileSync17 } from "fs";
|
|
11510
11660
|
import { join as join23 } from "path";
|
|
11511
11661
|
var USAGE23 = "rafa plan show <stub> [--tracker]";
|
|
11512
11662
|
var COMMAND3 = "rafa plan show";
|
|
@@ -11528,7 +11678,7 @@ function showPlan(plans, stub, tracker) {
|
|
|
11528
11678
|
const file = join23(plans.path, name2);
|
|
11529
11679
|
if (!isFile(file))
|
|
11530
11680
|
throw new CommandExit(1, missingText(stub, tracker, join23(plans.label, name2)));
|
|
11531
|
-
const model = parsePlan(
|
|
11681
|
+
const model = parsePlan(readFileSync17(file, "utf8"));
|
|
11532
11682
|
const { header } = model;
|
|
11533
11683
|
return {
|
|
11534
11684
|
stub,
|
|
@@ -11872,8 +12022,8 @@ function titleCell(title) {
|
|
|
11872
12022
|
return "(no title)";
|
|
11873
12023
|
return trimmed.length > TITLE_WIDTH ? `${trimmed.slice(0, TITLE_WIDTH - CUT.length)}${CUT}` : trimmed;
|
|
11874
12024
|
}
|
|
11875
|
-
function headLine3(
|
|
11876
|
-
return
|
|
12025
|
+
function headLine3(count2) {
|
|
12026
|
+
return count2 === 1 ? "1 open pull request" : `${count2} open pull requests`;
|
|
11877
12027
|
}
|
|
11878
12028
|
function cellsOf(row2, now) {
|
|
11879
12029
|
return [
|
|
@@ -11970,7 +12120,7 @@ function createPrListCommand(seams = DEFAULT_PR_SEAMS) {
|
|
|
11970
12120
|
var list_default8 = createPrListCommand();
|
|
11971
12121
|
|
|
11972
12122
|
// src/commands/pr/merge.ts
|
|
11973
|
-
import { existsSync as
|
|
12123
|
+
import { existsSync as existsSync10, readFileSync as readFileSync19 } from "fs";
|
|
11974
12124
|
import { join as join25 } from "path";
|
|
11975
12125
|
|
|
11976
12126
|
// src/board/roadmap-tick.ts
|
|
@@ -12126,13 +12276,13 @@ function tickSentence(result) {
|
|
|
12126
12276
|
import {
|
|
12127
12277
|
chmodSync,
|
|
12128
12278
|
copyFileSync as copyFileSync3,
|
|
12129
|
-
existsSync as
|
|
12279
|
+
existsSync as existsSync9,
|
|
12130
12280
|
mkdirSync as mkdirSync6,
|
|
12131
12281
|
readdirSync as readdirSync5,
|
|
12132
|
-
readFileSync as
|
|
12282
|
+
readFileSync as readFileSync18,
|
|
12133
12283
|
realpathSync as realpathSync5,
|
|
12134
|
-
renameSync,
|
|
12135
|
-
rmSync as
|
|
12284
|
+
renameSync as renameSync2,
|
|
12285
|
+
rmSync as rmSync3,
|
|
12136
12286
|
statSync as statSync12,
|
|
12137
12287
|
symlinkSync
|
|
12138
12288
|
} from "fs";
|
|
@@ -12202,12 +12352,12 @@ function listTrackers(repoRoot, planDir) {
|
|
|
12202
12352
|
}
|
|
12203
12353
|
function openTrackers(repoRoot, planDir) {
|
|
12204
12354
|
return listTrackers(repoRoot, planDir).flatMap((path) => {
|
|
12205
|
-
const task = findNextTask(
|
|
12355
|
+
const task = findNextTask(readFileSync18(join24(repoRoot, path), "utf8"));
|
|
12206
12356
|
return task ? [{ path, task }] : [];
|
|
12207
12357
|
});
|
|
12208
12358
|
}
|
|
12209
12359
|
function readManifestVersion2(repoRoot) {
|
|
12210
|
-
const manifest = JSON.parse(
|
|
12360
|
+
const manifest = JSON.parse(readFileSync18(join24(repoRoot, "package.json"), "utf8"));
|
|
12211
12361
|
const record = typeof manifest === "object" && manifest !== null ? manifest : {};
|
|
12212
12362
|
if (record["name"] !== name) {
|
|
12213
12363
|
throw new Error(`${join24(repoRoot, "package.json")} names ${JSON.stringify(record["name"])}, not ${name}: this is no rafa checkout`);
|
|
@@ -12238,41 +12388,41 @@ function copyTree(from, to) {
|
|
|
12238
12388
|
}
|
|
12239
12389
|
function replaceTree(from, to) {
|
|
12240
12390
|
const staging = temporaryName(to);
|
|
12241
|
-
|
|
12391
|
+
rmSync3(staging, { recursive: true, force: true });
|
|
12242
12392
|
try {
|
|
12243
12393
|
const copied = copyTree(from, staging);
|
|
12244
|
-
|
|
12394
|
+
swapIn2(staging, to);
|
|
12245
12395
|
return copied;
|
|
12246
12396
|
} catch (err) {
|
|
12247
|
-
|
|
12397
|
+
rmSync3(staging, { recursive: true, force: true });
|
|
12248
12398
|
throw err;
|
|
12249
12399
|
}
|
|
12250
12400
|
}
|
|
12251
|
-
function
|
|
12252
|
-
if (!
|
|
12253
|
-
|
|
12401
|
+
function swapIn2(staging, to) {
|
|
12402
|
+
if (!existsSync9(to)) {
|
|
12403
|
+
renameSync2(staging, to);
|
|
12254
12404
|
return;
|
|
12255
12405
|
}
|
|
12256
12406
|
const outgoing = `${temporaryName(to)}.outgoing`;
|
|
12257
|
-
|
|
12258
|
-
|
|
12407
|
+
rmSync3(outgoing, { recursive: true, force: true });
|
|
12408
|
+
renameSync2(to, outgoing);
|
|
12259
12409
|
try {
|
|
12260
|
-
|
|
12410
|
+
renameSync2(staging, to);
|
|
12261
12411
|
} catch (err) {
|
|
12262
|
-
|
|
12412
|
+
renameSync2(outgoing, to);
|
|
12263
12413
|
throw err;
|
|
12264
12414
|
}
|
|
12265
|
-
|
|
12415
|
+
rmSync3(outgoing, { recursive: true, force: true });
|
|
12266
12416
|
}
|
|
12267
12417
|
function relink(linkPath, target) {
|
|
12268
12418
|
mkdirSync6(dirname4(linkPath), { recursive: true });
|
|
12269
12419
|
const temporary = temporaryName(linkPath);
|
|
12270
|
-
|
|
12420
|
+
rmSync3(temporary, { force: true });
|
|
12271
12421
|
try {
|
|
12272
12422
|
symlinkSync(target, temporary);
|
|
12273
|
-
|
|
12423
|
+
renameSync2(temporary, linkPath);
|
|
12274
12424
|
} catch (err) {
|
|
12275
|
-
|
|
12425
|
+
rmSync3(temporary, { force: true });
|
|
12276
12426
|
throw err;
|
|
12277
12427
|
}
|
|
12278
12428
|
const resolved = realpathSync5(linkPath);
|
|
@@ -12332,7 +12482,7 @@ function runInstall(seams, options) {
|
|
|
12332
12482
|
return { kind: "refused", reason: "trackers", planDir, trackers: open };
|
|
12333
12483
|
const distDir = join24(repoRoot, "dist");
|
|
12334
12484
|
const runtimeDir = join24(runtimeRoot, version2);
|
|
12335
|
-
const installed =
|
|
12485
|
+
const installed = existsSync9(runtimeDir);
|
|
12336
12486
|
if (installed && options.force !== true) {
|
|
12337
12487
|
return { kind: "refused", reason: "runtime-exists", version: version2, runtimeDir };
|
|
12338
12488
|
}
|
|
@@ -12340,7 +12490,7 @@ function runInstall(seams, options) {
|
|
|
12340
12490
|
const code = inStage("build", () => seams.build(repoRoot));
|
|
12341
12491
|
if (code !== 0)
|
|
12342
12492
|
throw new StageFailure("build", `the build exited ${code}`);
|
|
12343
|
-
if (!
|
|
12493
|
+
if (!existsSync9(join24(distDir, RUNTIME_ENTRY))) {
|
|
12344
12494
|
throw new StageFailure("build", `the build exited 0 and left no ${join24(distDir, RUNTIME_ENTRY)}`);
|
|
12345
12495
|
}
|
|
12346
12496
|
log(installed ? `copying ${distDir} over ${runtimeDir}, replacing it whole` : `copying ${distDir} into ${runtimeDir}`);
|
|
@@ -12373,9 +12523,9 @@ function replaceFile(source, target) {
|
|
|
12373
12523
|
try {
|
|
12374
12524
|
copyFileSync3(source, temporary);
|
|
12375
12525
|
chmodSync(temporary, statSync12(source).mode & 4095);
|
|
12376
|
-
|
|
12526
|
+
renameSync2(temporary, target);
|
|
12377
12527
|
} catch (err) {
|
|
12378
|
-
|
|
12528
|
+
rmSync3(temporary, { force: true });
|
|
12379
12529
|
throw err;
|
|
12380
12530
|
}
|
|
12381
12531
|
}
|
|
@@ -12573,11 +12723,11 @@ async function confirmUncheckedMerge(unchecked, options) {
|
|
|
12573
12723
|
}
|
|
12574
12724
|
}
|
|
12575
12725
|
function commentProblemLine(number, problem2, body) {
|
|
12576
|
-
const
|
|
12726
|
+
const quoted2 = body.split(`
|
|
12577
12727
|
`).map((line) => `${INDENT3}${line}`).join(`
|
|
12578
12728
|
`);
|
|
12579
12729
|
return `the unchecked-merge comment was not posted on #${number}: ${problem2}. Post it yourself:
|
|
12580
|
-
${
|
|
12730
|
+
${quoted2}`;
|
|
12581
12731
|
}
|
|
12582
12732
|
async function postUncheckedComment(pulls, number, unchecked, warn) {
|
|
12583
12733
|
const body = unchecked.reading.comment;
|
|
@@ -12671,7 +12821,7 @@ function remoteHoldsBranch(git, branch, warn) {
|
|
|
12671
12821
|
}
|
|
12672
12822
|
function textOf(path) {
|
|
12673
12823
|
try {
|
|
12674
|
-
return
|
|
12824
|
+
return readFileSync19(path, "utf8");
|
|
12675
12825
|
} catch {
|
|
12676
12826
|
return "";
|
|
12677
12827
|
}
|
|
@@ -12685,7 +12835,7 @@ function followUpsFor(pr, git) {
|
|
|
12685
12835
|
version: facts.version,
|
|
12686
12836
|
tagged: tags.ok && tags.stdout.trim() !== "",
|
|
12687
12837
|
rafaCheckout: facts.rafaCheckout,
|
|
12688
|
-
runtimeInstalled:
|
|
12838
|
+
runtimeInstalled: existsSync10(join25(pr.project.home, RUNTIME_SUBDIR, facts.version))
|
|
12689
12839
|
});
|
|
12690
12840
|
}
|
|
12691
12841
|
function openGh(pr, seams) {
|
|
@@ -13066,8 +13216,8 @@ function fencedBlock(body, language) {
|
|
|
13066
13216
|
return `${fence}${language}
|
|
13067
13217
|
${text}${fence}`;
|
|
13068
13218
|
}
|
|
13069
|
-
function counted2(
|
|
13070
|
-
return
|
|
13219
|
+
function counted2(count2, noun) {
|
|
13220
|
+
return count2 === 1 ? `1 ${noun}` : `${count2} ${noun}s`;
|
|
13071
13221
|
}
|
|
13072
13222
|
function excerptCaption(reading) {
|
|
13073
13223
|
const shown = counted2(reading.lines.length, "line");
|
|
@@ -13236,17 +13386,17 @@ function readTriageBlock(body) {
|
|
|
13236
13386
|
}
|
|
13237
13387
|
return readFields(document);
|
|
13238
13388
|
}
|
|
13239
|
-
function
|
|
13389
|
+
function quoted2(value) {
|
|
13240
13390
|
return JSON.stringify(value);
|
|
13241
13391
|
}
|
|
13242
13392
|
function writeTriageBlock(fields) {
|
|
13243
13393
|
return [
|
|
13244
|
-
`head: ${
|
|
13245
|
-
`at: ${
|
|
13246
|
-
`class: ${
|
|
13394
|
+
`head: ${quoted2(fields.head)}`,
|
|
13395
|
+
`at: ${quoted2(fields.at)}`,
|
|
13396
|
+
`class: ${quoted2(fields.triageClass)}`,
|
|
13247
13397
|
`simple: ${String(fields.simple)}`,
|
|
13248
13398
|
`attempts: ${String(fields.attempts)}`,
|
|
13249
|
-
`files: [${fields.files.map((file) =>
|
|
13399
|
+
`files: [${fields.files.map((file) => quoted2(file)).join(", ")}]`
|
|
13250
13400
|
].join(`
|
|
13251
13401
|
`);
|
|
13252
13402
|
}
|
|
@@ -13276,10 +13426,10 @@ function noChecksLines(input) {
|
|
|
13276
13426
|
return [];
|
|
13277
13427
|
const number = input.pr.number;
|
|
13278
13428
|
const unchecked = readUnchecked(number, input.workflowCount ?? null);
|
|
13279
|
-
const [
|
|
13429
|
+
const [count2 = "", warning = ""] = unchecked.warning;
|
|
13280
13430
|
const yes = unchecked.yesMayAnswer ? "`--yes` may answer it" : "`--yes` is refused, so a person must answer it";
|
|
13281
13431
|
return [
|
|
13282
|
-
`- Workflows: ${
|
|
13432
|
+
`- Workflows: ${count2}`,
|
|
13283
13433
|
`- Warning: ${warning}`,
|
|
13284
13434
|
`- To merge it anyway: \`${skipChecksCommand(number)}\` (it asks first; ${yes})`
|
|
13285
13435
|
];
|
|
@@ -13671,8 +13821,8 @@ function readsAsConflicting(pr, conflictFiles) {
|
|
|
13671
13821
|
return true;
|
|
13672
13822
|
return conflictFiles.length > 0;
|
|
13673
13823
|
}
|
|
13674
|
-
function checkCount(
|
|
13675
|
-
return
|
|
13824
|
+
function checkCount(count2) {
|
|
13825
|
+
return count2 === 1 ? "1 check" : `${count2} checks`;
|
|
13676
13826
|
}
|
|
13677
13827
|
function fileList(files) {
|
|
13678
13828
|
const shown = files.slice(0, REASON_FILE_LIMIT).join(", ");
|
|
@@ -13683,12 +13833,12 @@ function conflictReason(files) {
|
|
|
13683
13833
|
return files.length === 0 ? "the head conflicts with the base and no conflicting file was read" : `the head conflicts with the base on ${fileList(files)}`;
|
|
13684
13834
|
}
|
|
13685
13835
|
function failureReason(step, failing) {
|
|
13686
|
-
const
|
|
13687
|
-
return step === undefined ? `${
|
|
13836
|
+
const count2 = checkCount(failing.length);
|
|
13837
|
+
return step === undefined ? `${count2} failing, and no failing step was named` : `${count2} failing, the failing step being "${step.name}"`;
|
|
13688
13838
|
}
|
|
13689
13839
|
function noChecksReason(number, workflowCount) {
|
|
13690
|
-
const
|
|
13691
|
-
return `the head reports no checks at all; ${
|
|
13840
|
+
const count2 = workflowCountLine(workflowCount).replace(/\.$/, "");
|
|
13841
|
+
return `the head reports no checks at all; ${count2.charAt(0).toLowerCase()}${count2.slice(1)};` + ` to merge it anyway, run rafa pr merge ${number} --skip-checks`;
|
|
13692
13842
|
}
|
|
13693
13843
|
function decideClass(input, verdict, conflicting) {
|
|
13694
13844
|
const { conflictFiles, rows, step } = input;
|
|
@@ -13770,8 +13920,8 @@ function isSameHead(stored, head) {
|
|
|
13770
13920
|
function shortHead(head) {
|
|
13771
13921
|
return head.trim().slice(0, HEADLINE_HEAD_LENGTH);
|
|
13772
13922
|
}
|
|
13773
|
-
function checkCount2(
|
|
13774
|
-
return
|
|
13923
|
+
function checkCount2(count2) {
|
|
13924
|
+
return count2 === 1 ? "1 check" : `${count2} checks`;
|
|
13775
13925
|
}
|
|
13776
13926
|
function storedTime(comment, block) {
|
|
13777
13927
|
if (comment === null)
|
|
@@ -13873,8 +14023,8 @@ function isFreshCandidate(updatedAt, now) {
|
|
|
13873
14023
|
const age = ageMs(updatedAt, now);
|
|
13874
14024
|
return age !== null && age <= TRIAGE_FRESH_WINDOW_MS;
|
|
13875
14025
|
}
|
|
13876
|
-
function plural4(
|
|
13877
|
-
return
|
|
14026
|
+
function plural4(count2, singular, many) {
|
|
14027
|
+
return count2 === 1 ? `1 ${singular}` : `${count2} ${many}`;
|
|
13878
14028
|
}
|
|
13879
14029
|
function describeAge(updatedAt, now) {
|
|
13880
14030
|
const age = ageMs(updatedAt, now);
|
|
@@ -13938,17 +14088,17 @@ function listing(decision, assess, rest, headline, exitCode = 0) {
|
|
|
13938
14088
|
`)
|
|
13939
14089
|
});
|
|
13940
14090
|
}
|
|
13941
|
-
function refusal6(rest,
|
|
13942
|
-
const headline = `${REFUSAL_PREFIX2}: ${plural4(
|
|
14091
|
+
function refusal6(rest, count2) {
|
|
14092
|
+
const headline = `${REFUSAL_PREFIX2}: ${plural4(count2, "red pull request", "red pull requests")}, ` + "and --resolve acts on one. Run one of:";
|
|
13943
14093
|
return listing("refuse", Object.freeze([]), rest, headline, REFUSE_EXIT_CODE);
|
|
13944
14094
|
}
|
|
13945
|
-
function someReading(fresh, stale,
|
|
14095
|
+
function someReading(fresh, stale, count2) {
|
|
13946
14096
|
const older = stale.length === 0 ? "" : `; ${plural4(stale.length, "older one is", "older ones are")} skipped`;
|
|
13947
|
-
const headline = `${
|
|
14097
|
+
const headline = `${count2} red: assessing ${joinNumbers(fresh)}${older}`;
|
|
13948
14098
|
return listing("some", fresh, stale, headline);
|
|
13949
14099
|
}
|
|
13950
|
-
function listReading(rest,
|
|
13951
|
-
const headline =
|
|
14100
|
+
function listReading(rest, count2) {
|
|
14101
|
+
const headline = count2 > MAX_TRIAGE_CANDIDATES ? `${count2} red, more than the ${MAX_TRIAGE_CANDIDATES} a bare rafa pr triage assesses at once. ` + "Run one of:" : `${count2} red, none moved in the last ${TRIAGE_FRESH_HOURS} hours. Run one of:`;
|
|
13952
14102
|
return listing("list", Object.freeze([]), rest, headline);
|
|
13953
14103
|
}
|
|
13954
14104
|
function selectTriagePullRequests(input) {
|
|
@@ -13958,24 +14108,24 @@ function selectTriagePullRequests(input) {
|
|
|
13958
14108
|
return plain("branch", Object.freeze([current]), `assessing #${current.number}, the pull request open on ${current.headRefName}`);
|
|
13959
14109
|
}
|
|
13960
14110
|
const candidates = byNumber(input.candidates);
|
|
13961
|
-
const
|
|
14111
|
+
const count2 = candidates.length;
|
|
13962
14112
|
const lines2 = candidates.map((pull) => skipped(pull, now, resolve13));
|
|
13963
|
-
if (resolve13 &&
|
|
13964
|
-
return refusal6(lines2,
|
|
13965
|
-
if (
|
|
14113
|
+
if (resolve13 && count2 > 1)
|
|
14114
|
+
return refusal6(lines2, count2);
|
|
14115
|
+
if (count2 === 0) {
|
|
13966
14116
|
return plain("none", Object.freeze([]), "no red pull request to triage, and no pull request on the current branch");
|
|
13967
14117
|
}
|
|
13968
|
-
if (
|
|
14118
|
+
if (count2 === 1) {
|
|
13969
14119
|
const only = candidates[0];
|
|
13970
14120
|
return plain("single", Object.freeze([only]), `1 red: assessing #${only.number}, last moved ${describeAge(only.updatedAt, now)}`);
|
|
13971
14121
|
}
|
|
13972
|
-
if (
|
|
13973
|
-
return listReading(lines2,
|
|
14122
|
+
if (count2 > MAX_TRIAGE_CANDIDATES)
|
|
14123
|
+
return listReading(lines2, count2);
|
|
13974
14124
|
const fresh = candidates.filter((pull) => isFreshCandidate(pull.updatedAt, now));
|
|
13975
14125
|
const stale = lines2.filter((one) => !one.fresh);
|
|
13976
14126
|
if (fresh.length === 0)
|
|
13977
|
-
return listReading(stale,
|
|
13978
|
-
return someReading(Object.freeze(fresh), stale,
|
|
14127
|
+
return listReading(stale, count2);
|
|
14128
|
+
return someReading(Object.freeze(fresh), stale, count2);
|
|
13979
14129
|
}
|
|
13980
14130
|
|
|
13981
14131
|
// src/pr/triage/conflict.ts
|
|
@@ -13994,10 +14144,10 @@ function parseMessages(records, from) {
|
|
|
13994
14144
|
const countRecord = records[at];
|
|
13995
14145
|
if (countRecord === undefined || countRecord === "")
|
|
13996
14146
|
break;
|
|
13997
|
-
const
|
|
13998
|
-
if (!Number.isInteger(
|
|
14147
|
+
const count2 = Number(countRecord);
|
|
14148
|
+
if (!Number.isInteger(count2) || count2 < 0)
|
|
13999
14149
|
break;
|
|
14000
|
-
const typeAt = at + 1 +
|
|
14150
|
+
const typeAt = at + 1 + count2;
|
|
14001
14151
|
const messageAt = typeAt + 1;
|
|
14002
14152
|
const type = records[typeAt];
|
|
14003
14153
|
const message = records[messageAt];
|
|
@@ -14176,10 +14326,10 @@ function noChecksLines2(reading, assessment) {
|
|
|
14176
14326
|
return [];
|
|
14177
14327
|
const number = reading.detail.number;
|
|
14178
14328
|
const unchecked = readUnchecked(number, workflowCountOf2(reading) ?? null);
|
|
14179
|
-
const [
|
|
14329
|
+
const [count2 = "", warning = ""] = unchecked.warning;
|
|
14180
14330
|
const yes = unchecked.yesMayAnswer ? "--yes may answer it" : "--yes is refused, so a person must answer it";
|
|
14181
14331
|
return [
|
|
14182
|
-
`${INDENT7}Workflows: ${
|
|
14332
|
+
`${INDENT7}Workflows: ${count2}`,
|
|
14183
14333
|
`${INDENT7}Warning: ${warning}`,
|
|
14184
14334
|
`${INDENT7}To merge it anyway: ${skipChecksCommand(number)} (it asks first; ${yes})`
|
|
14185
14335
|
];
|
|
@@ -14295,7 +14445,7 @@ function withTaskBudget(plan2, usd) {
|
|
|
14295
14445
|
}
|
|
14296
14446
|
|
|
14297
14447
|
// src/pr/plans/load.ts
|
|
14298
|
-
import { existsSync as
|
|
14448
|
+
import { existsSync as existsSync11, readFileSync as readFileSync20 } from "fs";
|
|
14299
14449
|
import { dirname as dirname5, join as join26 } from "path";
|
|
14300
14450
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
14301
14451
|
var MODULE_DIR2 = dirname5(fileURLToPath2(import.meta.url));
|
|
@@ -14322,11 +14472,11 @@ function readPinnedPlan(triageClass, lookup = {}) {
|
|
|
14322
14472
|
throw new Error(`No pinned resolve plan ships for ${triageClass}; ` + `one ships for ${PINNED_PLAN_CLASSES.join(", ")}`);
|
|
14323
14473
|
}
|
|
14324
14474
|
const candidates = pinnedPlanCandidates(lookup.moduleDir ?? MODULE_DIR2, triageClass);
|
|
14325
|
-
const found = candidates.find((candidate) =>
|
|
14475
|
+
const found = candidates.find((candidate) => existsSync11(candidate));
|
|
14326
14476
|
if (found === undefined) {
|
|
14327
14477
|
throw new Error(`The pinned resolve plan for ${triageClass} is missing: ` + `no file at ${candidates.join(" or ")}`);
|
|
14328
14478
|
}
|
|
14329
|
-
return
|
|
14479
|
+
return readFileSync20(found, "utf8");
|
|
14330
14480
|
}
|
|
14331
14481
|
var SLOT_PATTERN = /\{[A-Z][A-Z0-9_]*\}/g;
|
|
14332
14482
|
var CONFLICT_SENTENCE_SLOT = "CONFLICT_SENTENCE";
|
|
@@ -14848,11 +14998,11 @@ function readMaxAttempts(flags, usage2) {
|
|
|
14848
14998
|
if (value === undefined)
|
|
14849
14999
|
return DEFAULT_MAX_ATTEMPTS;
|
|
14850
15000
|
const spelled = typeof value === "boolean" ? "--max-attempts with no value" : `"${value}"`;
|
|
14851
|
-
const
|
|
14852
|
-
if (!Number.isSafeInteger(
|
|
15001
|
+
const count2 = typeof value === "string" ? Number(value) : Number.NaN;
|
|
15002
|
+
if (!Number.isSafeInteger(count2) || count2 < 1) {
|
|
14853
15003
|
throw lineRefusal3(`${spelled} is no attempt count, which is a whole number from 1;` + " type the pull request number before the flags", usage2);
|
|
14854
15004
|
}
|
|
14855
|
-
return
|
|
15005
|
+
return count2;
|
|
14856
15006
|
}
|
|
14857
15007
|
function readBranchOrNone(pr, warn) {
|
|
14858
15008
|
const fallback = "so the red pull requests are the candidates";
|
|
@@ -15344,7 +15494,7 @@ function createPrWaitCommand(seams = DEFAULT_WAIT_SEAMS) {
|
|
|
15344
15494
|
var wait_default = createPrWaitCommand();
|
|
15345
15495
|
|
|
15346
15496
|
// src/commands/release/status.ts
|
|
15347
|
-
import { existsSync as
|
|
15497
|
+
import { existsSync as existsSync12, readdirSync as readdirSync6, readFileSync as readFileSync21 } from "fs";
|
|
15348
15498
|
import { join as join28 } from "path";
|
|
15349
15499
|
var RELEASE_STATUS_USAGE = "rafa release status [--plan=<stub>]";
|
|
15350
15500
|
var UNREADABLE3 = "?";
|
|
@@ -15446,7 +15596,7 @@ function untaggedVersions(released, tags) {
|
|
|
15446
15596
|
}
|
|
15447
15597
|
function textOf2(path) {
|
|
15448
15598
|
try {
|
|
15449
|
-
return
|
|
15599
|
+
return readFileSync21(path, "utf8");
|
|
15450
15600
|
} catch {
|
|
15451
15601
|
return null;
|
|
15452
15602
|
}
|
|
@@ -15489,7 +15639,7 @@ function readBranch2(git) {
|
|
|
15489
15639
|
}
|
|
15490
15640
|
function planStubsUnder(root, planDir) {
|
|
15491
15641
|
const resolved = join28(root, planDir);
|
|
15492
|
-
if (!
|
|
15642
|
+
if (!existsSync12(resolved))
|
|
15493
15643
|
return [];
|
|
15494
15644
|
try {
|
|
15495
15645
|
return planStubsFromFileNames(readdirSync6(resolved));
|
|
@@ -15560,10 +15710,10 @@ function levelPhrase(level) {
|
|
|
15560
15710
|
function pendingCell(reading) {
|
|
15561
15711
|
if (reading.stub === null)
|
|
15562
15712
|
return `${NOTHING}: no current plan`;
|
|
15563
|
-
const
|
|
15713
|
+
const count2 = reading.notes.length === 1 ? "1 note" : `${reading.notes.length} notes`;
|
|
15564
15714
|
if (reading.notes.length === 0)
|
|
15565
15715
|
return `${NOTHING} for ${reading.stub}`;
|
|
15566
|
-
return `${
|
|
15716
|
+
return `${count2} for ${reading.stub}, ${levelPhrase(reading.level ?? "none")}`;
|
|
15567
15717
|
}
|
|
15568
15718
|
function pendingLines(reading) {
|
|
15569
15719
|
return renderNoteLines(groupChangeNotes(reading.notes));
|
|
@@ -15690,7 +15840,7 @@ function createReleaseStatusCommand(seams = DEFAULT_RELEASE_SEAMS) {
|
|
|
15690
15840
|
var status_default2 = createReleaseStatusCommand();
|
|
15691
15841
|
|
|
15692
15842
|
// src/commands/release/tag.ts
|
|
15693
|
-
import { readFileSync as
|
|
15843
|
+
import { readFileSync as readFileSync22 } from "fs";
|
|
15694
15844
|
import { join as join29 } from "path";
|
|
15695
15845
|
var RELEASE_TAG_USAGE = "rafa release tag";
|
|
15696
15846
|
var DEFAULT_RELEASE_BRANCH = "main";
|
|
@@ -15710,7 +15860,7 @@ function readBranch3(git) {
|
|
|
15710
15860
|
}
|
|
15711
15861
|
function textOf3(path) {
|
|
15712
15862
|
try {
|
|
15713
|
-
return
|
|
15863
|
+
return readFileSync22(path, "utf8");
|
|
15714
15864
|
} catch {
|
|
15715
15865
|
return null;
|
|
15716
15866
|
}
|
|
@@ -16028,11 +16178,11 @@ import { statSync as statSync14 } from "fs";
|
|
|
16028
16178
|
import { join as join34, resolve as resolve15 } from "path";
|
|
16029
16179
|
|
|
16030
16180
|
// src/backfill/backup.ts
|
|
16031
|
-
import { copyFileSync as copyFileSync4, existsSync as
|
|
16181
|
+
import { copyFileSync as copyFileSync4, existsSync as existsSync13, mkdirSync as mkdirSync8 } from "fs";
|
|
16032
16182
|
import { dirname as dirname6, isAbsolute as isAbsolute8, join as join31, relative as relative8, resolve as resolve13, sep as sep5 } from "path";
|
|
16033
16183
|
|
|
16034
16184
|
// src/backfill/proposal-file.ts
|
|
16035
|
-
import { readdirSync as readdirSync7, readFileSync as
|
|
16185
|
+
import { readdirSync as readdirSync7, readFileSync as readFileSync23 } from "fs";
|
|
16036
16186
|
import { join as join30 } from "path";
|
|
16037
16187
|
var BACKFILL_PATH = join30(".rafa", "backfill");
|
|
16038
16188
|
var PROPOSAL_FILE_PREFIX = "proposals-";
|
|
@@ -16198,7 +16348,7 @@ function readProposalFiles(dir) {
|
|
|
16198
16348
|
return names.filter((name2) => isProposalFileName(name2)).sort((left, right) => left.localeCompare(right)).map((name2) => {
|
|
16199
16349
|
const path = join30(dir, name2);
|
|
16200
16350
|
try {
|
|
16201
|
-
return { path, result: parseProposalFile(
|
|
16351
|
+
return { path, result: parseProposalFile(readFileSync23(path, "utf8")) };
|
|
16202
16352
|
} catch (error) {
|
|
16203
16353
|
return { path, result: unreadable(`the file cannot be read (${error instanceof Error ? error.message : String(error)})`) };
|
|
16204
16354
|
}
|
|
@@ -16227,9 +16377,9 @@ function backupFile(path, options) {
|
|
|
16227
16377
|
const backup = backupPathFor(path, options.root, options.backupDir);
|
|
16228
16378
|
if (backup === null)
|
|
16229
16379
|
return { path, kind: "outside", backup: null };
|
|
16230
|
-
if (!
|
|
16380
|
+
if (!existsSync13(path))
|
|
16231
16381
|
return { path, kind: "missing", backup: null };
|
|
16232
|
-
if (
|
|
16382
|
+
if (existsSync13(backup))
|
|
16233
16383
|
return { path, kind: "kept", backup };
|
|
16234
16384
|
mkdirSync8(dirname6(backup), { recursive: true });
|
|
16235
16385
|
copyFileSync4(path, backup);
|
|
@@ -16254,7 +16404,7 @@ function countBackups(results) {
|
|
|
16254
16404
|
}
|
|
16255
16405
|
|
|
16256
16406
|
// src/backfill/derive.ts
|
|
16257
|
-
import { readFileSync as
|
|
16407
|
+
import { readFileSync as readFileSync24, writeFileSync as writeFileSync7 } from "fs";
|
|
16258
16408
|
import { basename as basename8 } from "path";
|
|
16259
16409
|
var DERIVED_FIELDS = ["stack", "paths", "when_to_use"];
|
|
16260
16410
|
function renderWhenToUse(trigger, prevents) {
|
|
@@ -16380,7 +16530,7 @@ function planFile(entry, options) {
|
|
|
16380
16530
|
}
|
|
16381
16531
|
let original;
|
|
16382
16532
|
try {
|
|
16383
|
-
original =
|
|
16533
|
+
original = readFileSync24(entry.path, "utf8");
|
|
16384
16534
|
} catch (error) {
|
|
16385
16535
|
return inert(entry, "skipped", `the file cannot be read (${error instanceof Error ? error.message : String(error)})`);
|
|
16386
16536
|
}
|
|
@@ -16424,7 +16574,7 @@ function planDerivation(root, options) {
|
|
|
16424
16574
|
function applyFile(action, options) {
|
|
16425
16575
|
if (action.text === null || action.original === null)
|
|
16426
16576
|
return action;
|
|
16427
|
-
const current =
|
|
16577
|
+
const current = readFileSync24(action.path, "utf8");
|
|
16428
16578
|
if (current !== action.original) {
|
|
16429
16579
|
return {
|
|
16430
16580
|
...action,
|
|
@@ -16455,7 +16605,7 @@ function applyDerivation(plan2, options) {
|
|
|
16455
16605
|
}
|
|
16456
16606
|
|
|
16457
16607
|
// src/backfill/proposal-batch.ts
|
|
16458
|
-
import { readFileSync as
|
|
16608
|
+
import { readFileSync as readFileSync25 } from "fs";
|
|
16459
16609
|
import { relative as relative9 } from "path";
|
|
16460
16610
|
|
|
16461
16611
|
// src/demote/report.ts
|
|
@@ -16754,7 +16904,7 @@ function readCandidate(root, entry) {
|
|
|
16754
16904
|
return null;
|
|
16755
16905
|
let text;
|
|
16756
16906
|
try {
|
|
16757
|
-
text =
|
|
16907
|
+
text = readFileSync25(entry.path, "utf8");
|
|
16758
16908
|
} catch {
|
|
16759
16909
|
return null;
|
|
16760
16910
|
}
|
|
@@ -16860,7 +17010,7 @@ function parseSessionAnswer(stdout) {
|
|
|
16860
17010
|
}
|
|
16861
17011
|
|
|
16862
17012
|
// src/backfill/propose.ts
|
|
16863
|
-
import { mkdirSync as mkdirSync9, readFileSync as
|
|
17013
|
+
import { mkdirSync as mkdirSync9, readFileSync as readFileSync26, writeFileSync as writeFileSync8 } from "fs";
|
|
16864
17014
|
import { join as join32, resolve as resolve14 } from "path";
|
|
16865
17015
|
var PROPOSAL_ACTION_KINDS = [
|
|
16866
17016
|
"applied",
|
|
@@ -17019,7 +17169,7 @@ function applyRow(root, row2, options) {
|
|
|
17019
17169
|
}
|
|
17020
17170
|
let original;
|
|
17021
17171
|
try {
|
|
17022
|
-
original =
|
|
17172
|
+
original = readFileSync26(path, "utf8");
|
|
17023
17173
|
} catch {
|
|
17024
17174
|
return inert2(path, row2, "refused", "the file the row names is gone");
|
|
17025
17175
|
}
|
|
@@ -17058,7 +17208,7 @@ function applyProposals(files, root, options) {
|
|
|
17058
17208
|
}
|
|
17059
17209
|
|
|
17060
17210
|
// src/demote/select.ts
|
|
17061
|
-
import { readdirSync as readdirSync8, readFileSync as
|
|
17211
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync27, realpathSync as realpathSync6, statSync as statSync13 } from "fs";
|
|
17062
17212
|
import { basename as basename9, dirname as dirname7, join as join33 } from "path";
|
|
17063
17213
|
var SKILLS_DIRECTORY = "skills";
|
|
17064
17214
|
var CLAUDE_DIRECTORY = ".claude";
|
|
@@ -17120,7 +17270,7 @@ function readSelected(absolute, path, entries) {
|
|
|
17120
17270
|
let text;
|
|
17121
17271
|
let mtime;
|
|
17122
17272
|
try {
|
|
17123
|
-
text =
|
|
17273
|
+
text = readFileSync27(absolute, "utf8");
|
|
17124
17274
|
mtime = statSync13(absolute).mtime.toISOString();
|
|
17125
17275
|
} catch {
|
|
17126
17276
|
return null;
|
|
@@ -17505,11 +17655,11 @@ function createSkillCheckCommand(seams = DEFAULT_CHECK_SEAMS) {
|
|
|
17505
17655
|
var check_default3 = createSkillCheckCommand();
|
|
17506
17656
|
|
|
17507
17657
|
// src/commands/skill/demote.ts
|
|
17508
|
-
import { existsSync as
|
|
17658
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync11, readFileSync as readFileSync29, statSync as statSync16, writeFileSync as writeFileSync10 } from "fs";
|
|
17509
17659
|
import { dirname as dirname9, resolve as resolve16 } from "path";
|
|
17510
17660
|
|
|
17511
17661
|
// src/demote/apply.ts
|
|
17512
|
-
import { copyFileSync as copyFileSync5, existsSync as
|
|
17662
|
+
import { copyFileSync as copyFileSync5, existsSync as existsSync14, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync2, readdirSync as readdirSync9, readFileSync as readFileSync28, renameSync as renameSync3, rmSync as rmSync4, statSync as statSync15, unlinkSync, writeFileSync as writeFileSync9 } from "fs";
|
|
17513
17663
|
import { tmpdir as tmpdir2 } from "os";
|
|
17514
17664
|
import { dirname as dirname8, join as join35 } from "path";
|
|
17515
17665
|
var DEMOTION_ACTION_KINDS = [
|
|
@@ -17551,7 +17701,7 @@ function takenInstinctIds(dir) {
|
|
|
17551
17701
|
}
|
|
17552
17702
|
function readText4(path) {
|
|
17553
17703
|
try {
|
|
17554
|
-
return statSync15(path).isFile() ?
|
|
17704
|
+
return statSync15(path).isFile() ? readFileSync28(path, "utf8") : null;
|
|
17555
17705
|
} catch {
|
|
17556
17706
|
return null;
|
|
17557
17707
|
}
|
|
@@ -17579,7 +17729,7 @@ function planKept(scope, row2, file) {
|
|
|
17579
17729
|
return inert3(row2.path, "procedure", "kept", "procedure-shaped: left where it is, for the backfill");
|
|
17580
17730
|
}
|
|
17581
17731
|
const to = promotedPath(scope, row2.path);
|
|
17582
|
-
if (
|
|
17732
|
+
if (existsSync14(to) || existsSync14(dirname8(to))) {
|
|
17583
17733
|
return inert3(row2.path, "procedure", "refused", `kept as a skill, but ${to} is already there`);
|
|
17584
17734
|
}
|
|
17585
17735
|
return {
|
|
@@ -17616,9 +17766,9 @@ function planDemoted(scope, row2, file, context) {
|
|
|
17616
17766
|
}
|
|
17617
17767
|
const destination = join35(scope.instinctsDir, `${id}${MARKDOWN_EXTENSION}`);
|
|
17618
17768
|
const kept = demotedPath(scope, row2.path);
|
|
17619
|
-
if (
|
|
17769
|
+
if (existsSync14(destination))
|
|
17620
17770
|
return inert3(row2.path, "observation", "refused", `${destination} is already there`);
|
|
17621
|
-
if (
|
|
17771
|
+
if (existsSync14(kept))
|
|
17622
17772
|
return inert3(row2.path, "observation", "refused", `${kept} is already there`);
|
|
17623
17773
|
context.taken.push(id);
|
|
17624
17774
|
return {
|
|
@@ -17667,13 +17817,13 @@ function planDemotion(report3, scope, seams = DEFAULT_APPLY_SEAMS) {
|
|
|
17667
17817
|
const actions = report3.rows.map((row2) => planRow(scope, row2, { temp, taken, seams }));
|
|
17668
17818
|
return { scope, actions, counts: countActions(actions) };
|
|
17669
17819
|
} finally {
|
|
17670
|
-
|
|
17820
|
+
rmSync4(temp, { recursive: true, force: true });
|
|
17671
17821
|
}
|
|
17672
17822
|
}
|
|
17673
17823
|
function moveFile(move3) {
|
|
17674
17824
|
mkdirSync10(dirname8(move3.to), { recursive: true });
|
|
17675
17825
|
try {
|
|
17676
|
-
|
|
17826
|
+
renameSync3(move3.from, move3.to);
|
|
17677
17827
|
} catch {
|
|
17678
17828
|
copyFileSync5(move3.from, move3.to);
|
|
17679
17829
|
unlinkSync(move3.from);
|
|
@@ -17780,9 +17930,9 @@ function verdictLine(report3) {
|
|
|
17780
17930
|
return `${String(report3.rows.length)} file(s): ${parts.join(", ")}`;
|
|
17781
17931
|
}
|
|
17782
17932
|
function previousReport(path, context) {
|
|
17783
|
-
if (!
|
|
17933
|
+
if (!existsSync15(path))
|
|
17784
17934
|
return null;
|
|
17785
|
-
const parsed = parseDemotionReport(
|
|
17935
|
+
const parsed = parseDemotionReport(readFileSync29(path, "utf8"));
|
|
17786
17936
|
if (parsed.report !== null)
|
|
17787
17937
|
return parsed.report;
|
|
17788
17938
|
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(", ")}`);
|
|
@@ -17815,10 +17965,10 @@ function runWrite(context, scope) {
|
|
|
17815
17965
|
context.output.info(line);
|
|
17816
17966
|
}
|
|
17817
17967
|
function reviewedReport(scope) {
|
|
17818
|
-
if (!
|
|
17968
|
+
if (!existsSync15(scope.reportPath)) {
|
|
17819
17969
|
throw new CommandExit(1, `\u274C No report at ${scope.reportPath}; run "rafa skill demote ${scope.dir}" first, then review it`);
|
|
17820
17970
|
}
|
|
17821
|
-
const parsed = parseDemotionReport(
|
|
17971
|
+
const parsed = parseDemotionReport(readFileSync29(scope.reportPath, "utf8"));
|
|
17822
17972
|
if (parsed.report === null) {
|
|
17823
17973
|
const lines2 = parsed.issues.map((issue2) => ` line ${String(issue2.line)} ${issue2.code}: ${issue2.message}`);
|
|
17824
17974
|
throw new CommandExit(1, [`\u274C ${scope.reportPath} does not parse:`, ...lines2].join(`
|
|
@@ -17924,7 +18074,7 @@ var demote_default = createSkillDemoteCommand();
|
|
|
17924
18074
|
|
|
17925
18075
|
// src/commands/skill/show.ts
|
|
17926
18076
|
var DEFAULT_SKILL_SHOW_SEAMS = DEFAULT_SKILL_LIST_SEAMS;
|
|
17927
|
-
var
|
|
18077
|
+
var COMMAND_NAME6 = "rafa skill show";
|
|
17928
18078
|
var USAGE32 = "rafa skill show <name> [--full]";
|
|
17929
18079
|
function unknownSkillMessage(name2, inventory) {
|
|
17930
18080
|
const agent = findShown(inventory.records, "agent", name2);
|
|
@@ -17952,7 +18102,7 @@ async function runShow3(context, seams) {
|
|
|
17952
18102
|
const full = readSwitch("full", context.flags["full"], `Type the name ahead of it: ${USAGE32}`);
|
|
17953
18103
|
const name2 = expectOneArgument(context.args, USAGE32);
|
|
17954
18104
|
const project = projectOf14(context);
|
|
17955
|
-
const { inventory, settingSources } = await projectInventory(project, context, seams,
|
|
18105
|
+
const { inventory, settingSources } = await projectInventory(project, context, seams, COMMAND_NAME6);
|
|
17956
18106
|
const warnings = warningLines(inventory);
|
|
17957
18107
|
for (const warning of warnings)
|
|
17958
18108
|
context.output.warn(warning);
|
|
@@ -18030,8 +18180,8 @@ var VERDICT_WORDS = Object.freeze({
|
|
|
18030
18180
|
pending: "checks pending",
|
|
18031
18181
|
none: "no checks"
|
|
18032
18182
|
});
|
|
18033
|
-
function counted3(
|
|
18034
|
-
return `${String(
|
|
18183
|
+
function counted3(count2, noun, plural5 = `${noun}s`) {
|
|
18184
|
+
return `${String(count2)} ${count2 === 1 ? noun : plural5}`;
|
|
18035
18185
|
}
|
|
18036
18186
|
function info(text) {
|
|
18037
18187
|
return { level: "info", text };
|
|
@@ -18279,7 +18429,7 @@ async function readStatusSections(input, seams = {}) {
|
|
|
18279
18429
|
}
|
|
18280
18430
|
|
|
18281
18431
|
// src/commands/status.ts
|
|
18282
|
-
var
|
|
18432
|
+
var COMMAND_NAME7 = "rafa status";
|
|
18283
18433
|
var STATUS_USAGE = "rafa status";
|
|
18284
18434
|
var STATUS_ARGUMENT_EXIT = 2;
|
|
18285
18435
|
var DEFAULT_STATUS_SEAMS = Object.freeze({});
|
|
@@ -18291,13 +18441,13 @@ function projectOf15(context) {
|
|
|
18291
18441
|
function expectNoWord(args) {
|
|
18292
18442
|
if (args.length === 0)
|
|
18293
18443
|
return;
|
|
18294
|
-
throw new CommandExit(STATUS_ARGUMENT_EXIT, `\u274C ${
|
|
18444
|
+
throw new CommandExit(STATUS_ARGUMENT_EXIT, `\u274C ${COMMAND_NAME7}: expected no argument, got ${String(args.length)}: ${args.join(" ")}
|
|
18295
18445
|
Usage: ${STATUS_USAGE}`);
|
|
18296
18446
|
}
|
|
18297
18447
|
async function runStatus2(context, seams) {
|
|
18298
18448
|
expectNoWord(context.args);
|
|
18299
18449
|
const project = projectOf15(context);
|
|
18300
|
-
const config = resolveProjectConfig(project,
|
|
18450
|
+
const config = resolveProjectConfig(project, COMMAND_NAME7, (message) => {
|
|
18301
18451
|
context.output.warn(message);
|
|
18302
18452
|
});
|
|
18303
18453
|
const read3 = seams.read ?? ((input) => readStatusSections(input));
|
|
@@ -18363,7 +18513,7 @@ var CORE_SUBJECTS = Object.freeze([
|
|
|
18363
18513
|
{ name: "loop", summary: "start a plan; stop, pause, resume, show and list its sessions" },
|
|
18364
18514
|
{ name: "issue", summary: "the tracker: list, show, create, comment on and move issues; mark one ready, unblock it and check its references" },
|
|
18365
18515
|
{ name: "pr", summary: "the pull request of a branch: one line, in full or in the browser; list, wait on, merge and triage them" },
|
|
18366
|
-
{ name: "effort", summary: "collect session and commit rows; report per plan" },
|
|
18516
|
+
{ name: "effort", summary: "collect session and commit rows; report per plan; repair a store a newer rafa migrated" },
|
|
18367
18517
|
{ name: "module", summary: "list the configured modules; run an action a module provides" },
|
|
18368
18518
|
{ name: "agent", summary: "copy an agent definition into the project; list what a session sees" },
|
|
18369
18519
|
{ name: "skill", summary: "check a skills directory; list each tier; demote and backfill it" },
|
|
@@ -18400,6 +18550,7 @@ var CORE_COMMANDS = Object.freeze([
|
|
|
18400
18550
|
triage_default,
|
|
18401
18551
|
collect_default,
|
|
18402
18552
|
report_default,
|
|
18553
|
+
fix_schema_default,
|
|
18403
18554
|
list_default7,
|
|
18404
18555
|
exec_default,
|
|
18405
18556
|
vendor_default,
|