@open-tomato/rafa 0.19.0 → 0.21.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 +62 -5
- package/dist/bundled/skills/dev-planner/SKILL.md +7 -0
- package/dist/cli.js +2976 -1192
- package/dist/{describe-cenk70n5.js → describe-0tefrkk7.js} +3 -3
- package/dist/effort/store/index.js +4 -4
- 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-am92b8qp.js} +50 -8
- package/dist/{index-mh5hyw8g.js → index-kv51t295.js} +501 -314
- package/dist/{index-cedghpva.js → index-pmkgvtfe.js} +5 -1
- package/dist/{index-ca0fccvr.js → index-pzpk59ma.js} +4440 -2960
- package/dist/{index-pqrpcfaz.js → index-twbp38kz.js} +45 -38
- package/dist/index.js +7 -7
- package/dist/plan/index.js +3 -3
- package/dist/plan-prompt.md +2 -0
- package/package.json +2 -2
|
@@ -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,
|
|
@@ -175,6 +177,7 @@ import {
|
|
|
175
177
|
readTextFlag,
|
|
176
178
|
readTrees,
|
|
177
179
|
ready_default,
|
|
180
|
+
recordPlanCi,
|
|
178
181
|
refusal,
|
|
179
182
|
refuseMisplacedRuntime,
|
|
180
183
|
remainingFrom,
|
|
@@ -225,7 +228,7 @@ import {
|
|
|
225
228
|
versionLine,
|
|
226
229
|
waitForChecks,
|
|
227
230
|
writeSession
|
|
228
|
-
} from "./index-
|
|
231
|
+
} from "./index-pzpk59ma.js";
|
|
229
232
|
import {
|
|
230
233
|
PROBE_TIMEOUT_MS,
|
|
231
234
|
findNextTask,
|
|
@@ -239,7 +242,7 @@ import {
|
|
|
239
242
|
runPreflight,
|
|
240
243
|
splitBlockerComment,
|
|
241
244
|
trackerPathFor
|
|
242
|
-
} from "./index-
|
|
245
|
+
} from "./index-21qkxk63.js";
|
|
243
246
|
import {
|
|
244
247
|
ACTION_HEADING,
|
|
245
248
|
CAUSE_HEADING,
|
|
@@ -252,6 +255,7 @@ import {
|
|
|
252
255
|
ISSUE_TYPES,
|
|
253
256
|
MARKDOWN_EXTENSION,
|
|
254
257
|
SKILL_FILE,
|
|
258
|
+
SQLITE_MIGRATIONS,
|
|
255
259
|
allRecords,
|
|
256
260
|
claudeArgs,
|
|
257
261
|
createGhRunner,
|
|
@@ -260,6 +264,7 @@ import {
|
|
|
260
264
|
gitRemoteUrl,
|
|
261
265
|
instinctProject,
|
|
262
266
|
mergeFrontmatter,
|
|
267
|
+
migrateSchema,
|
|
263
268
|
moduleOfLabels,
|
|
264
269
|
normalizeRemote,
|
|
265
270
|
readFrontmatter,
|
|
@@ -275,7 +280,7 @@ import {
|
|
|
275
280
|
toHeldRecords,
|
|
276
281
|
typeOfLabels,
|
|
277
282
|
writeFrontmatter
|
|
278
|
-
} from "./index-
|
|
283
|
+
} from "./index-am92b8qp.js";
|
|
279
284
|
import {
|
|
280
285
|
CONFIG_DEFAULTS,
|
|
281
286
|
CONFIG_FILE,
|
|
@@ -289,7 +294,7 @@ import {
|
|
|
289
294
|
readItemBytes,
|
|
290
295
|
readRafaBlocks,
|
|
291
296
|
resolveTiers
|
|
292
|
-
} from "./index-
|
|
297
|
+
} from "./index-twbp38kz.js";
|
|
293
298
|
import {
|
|
294
299
|
promotable
|
|
295
300
|
} from "./index-d6d0942q.js";
|
|
@@ -297,10 +302,10 @@ import {
|
|
|
297
302
|
createCommandRegistry,
|
|
298
303
|
describeRegistry,
|
|
299
304
|
mountKey
|
|
300
|
-
} from "./index-
|
|
305
|
+
} from "./index-4a45ffqh.js";
|
|
301
306
|
import {
|
|
302
307
|
CommandExit
|
|
303
|
-
} from "./index-
|
|
308
|
+
} from "./index-28jzpyks.js";
|
|
304
309
|
import {
|
|
305
310
|
MERGE_METHODS,
|
|
306
311
|
RELEASE_AUTO,
|
|
@@ -312,7 +317,7 @@ import {
|
|
|
312
317
|
isSkillTier,
|
|
313
318
|
messageOf,
|
|
314
319
|
parseBudgetUsd
|
|
315
|
-
} from "./index-
|
|
320
|
+
} from "./index-pmkgvtfe.js";
|
|
316
321
|
import {
|
|
317
322
|
triggerKey
|
|
318
323
|
} from "./index-wp8c28fd.js";
|
|
@@ -2287,148 +2292,6 @@ async function checkQuotes(matches, files) {
|
|
|
2287
2292
|
return { kept, dropped: matches.length - kept.length };
|
|
2288
2293
|
}
|
|
2289
2294
|
|
|
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
2295
|
// src/inventory/search/scratch.ts
|
|
2433
2296
|
import { copyFileSync, mkdirSync, mkdtempSync, rmSync } from "fs";
|
|
2434
2297
|
import { tmpdir } from "os";
|
|
@@ -2851,7 +2714,7 @@ function createAgentShowCommand(seams = DEFAULT_AGENT_SHOW_SEAMS) {
|
|
|
2851
2714
|
var show_default = createAgentShowCommand();
|
|
2852
2715
|
|
|
2853
2716
|
// src/commands/agent/vendor.ts
|
|
2854
|
-
import { copyFileSync as copyFileSync2, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as
|
|
2717
|
+
import { copyFileSync as copyFileSync2, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync5, writeFileSync } from "fs";
|
|
2855
2718
|
import { basename as basename2, join as join6 } from "path";
|
|
2856
2719
|
var USAGE4 = "rafa agent vendor <name>... [--force]";
|
|
2857
2720
|
var NOTHING_WRITTEN = "Nothing was written.";
|
|
@@ -2938,7 +2801,7 @@ function planCopies(names, project, force, entry) {
|
|
|
2938
2801
|
function copyOne(copy, date) {
|
|
2939
2802
|
try {
|
|
2940
2803
|
copyFileSync2(copy.from, copy.to);
|
|
2941
|
-
writeFileSync(copy.to, withSourceHeader(
|
|
2804
|
+
writeFileSync(copy.to, withSourceHeader(readFileSync5(copy.to, "utf8"), copy.from, date), "utf8");
|
|
2942
2805
|
} catch (error) {
|
|
2943
2806
|
throw new CommandExit(1, `\u274C ${USAGE4}: agent "${copy.name}" could not be written to ${copy.to}: ${String(error)}`);
|
|
2944
2807
|
}
|
|
@@ -4287,7 +4150,7 @@ import { statSync as statSync5 } from "fs";
|
|
|
4287
4150
|
import { join as join10 } from "path";
|
|
4288
4151
|
|
|
4289
4152
|
// src/board/setup-config.ts
|
|
4290
|
-
import { readFileSync as
|
|
4153
|
+
import { readFileSync as readFileSync6 } from "fs";
|
|
4291
4154
|
function roadmapIssueIn(text, path) {
|
|
4292
4155
|
return parseConfigText(text, path).values.roadmapIssue ?? null;
|
|
4293
4156
|
}
|
|
@@ -4295,7 +4158,7 @@ function readRoadmapSetting(root) {
|
|
|
4295
4158
|
const path = configFilePath(root);
|
|
4296
4159
|
let text;
|
|
4297
4160
|
try {
|
|
4298
|
-
text =
|
|
4161
|
+
text = readFileSync6(path, "utf8");
|
|
4299
4162
|
} catch (error) {
|
|
4300
4163
|
return { issue: null, text: "", problem: `${path} could not be read: ${messageOf(error)}` };
|
|
4301
4164
|
}
|
|
@@ -4344,7 +4207,7 @@ function withRoadmapIssue(text, issue) {
|
|
|
4344
4207
|
}
|
|
4345
4208
|
|
|
4346
4209
|
// src/board/setup.ts
|
|
4347
|
-
import { existsSync as existsSync4, lstatSync, mkdirSync as mkdirSync3, readFileSync as
|
|
4210
|
+
import { existsSync as existsSync4, lstatSync, mkdirSync as mkdirSync3, readFileSync as readFileSync7, statSync as statSync4, writeFileSync as writeFileSync2 } from "fs";
|
|
4348
4211
|
import { dirname, join as join9 } from "path";
|
|
4349
4212
|
import { fileURLToPath } from "url";
|
|
4350
4213
|
var PREFIX = "board setup";
|
|
@@ -4479,7 +4342,7 @@ function readSpecTemplate(moduleDir = MODULE_DIR) {
|
|
|
4479
4342
|
if (!existsSync4(source)) {
|
|
4480
4343
|
throw new Error(`${PREFIX}: the spec issue template is missing: no file at ${source}`);
|
|
4481
4344
|
}
|
|
4482
|
-
return
|
|
4345
|
+
return readFileSync7(source, "utf8");
|
|
4483
4346
|
}
|
|
4484
4347
|
function writeSpecTemplate(root, moduleDir = MODULE_DIR) {
|
|
4485
4348
|
const path = join9(root, SPEC_TEMPLATE_PATH);
|
|
@@ -6439,7 +6302,7 @@ function writeInstall(context, install) {
|
|
|
6439
6302
|
}
|
|
6440
6303
|
|
|
6441
6304
|
// src/commands/doctor-refs.ts
|
|
6442
|
-
import { readdirSync, readFileSync as
|
|
6305
|
+
import { readdirSync, readFileSync as readFileSync8, statSync as statSync8 } from "fs";
|
|
6443
6306
|
import { join as join16, resolve as resolve5 } from "path";
|
|
6444
6307
|
function issueCheckCommand(issue) {
|
|
6445
6308
|
return `rafa issue check ${String(issue)}`;
|
|
@@ -6509,7 +6372,7 @@ async function readCopy(file, input, verify) {
|
|
|
6509
6372
|
const path = join16(input.specsDir, file.name);
|
|
6510
6373
|
const empty = { issue: file.issue, path, suspect: 0, dangling: 0, unknown: 0 };
|
|
6511
6374
|
try {
|
|
6512
|
-
const copy =
|
|
6375
|
+
const copy = readFileSync8(resolve5(input.root, path), "utf8");
|
|
6513
6376
|
const { rows } = await readRefsText({ copy, issue: file.issue, verify: await verify() });
|
|
6514
6377
|
const states = rows.map((row) => row.state);
|
|
6515
6378
|
return Object.freeze({
|
|
@@ -6801,14 +6664,14 @@ function renderBoard(board) {
|
|
|
6801
6664
|
}
|
|
6802
6665
|
|
|
6803
6666
|
// src/commands/doctor-tiers.ts
|
|
6804
|
-
import { readFileSync as
|
|
6667
|
+
import { readFileSync as readFileSync9, realpathSync as realpathSync4 } from "fs";
|
|
6805
6668
|
import { basename as basename5, dirname as dirname2 } from "path";
|
|
6806
6669
|
var TIERS_SECTION_TITLE = "Skill tiers";
|
|
6807
6670
|
var CLAUDE_VERSION_TIMEOUT_MS = 1e4;
|
|
6808
6671
|
var VERSION_PATTERN = /^\s*(\d+\.\d+\.\d+)/;
|
|
6809
6672
|
function readTextFile(path) {
|
|
6810
6673
|
try {
|
|
6811
|
-
return
|
|
6674
|
+
return readFileSync9(path, "utf8");
|
|
6812
6675
|
} catch {
|
|
6813
6676
|
return null;
|
|
6814
6677
|
}
|
|
@@ -6895,12 +6758,18 @@ function cliVersionRows(installed, pinned = SERVE_CLI_VERSION) {
|
|
|
6895
6758
|
}
|
|
6896
6759
|
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
6760
|
}
|
|
6761
|
+
function skillUseVersionRows(installed, pinned = SKILL_USE_CLI_VERSION) {
|
|
6762
|
+
if (installed === null || installed === pinned)
|
|
6763
|
+
return [];
|
|
6764
|
+
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")];
|
|
6765
|
+
}
|
|
6898
6766
|
function doctorTierRows(inventory, installed, readers = {}) {
|
|
6899
6767
|
const readText2 = readers.readText ?? readTextFile;
|
|
6900
6768
|
return [
|
|
6901
6769
|
...collisionRows(inventory.resolution.collisions),
|
|
6902
6770
|
...unreviewedRows(inventory.records, readText2),
|
|
6903
6771
|
...cliVersionRows(installed),
|
|
6772
|
+
...skillUseVersionRows(installed),
|
|
6904
6773
|
...copyRows(inventory.resolution.items, readers.realPath ?? realPathOf),
|
|
6905
6774
|
...noProvenanceRows(inventory, readText2)
|
|
6906
6775
|
];
|
|
@@ -7256,7 +7125,7 @@ var collect_default = wrapPhaseZeroCommand({
|
|
|
7256
7125
|
subject: "effort",
|
|
7257
7126
|
action: "collect",
|
|
7258
7127
|
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.",
|
|
7128
|
+
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
7129
|
args: [],
|
|
7261
7130
|
flags: [
|
|
7262
7131
|
{
|
|
@@ -7272,10 +7141,15 @@ var collect_default = wrapPhaseZeroCommand({
|
|
|
7272
7141
|
},
|
|
7273
7142
|
{
|
|
7274
7143
|
name: "sessions",
|
|
7275
|
-
description: "Collects session rows; `--no-sessions` skips them. Refused beside `--no-git`," + " which would leave nothing to collect.",
|
|
7144
|
+
description: "Collects session rows; `--no-sessions` skips them. Refused beside `--no-git`," + " which would leave nothing to collect, unless `--skills` is given.",
|
|
7276
7145
|
type: "boolean",
|
|
7277
7146
|
default: true
|
|
7278
7147
|
},
|
|
7148
|
+
{
|
|
7149
|
+
name: "skills",
|
|
7150
|
+
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`.",
|
|
7151
|
+
type: "boolean"
|
|
7152
|
+
},
|
|
7279
7153
|
{
|
|
7280
7154
|
name: "verbose",
|
|
7281
7155
|
description: "Prints what each half found before the summary: the logs and plan stubs it read," + " each session read, and the commits parsed.",
|
|
@@ -7295,13 +7169,282 @@ var collect_default = wrapPhaseZeroCommand({
|
|
|
7295
7169
|
outputs: ["text", "json"]
|
|
7296
7170
|
}, collect);
|
|
7297
7171
|
|
|
7172
|
+
// src/effort/store/fix-schema.ts
|
|
7173
|
+
import { existsSync as existsSync5, renameSync, rmSync as rmSync2 } from "fs";
|
|
7174
|
+
import { Database } from "bun:sqlite";
|
|
7175
|
+
class SchemaFixRefusal extends Error {
|
|
7176
|
+
constructor(message) {
|
|
7177
|
+
super(message);
|
|
7178
|
+
this.name = "SchemaFixRefusal";
|
|
7179
|
+
}
|
|
7180
|
+
}
|
|
7181
|
+
var LIVE = "live";
|
|
7182
|
+
function quoted(name2) {
|
|
7183
|
+
return `"${name2.replaceAll('"', '""')}"`;
|
|
7184
|
+
}
|
|
7185
|
+
function tableNames(db, schema) {
|
|
7186
|
+
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);
|
|
7187
|
+
}
|
|
7188
|
+
function columnNames(db, schema, table) {
|
|
7189
|
+
return db.query("SELECT name FROM pragma_table_info(?, ?)").all(table, schema).map((row2) => row2.name);
|
|
7190
|
+
}
|
|
7191
|
+
function count(db, sql) {
|
|
7192
|
+
return db.query(sql).get()?.n ?? 0;
|
|
7193
|
+
}
|
|
7194
|
+
function versionOf(path) {
|
|
7195
|
+
const db = new Database(path, { readonly: true });
|
|
7196
|
+
try {
|
|
7197
|
+
return db.query("PRAGMA user_version").get()?.user_version ?? 0;
|
|
7198
|
+
} finally {
|
|
7199
|
+
db.close();
|
|
7200
|
+
}
|
|
7201
|
+
}
|
|
7202
|
+
function refuseInFlight(path) {
|
|
7203
|
+
for (const suffix of ["-journal", "-wal"]) {
|
|
7204
|
+
if (existsSync5(`${path}${suffix}`)) {
|
|
7205
|
+
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");
|
|
7206
|
+
}
|
|
7207
|
+
}
|
|
7208
|
+
}
|
|
7209
|
+
function refuseRemoved(db, known, live) {
|
|
7210
|
+
for (const table of known) {
|
|
7211
|
+
if (!live.has(table)) {
|
|
7212
|
+
throw new SchemaFixRefusal(`the store holds no table ${table}, which this rafa writes; its newer schema is not additive`);
|
|
7213
|
+
}
|
|
7214
|
+
const liveColumns = new Set(columnNames(db, LIVE, table));
|
|
7215
|
+
const missing = columnNames(db, "main", table).filter((column) => !liveColumns.has(column));
|
|
7216
|
+
if (missing.length > 0) {
|
|
7217
|
+
throw new SchemaFixRefusal(`the store holds no column ${missing.map((column) => `${table}.${column}`).join(", ")}, which this rafa` + " writes; its newer schema is not additive");
|
|
7218
|
+
}
|
|
7219
|
+
}
|
|
7220
|
+
}
|
|
7221
|
+
function copyKnown(db, known) {
|
|
7222
|
+
db.transaction(() => {
|
|
7223
|
+
for (const table of known) {
|
|
7224
|
+
const columns2 = columnNames(db, "main", table).map(quoted).join(", ");
|
|
7225
|
+
db.run(`INSERT INTO main.${quoted(table)} (${columns2}) SELECT ${columns2} FROM ${LIVE}.${quoted(table)}`);
|
|
7226
|
+
}
|
|
7227
|
+
})();
|
|
7228
|
+
}
|
|
7229
|
+
function checkedCounts(db, known) {
|
|
7230
|
+
return known.map((table) => {
|
|
7231
|
+
const rows = count(db, `SELECT count(*) AS n FROM main.${quoted(table)}`);
|
|
7232
|
+
const liveRows = count(db, `SELECT count(*) AS n FROM ${LIVE}.${quoted(table)}`);
|
|
7233
|
+
if (rows !== liveRows) {
|
|
7234
|
+
throw new SchemaFixRefusal(`the rebuilt ${table} holds ${String(rows)} rows, the store ${String(liveRows)}`);
|
|
7235
|
+
}
|
|
7236
|
+
return { table, rows };
|
|
7237
|
+
});
|
|
7238
|
+
}
|
|
7239
|
+
function leftBehind(db, known, live) {
|
|
7240
|
+
const leftTables = live.filter((table) => !known.has(table)).map((table) => ({ table, rows: count(db, `SELECT count(*) AS n FROM ${LIVE}.${quoted(table)}`) }));
|
|
7241
|
+
const leftColumns = live.filter((table) => known.has(table)).flatMap((table) => {
|
|
7242
|
+
const kept = new Set(columnNames(db, "main", table));
|
|
7243
|
+
return columnNames(db, LIVE, table).filter((column) => !kept.has(column)).map((column) => ({
|
|
7244
|
+
table,
|
|
7245
|
+
column,
|
|
7246
|
+
values: count(db, `SELECT count(*) AS n FROM ${LIVE}.${quoted(table)} WHERE ${quoted(column)} IS NOT NULL`)
|
|
7247
|
+
}));
|
|
7248
|
+
});
|
|
7249
|
+
return { leftTables, leftColumns };
|
|
7250
|
+
}
|
|
7251
|
+
function refuseCorrupt(db) {
|
|
7252
|
+
const answer = db.query("PRAGMA main.integrity_check").get()?.integrity_check;
|
|
7253
|
+
if (answer !== "ok")
|
|
7254
|
+
throw new SchemaFixRefusal(`the rebuilt store failed integrity_check: ${answer ?? "no answer"}`);
|
|
7255
|
+
}
|
|
7256
|
+
function buildParallel(path, parallelPath, migrations) {
|
|
7257
|
+
const db = new Database(parallelPath, { create: true, readwrite: true });
|
|
7258
|
+
try {
|
|
7259
|
+
migrateSchema(db, parallelPath, migrations);
|
|
7260
|
+
db.run(`ATTACH DATABASE ? AS ${LIVE}`, [path]);
|
|
7261
|
+
const known = tableNames(db, "main");
|
|
7262
|
+
const live = tableNames(db, LIVE);
|
|
7263
|
+
refuseRemoved(db, known, new Set(live));
|
|
7264
|
+
copyKnown(db, known);
|
|
7265
|
+
const kept = checkedCounts(db, known);
|
|
7266
|
+
const left = leftBehind(db, new Set(known), live);
|
|
7267
|
+
db.run(`DETACH DATABASE ${LIVE}`);
|
|
7268
|
+
refuseCorrupt(db);
|
|
7269
|
+
return { kept, ...left };
|
|
7270
|
+
} finally {
|
|
7271
|
+
db.close();
|
|
7272
|
+
}
|
|
7273
|
+
}
|
|
7274
|
+
function removeParallel(parallelPath) {
|
|
7275
|
+
rmSync2(parallelPath, { force: true });
|
|
7276
|
+
rmSync2(`${parallelPath}-journal`, { force: true });
|
|
7277
|
+
}
|
|
7278
|
+
function swapIn(path, parallelPath, backupPath) {
|
|
7279
|
+
renameSync(path, backupPath);
|
|
7280
|
+
try {
|
|
7281
|
+
renameSync(parallelPath, path);
|
|
7282
|
+
} catch (error) {
|
|
7283
|
+
renameSync(backupPath, path);
|
|
7284
|
+
throw error;
|
|
7285
|
+
}
|
|
7286
|
+
}
|
|
7287
|
+
function freshPaths(path, version2, stamp) {
|
|
7288
|
+
const parallelPath = `${path}.fix-${stamp}`;
|
|
7289
|
+
const backupPath = `${path}.v${String(version2)}-${stamp}.bak`;
|
|
7290
|
+
for (const taken of [parallelPath, backupPath]) {
|
|
7291
|
+
if (existsSync5(taken))
|
|
7292
|
+
throw new SchemaFixRefusal(`${taken} is already there; move it aside or pass another stamp`);
|
|
7293
|
+
}
|
|
7294
|
+
return { parallelPath, backupPath };
|
|
7295
|
+
}
|
|
7296
|
+
function fixStoreSchema(options) {
|
|
7297
|
+
const { path, dryRun, stamp } = options;
|
|
7298
|
+
const migrations = options.migrations ?? SQLITE_MIGRATIONS;
|
|
7299
|
+
const knownVersion = migrations.length;
|
|
7300
|
+
const nothing = { kept: [], leftTables: [], leftColumns: [], backupPath: null };
|
|
7301
|
+
if (!existsSync5(path))
|
|
7302
|
+
return { path, status: "missing", storeVersion: null, knownVersion, ...nothing };
|
|
7303
|
+
refuseInFlight(path);
|
|
7304
|
+
const storeVersion = versionOf(path);
|
|
7305
|
+
if (storeVersion === knownVersion)
|
|
7306
|
+
return { path, status: "current", storeVersion, knownVersion, ...nothing };
|
|
7307
|
+
if (storeVersion < knownVersion)
|
|
7308
|
+
return { path, status: "behind", storeVersion, knownVersion, ...nothing };
|
|
7309
|
+
const { parallelPath, backupPath } = freshPaths(path, storeVersion, stamp);
|
|
7310
|
+
let built;
|
|
7311
|
+
try {
|
|
7312
|
+
built = buildParallel(path, parallelPath, migrations);
|
|
7313
|
+
} catch (error) {
|
|
7314
|
+
removeParallel(parallelPath);
|
|
7315
|
+
throw error;
|
|
7316
|
+
}
|
|
7317
|
+
if (dryRun) {
|
|
7318
|
+
removeParallel(parallelPath);
|
|
7319
|
+
return { path, status: "would-rebuild", storeVersion, knownVersion, ...built, backupPath: null };
|
|
7320
|
+
}
|
|
7321
|
+
swapIn(path, parallelPath, backupPath);
|
|
7322
|
+
return { path, status: "rebuilt", storeVersion, knownVersion, ...built, backupPath };
|
|
7323
|
+
}
|
|
7324
|
+
|
|
7325
|
+
// src/commands/effort/fix-schema.ts
|
|
7326
|
+
var COMMAND_NAME5 = "rafa effort fix-schema";
|
|
7327
|
+
var FIX_SCHEMA_USAGE = "rafa effort fix-schema [--dry-run]";
|
|
7328
|
+
var DRY_RUN_FLAG2 = "dry-run";
|
|
7329
|
+
function fileStamp(date) {
|
|
7330
|
+
return date.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
|
|
7331
|
+
}
|
|
7332
|
+
function refuseLiveLoop(root, isAlive) {
|
|
7333
|
+
let records;
|
|
7334
|
+
try {
|
|
7335
|
+
records = readSessions(root, isAlive === undefined ? {} : { isAlive });
|
|
7336
|
+
} catch (error) {
|
|
7337
|
+
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)}`);
|
|
7338
|
+
}
|
|
7339
|
+
const live = records.find((record) => record.state === "running" || record.state === "paused");
|
|
7340
|
+
if (live === undefined)
|
|
7341
|
+
return;
|
|
7342
|
+
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.`);
|
|
7343
|
+
}
|
|
7344
|
+
function rebuildLines(result) {
|
|
7345
|
+
const rows = result.kept.reduce((sum, table) => sum + table.rows, 0);
|
|
7346
|
+
const kept = result.kept.map((table) => `${table.table} ${String(table.rows)}`).join(", ");
|
|
7347
|
+
const left = [
|
|
7348
|
+
...result.leftTables.map((table) => `table ${table.table} (${String(table.rows)} rows)`),
|
|
7349
|
+
...result.leftColumns.map((column) => `column ${column.table}.${column.column} (${String(column.values)} values)`)
|
|
7350
|
+
];
|
|
7351
|
+
return [
|
|
7352
|
+
`${result.path} is at schema version ${String(result.storeVersion)}, past the ${String(result.knownVersion)} this rafa knows.`,
|
|
7353
|
+
`Keeps ${String(result.kept.length)} tables, ${String(rows)} rows: ${kept}.`,
|
|
7354
|
+
left.length === 0 ? "Leaves nothing behind." : `Leaves behind, kept only in the backup: ${left.join("; ")}.`
|
|
7355
|
+
];
|
|
7356
|
+
}
|
|
7357
|
+
function renderFixSchema(result) {
|
|
7358
|
+
switch (result.status) {
|
|
7359
|
+
case "missing":
|
|
7360
|
+
return [`No effort store at ${result.path}: nothing to repair.`];
|
|
7361
|
+
case "current":
|
|
7362
|
+
return [`\u2705 ${result.path} is at schema version ${String(result.knownVersion)}, the one this rafa knows: nothing to repair.`];
|
|
7363
|
+
case "behind":
|
|
7364
|
+
return [
|
|
7365
|
+
`${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."
|
|
7366
|
+
];
|
|
7367
|
+
case "would-rebuild":
|
|
7368
|
+
return [
|
|
7369
|
+
...rebuildLines(result),
|
|
7370
|
+
`\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."
|
|
7371
|
+
];
|
|
7372
|
+
case "rebuilt":
|
|
7373
|
+
return [
|
|
7374
|
+
...rebuildLines(result),
|
|
7375
|
+
`\u2705 Rebuilt at version ${String(result.knownVersion)}. The original is kept whole at ${String(result.backupPath)};` + " rename it back to undo."
|
|
7376
|
+
];
|
|
7377
|
+
}
|
|
7378
|
+
}
|
|
7379
|
+
function runFixSchema(context, seams) {
|
|
7380
|
+
expectNoArgument(context.args, FIX_SCHEMA_USAGE);
|
|
7381
|
+
const dryRun = readSwitch(DRY_RUN_FLAG2, context.flags[DRY_RUN_FLAG2], `Usage: ${FIX_SCHEMA_USAGE}`);
|
|
7382
|
+
if (context.project === null)
|
|
7383
|
+
throw new Error(`${COMMAND_NAME5} runs inside a project, and was handed none`);
|
|
7384
|
+
const root = context.project.root;
|
|
7385
|
+
if (!dryRun)
|
|
7386
|
+
refuseLiveLoop(root, seams.isAlive);
|
|
7387
|
+
let result;
|
|
7388
|
+
try {
|
|
7389
|
+
result = fixStoreSchema({
|
|
7390
|
+
path: sqliteStorePath(root),
|
|
7391
|
+
dryRun,
|
|
7392
|
+
stamp: fileStamp((seams.now ?? (() => new Date))())
|
|
7393
|
+
});
|
|
7394
|
+
} catch (error) {
|
|
7395
|
+
if (error instanceof SchemaFixRefusal)
|
|
7396
|
+
throw new CommandExit(1, `\u274C ${COMMAND_NAME5}: ${error.message}`);
|
|
7397
|
+
throw error;
|
|
7398
|
+
}
|
|
7399
|
+
if (context.outputMode === "json") {
|
|
7400
|
+
context.output.result(result);
|
|
7401
|
+
return;
|
|
7402
|
+
}
|
|
7403
|
+
for (const line of renderFixSchema(result))
|
|
7404
|
+
context.output.info(line);
|
|
7405
|
+
}
|
|
7406
|
+
function createFixSchemaCommand(seams = {}) {
|
|
7407
|
+
const command = {
|
|
7408
|
+
name: "effort fix-schema",
|
|
7409
|
+
subject: "effort",
|
|
7410
|
+
action: "fix-schema",
|
|
7411
|
+
summary: "rebuild an effort store a newer rafa migrated at the version this rafa knows, keeping the original",
|
|
7412
|
+
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.",
|
|
7413
|
+
args: [],
|
|
7414
|
+
flags: [
|
|
7415
|
+
{
|
|
7416
|
+
name: DRY_RUN_FLAG2,
|
|
7417
|
+
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.",
|
|
7418
|
+
type: "boolean"
|
|
7419
|
+
}
|
|
7420
|
+
],
|
|
7421
|
+
examples: [
|
|
7422
|
+
{
|
|
7423
|
+
cmd: "rafa effort fix-schema --dry-run",
|
|
7424
|
+
note: "Prints what a rebuild would keep and leave behind, changing nothing."
|
|
7425
|
+
},
|
|
7426
|
+
{
|
|
7427
|
+
cmd: "rafa effort fix-schema",
|
|
7428
|
+
note: "Swaps the rebuild in and prints where the original was kept."
|
|
7429
|
+
}
|
|
7430
|
+
],
|
|
7431
|
+
outputs: ["text", "json"],
|
|
7432
|
+
run: async (context) => {
|
|
7433
|
+
runFixSchema(context, seams);
|
|
7434
|
+
await Promise.resolve();
|
|
7435
|
+
}
|
|
7436
|
+
};
|
|
7437
|
+
return Object.freeze(command);
|
|
7438
|
+
}
|
|
7439
|
+
var fix_schema_default = createFixSchemaCommand();
|
|
7440
|
+
|
|
7298
7441
|
// src/commands/effort/report.ts
|
|
7299
7442
|
var report_default = wrapPhaseZeroCommand({
|
|
7300
7443
|
name: "effort report",
|
|
7301
7444
|
subject: "effort",
|
|
7302
7445
|
action: "report",
|
|
7303
7446
|
summary: "roll the stored session rows up per plan, then tally the task reports and list preflight halts",
|
|
7304
|
-
description: "Rolls the session rows `rafa effort collect` stored up per plan, or per branch for a" + " session no plan claims, then tallies the stored task reports by plan, status and outcome, and" + " lists the runs whose preflight halted, one row per required item that failed. It" + " reads only what is stored, so two runs over an unchanged store print the same bytes. With" + " `--output=json` the report is the data of the terminal result event. An unrecognised argument" + " and a config the loop cannot run on are each refused, one line per problem.",
|
|
7447
|
+
description: "Rolls the session rows `rafa effort collect` stored up per plan, or per branch for a" + " session no plan claims, then tallies the stored task reports by plan, status and outcome, and" + " lists the runs whose preflight halted, one row per required item that failed. It" + " reads only what is stored, so two runs over an unchanged store print the same bytes. With" + " `--output=json` the report is the data of the terminal result event. With `--skills` it prints" + " the skills report instead: per plan, and per resolver within one, whether each offered skill and" + " injected lesson co-occurred with a recurrence of the failure it should prevent, read from the stored" + " rows and the skills' frontmatter, never from a session log. An unrecognised argument" + " and a config the loop cannot run on are each refused, one line per problem.",
|
|
7305
7448
|
args: [],
|
|
7306
7449
|
flags: [
|
|
7307
7450
|
{
|
|
@@ -7314,6 +7457,16 @@ var report_default = wrapPhaseZeroCommand({
|
|
|
7314
7457
|
description: "Keeps only the sessions whose dominant entrypoint is one of these, comma-separated." + " `sdk-cli` is the loop.",
|
|
7315
7458
|
type: "string"
|
|
7316
7459
|
},
|
|
7460
|
+
{
|
|
7461
|
+
name: "skills",
|
|
7462
|
+
description: "Prints the skills report in place of the session tables: per plan and per resolver," + " each skill's and lesson's signal, the skills invoked and never offered, M1, M2 and plan CI." + " Refused beside `--kind` or `--entrypoint`, which narrow session rows it does not read.",
|
|
7463
|
+
type: "boolean"
|
|
7464
|
+
},
|
|
7465
|
+
{
|
|
7466
|
+
name: "plan",
|
|
7467
|
+
description: "Keeps only these plan stubs in the skills report, comma-separated, and may be" + " repeated. A stub the store holds no row for reads as no plan. Refused without `--skills`.",
|
|
7468
|
+
type: "string"
|
|
7469
|
+
},
|
|
7317
7470
|
{
|
|
7318
7471
|
name: "json",
|
|
7319
7472
|
description: "Deprecated: the phase 0 spelling of `--output=json`, read as that flag after one" + " deprecation line on stderr.",
|
|
@@ -7326,6 +7479,10 @@ var report_default = wrapPhaseZeroCommand({
|
|
|
7326
7479
|
cmd: "rafa effort report",
|
|
7327
7480
|
note: "Prints the per-plan tables, the task report tallies, then the preflight halts."
|
|
7328
7481
|
},
|
|
7482
|
+
{
|
|
7483
|
+
cmd: "rafa effort report --skills --plan=rafa-24-know-which-skills-earn",
|
|
7484
|
+
note: "Prints one plan's skills and lessons with their signals, per resolver, under the fixed" + " co-occurrence line."
|
|
7485
|
+
},
|
|
7329
7486
|
{
|
|
7330
7487
|
cmd: "rafa effort report --entrypoint=sdk-cli --kind=task --output=json",
|
|
7331
7488
|
note: "Writes a start event, then a result event whose data is the report of the task sessions" + " the loop ran."
|
|
@@ -7335,12 +7492,12 @@ var report_default = wrapPhaseZeroCommand({
|
|
|
7335
7492
|
}, report);
|
|
7336
7493
|
|
|
7337
7494
|
// src/commands/init.ts
|
|
7338
|
-
import { existsSync as
|
|
7495
|
+
import { existsSync as existsSync8, readFileSync as readFileSync14 } from "fs";
|
|
7339
7496
|
import { homedir } from "os";
|
|
7340
7497
|
import { join as join21, relative as relative6, sep as sep4 } from "path";
|
|
7341
7498
|
|
|
7342
7499
|
// src/agents/vendorable.ts
|
|
7343
|
-
import { readdirSync as readdirSync2, readFileSync as
|
|
7500
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync10 } from "fs";
|
|
7344
7501
|
import { isAbsolute as isAbsolute5, join as join17 } from "path";
|
|
7345
7502
|
function planFiles(dir) {
|
|
7346
7503
|
let entries;
|
|
@@ -7353,7 +7510,7 @@ function planFiles(dir) {
|
|
|
7353
7510
|
}
|
|
7354
7511
|
function readText2(path) {
|
|
7355
7512
|
try {
|
|
7356
|
-
return
|
|
7513
|
+
return readFileSync10(path, "utf8");
|
|
7357
7514
|
} catch {
|
|
7358
7515
|
return null;
|
|
7359
7516
|
}
|
|
@@ -7398,7 +7555,7 @@ function vendorableAgentWarnings(agents, root) {
|
|
|
7398
7555
|
|
|
7399
7556
|
// src/project/gitignore.ts
|
|
7400
7557
|
import { createHash } from "crypto";
|
|
7401
|
-
import { existsSync as
|
|
7558
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync11, writeFileSync as writeFileSync3 } from "fs";
|
|
7402
7559
|
import { dirname as dirname3, isAbsolute as isAbsolute6, join as join18 } from "path";
|
|
7403
7560
|
var GITIGNORE_FILE = ".gitignore";
|
|
7404
7561
|
var DIGEST_NAME = "tracking.digest";
|
|
@@ -7485,9 +7642,9 @@ function attempt(file, failure3, act) {
|
|
|
7485
7642
|
}
|
|
7486
7643
|
}
|
|
7487
7644
|
function readIfPresent2(file) {
|
|
7488
|
-
if (!
|
|
7645
|
+
if (!existsSync6(file))
|
|
7489
7646
|
return null;
|
|
7490
|
-
return attempt(file, "cannot be read", () =>
|
|
7647
|
+
return attempt(file, "cannot be read", () => readFileSync11(file, "utf8"));
|
|
7491
7648
|
}
|
|
7492
7649
|
function writeTrackingGitignore(root, flags) {
|
|
7493
7650
|
requireAbsolute(root);
|
|
@@ -7550,7 +7707,7 @@ import { resolve as resolve8 } from "path";
|
|
|
7550
7707
|
|
|
7551
7708
|
// src/project/roots.ts
|
|
7552
7709
|
import { spawnSync } from "child_process";
|
|
7553
|
-
import { accessSync, constants, readFileSync as
|
|
7710
|
+
import { accessSync, constants, readFileSync as readFileSync12, statSync as statSync9 } from "fs";
|
|
7554
7711
|
import { isAbsolute as isAbsolute7, join as join19, resolve as resolve7 } from "path";
|
|
7555
7712
|
var REFUSED_ROOTS = Object.freeze([
|
|
7556
7713
|
{ path: "/", why: "is the filesystem root" },
|
|
@@ -7571,7 +7728,7 @@ var PACKAGE_JSON = "package.json";
|
|
|
7571
7728
|
var NOT_A_REPOSITORY = "fatal: not a git repository (or any ";
|
|
7572
7729
|
var DISK_ROOTS_FILE_SYSTEM = Object.freeze({
|
|
7573
7730
|
...DISK_FILE_SYSTEM,
|
|
7574
|
-
readFile: (path) =>
|
|
7731
|
+
readFile: (path) => readFileSync12(path, "utf8"),
|
|
7575
7732
|
isDirectory: (path) => statSync9(path).isDirectory(),
|
|
7576
7733
|
assertWritable: (path) => accessSync(path, constants.W_OK)
|
|
7577
7734
|
});
|
|
@@ -7763,10 +7920,10 @@ function namedRoot(typed, start2, source, seams) {
|
|
|
7763
7920
|
return chosen(fs.realpath(path), source);
|
|
7764
7921
|
}
|
|
7765
7922
|
function numberedCandidate(digits, found) {
|
|
7766
|
-
const
|
|
7923
|
+
const count2 = found.candidates.length;
|
|
7767
7924
|
const candidate = found.candidates[Number(digits) - 1];
|
|
7768
7925
|
if (candidate === undefined) {
|
|
7769
|
-
return problem(`no candidate is numbered ${digits}; type 1 to ${String(
|
|
7926
|
+
return problem(`no candidate is numbered ${digits}; type 1 to ${String(count2)}, or a path`);
|
|
7770
7927
|
}
|
|
7771
7928
|
return candidate.refusal === null ? chosen(candidate.path, candidate.source) : problem(candidate.refusal.reason);
|
|
7772
7929
|
}
|
|
@@ -7796,7 +7953,7 @@ async function promptForRoot(found, prompter, seams) {
|
|
|
7796
7953
|
}
|
|
7797
7954
|
|
|
7798
7955
|
// src/project/scaffold.ts
|
|
7799
|
-
import { existsSync as
|
|
7956
|
+
import { existsSync as existsSync7, lstatSync as lstatSync2, mkdirSync as mkdirSync5, statSync as statSync10, writeFileSync as writeFileSync4 } from "fs";
|
|
7800
7957
|
import { join as join20 } from "path";
|
|
7801
7958
|
var PROJECT_TREE = Object.freeze(["specs", "plans", "runs", "effort", "instincts"]);
|
|
7802
7959
|
var USER_TREE = Object.freeze(["instincts"]);
|
|
@@ -7857,7 +8014,10 @@ var CONFIG_SETTINGS_LINES = Object.freeze([
|
|
|
7857
8014
|
"# skills: {} # name: false turns a skill off; name: project | rafa | user pins its tier",
|
|
7858
8015
|
"# agents: {} # name: false turns an agent off; name: project | rafa | user pins its tier",
|
|
7859
8016
|
"# routing:",
|
|
7860
|
-
...DEFAULT_ROUTES.map(([shape, agent]) => `# ${shape}: ${agent}`)
|
|
8017
|
+
...DEFAULT_ROUTES.map(([shape, agent]) => `# ${shape}: ${agent}`),
|
|
8018
|
+
"# task:",
|
|
8019
|
+
`# skills: ${CONFIG_DEFAULTS.taskSkills} # planner | tag | none, the resolver that picks a task's skills`,
|
|
8020
|
+
`# lessons: ${CONFIG_DEFAULTS.taskLessons} # on | off, whether blessed lessons join a task's prompt`
|
|
7861
8021
|
]);
|
|
7862
8022
|
var VERSION_LINE = `version: ${String(CONFIG_DEFAULTS.version)}`;
|
|
7863
8023
|
var PROJECT_HEADER = Object.freeze([
|
|
@@ -7906,7 +8066,7 @@ function isDirectory2(path) {
|
|
|
7906
8066
|
function directoryConflict(dir) {
|
|
7907
8067
|
if (!occupied(dir) || isDirectory2(dir))
|
|
7908
8068
|
return null;
|
|
7909
|
-
return
|
|
8069
|
+
return existsSync7(dir) ? `${dir} is not a directory` : `${dir} is a link to nothing`;
|
|
7910
8070
|
}
|
|
7911
8071
|
function layoutConflicts(layout) {
|
|
7912
8072
|
const [scopeDir, ...tree] = layout.dirs;
|
|
@@ -7914,7 +8074,7 @@ function layoutConflicts(layout) {
|
|
|
7914
8074
|
if (opening !== null)
|
|
7915
8075
|
return [opening];
|
|
7916
8076
|
const dirs = tree.flatMap((dir) => directoryConflict(dir) ?? []);
|
|
7917
|
-
const file = occupied(layout.configFile) && !
|
|
8077
|
+
const file = occupied(layout.configFile) && !existsSync7(layout.configFile) ? [`${layout.configFile} is a link to nothing`] : [];
|
|
7918
8078
|
return [...dirs, ...file];
|
|
7919
8079
|
}
|
|
7920
8080
|
function scaffoldConflicts(root, home) {
|
|
@@ -7928,7 +8088,7 @@ function attempt2(path, failure3, act) {
|
|
|
7928
8088
|
}
|
|
7929
8089
|
}
|
|
7930
8090
|
function ensureDirectory(path) {
|
|
7931
|
-
if (
|
|
8091
|
+
if (existsSync7(path))
|
|
7932
8092
|
return { path, kind: "directory", change: "unchanged" };
|
|
7933
8093
|
attempt2(path, "cannot be created", () => {
|
|
7934
8094
|
mkdirSync5(path, { recursive: true });
|
|
@@ -7936,7 +8096,7 @@ function ensureDirectory(path) {
|
|
|
7936
8096
|
return { path, kind: "directory", change: "created" };
|
|
7937
8097
|
}
|
|
7938
8098
|
function ensureFile(path, text) {
|
|
7939
|
-
if (
|
|
8099
|
+
if (existsSync7(path))
|
|
7940
8100
|
return { path, kind: "file", change: "unchanged" };
|
|
7941
8101
|
attempt2(path, "cannot be written", () => {
|
|
7942
8102
|
writeFileSync4(path, text, { encoding: "utf8", flag: "wx" });
|
|
@@ -7959,7 +8119,7 @@ function writeUserScope(home) {
|
|
|
7959
8119
|
import { writeFileSync as writeFileSync5 } from "fs";
|
|
7960
8120
|
|
|
7961
8121
|
// src/release/setting.ts
|
|
7962
|
-
import { readFileSync as
|
|
8122
|
+
import { readFileSync as readFileSync13 } from "fs";
|
|
7963
8123
|
var RELEASE_ENABLED_SETTING = "release.enabled";
|
|
7964
8124
|
function releaseEnabledIn(text, path) {
|
|
7965
8125
|
return parseConfigText(text, path).values.releaseEnabled ?? null;
|
|
@@ -7968,7 +8128,7 @@ function readReleaseSetting(root) {
|
|
|
7968
8128
|
const path = configFilePath(root);
|
|
7969
8129
|
let text;
|
|
7970
8130
|
try {
|
|
7971
|
-
text =
|
|
8131
|
+
text = readFileSync13(path, "utf8");
|
|
7972
8132
|
} catch (error) {
|
|
7973
8133
|
return { enabled: null, text: "", problem: `${path} could not be read: ${messageOf(error)}` };
|
|
7974
8134
|
}
|
|
@@ -8245,7 +8405,7 @@ function resolvedConfig2(root, home, warn) {
|
|
|
8245
8405
|
function checkGitignore(root, flags) {
|
|
8246
8406
|
const file = join21(root, GITIGNORE_FILE);
|
|
8247
8407
|
try {
|
|
8248
|
-
const text =
|
|
8408
|
+
const text = existsSync8(file) ? readFileSync14(file, "utf8") : null;
|
|
8249
8409
|
withTrackingBlock(text, flags, file);
|
|
8250
8410
|
} catch (error) {
|
|
8251
8411
|
const message = error instanceof GitignoreError ? error.message : `rafa init: ${file} cannot be read (${messageOf(error)})`;
|
|
@@ -8276,8 +8436,8 @@ function initialise(root, start2, home, context, entry) {
|
|
|
8276
8436
|
checkConflicts(root.path, home);
|
|
8277
8437
|
const config = resolvedConfig2(root.path, home, warn);
|
|
8278
8438
|
checkGitignore(root.path, config);
|
|
8279
|
-
const configExisted =
|
|
8280
|
-
const digestExisted =
|
|
8439
|
+
const configExisted = existsSync8(configFilePath(root.path));
|
|
8440
|
+
const digestExisted = existsSync8(join21(root.path, TRACKING_DIGEST_FILE));
|
|
8281
8441
|
const project = writeProjectScope(root.path);
|
|
8282
8442
|
const tracking = applyTracking(root.path, config, warn);
|
|
8283
8443
|
const writes = [...project, ...trackingWrites(tracking, digestExisted), ...writeUserScope(home)];
|
|
@@ -9100,7 +9260,7 @@ function createInstinctShowCommand() {
|
|
|
9100
9260
|
var show_default2 = createInstinctShowCommand();
|
|
9101
9261
|
|
|
9102
9262
|
// src/commands/issue/check.ts
|
|
9103
|
-
import { readdirSync as readdirSync3, readFileSync as
|
|
9263
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync15, statSync as statSync11 } from "fs";
|
|
9104
9264
|
import { join as join22, resolve as resolve10 } from "path";
|
|
9105
9265
|
var CHECK_USAGE = "rafa issue check <n> [--stamp]";
|
|
9106
9266
|
var STAMP_FLAG = "stamp";
|
|
@@ -9177,7 +9337,7 @@ function checkedRefLine(ref) {
|
|
|
9177
9337
|
}
|
|
9178
9338
|
function countLine(references) {
|
|
9179
9339
|
const noun = references.length === 1 ? "reference" : "references";
|
|
9180
|
-
const counts = STATE_ORDER.map((state) => [state, references.filter((ref) => ref.state === state).length]).filter(([,
|
|
9340
|
+
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
9341
|
return counts.length === 0 ? "No references." : `${String(references.length)} ${noun}: ${counts.join(", ")}`;
|
|
9182
9342
|
}
|
|
9183
9343
|
function renderCheck2(result) {
|
|
@@ -9196,7 +9356,7 @@ async function readReferences(absolute, issue, verify, stamp) {
|
|
|
9196
9356
|
return rows.map((row2) => checkedRef(row2, row2.stamp));
|
|
9197
9357
|
}
|
|
9198
9358
|
const once = memoiseVerifier(verify);
|
|
9199
|
-
const before = await readRefsText({ copy:
|
|
9359
|
+
const before = await readRefsText({ copy: readFileSync15(absolute, "utf8"), issue, verify: once });
|
|
9200
9360
|
const after = await restampCopyRefs({ path: absolute, issue, verify: once });
|
|
9201
9361
|
return before.rows.map((row2, index) => checkedRef(row2, after.rows[index]?.stamp ?? null));
|
|
9202
9362
|
}
|
|
@@ -10603,6 +10763,11 @@ var wrapped = wrapPhaseZeroCommand({
|
|
|
10603
10763
|
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
10764
|
type: "string"
|
|
10605
10765
|
},
|
|
10766
|
+
{
|
|
10767
|
+
name: "skills-resolver",
|
|
10768
|
+
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.",
|
|
10769
|
+
type: "string"
|
|
10770
|
+
},
|
|
10606
10771
|
{
|
|
10607
10772
|
name: "runtime",
|
|
10608
10773
|
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 +11247,7 @@ function fastForwardBase(git, plan2) {
|
|
|
11082
11247
|
|
|
11083
11248
|
// src/commands/next.ts
|
|
11084
11249
|
var NEXT_USAGE = "rafa next [--dry-run] [--yes[=<action ids>]]";
|
|
11085
|
-
var
|
|
11250
|
+
var DRY_RUN_FLAG3 = "dry-run";
|
|
11086
11251
|
var STATE_MARK = "\uD83D\uDCCD";
|
|
11087
11252
|
var PROPOSAL_MARK = "\uD83D\uDC49";
|
|
11088
11253
|
var STOP_MARK = "\u23F9";
|
|
@@ -11103,7 +11268,7 @@ function dryRunLine(dryRun) {
|
|
|
11103
11268
|
if (dryRun === "no-terminal") {
|
|
11104
11269
|
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
11270
|
}
|
|
11106
|
-
return `${STOP_MARK} --${
|
|
11271
|
+
return `${STOP_MARK} --${DRY_RUN_FLAG3}: nothing ran.`;
|
|
11107
11272
|
}
|
|
11108
11273
|
function stopLine(stop, state, ceiling, dryRun) {
|
|
11109
11274
|
if (stop === "dry-run")
|
|
@@ -11199,14 +11364,14 @@ function lineRefusal2(problem2) {
|
|
|
11199
11364
|
Usage: ${NEXT_USAGE}`);
|
|
11200
11365
|
}
|
|
11201
11366
|
function readDryRun(flags) {
|
|
11202
|
-
const value = flags[
|
|
11367
|
+
const value = flags[DRY_RUN_FLAG3];
|
|
11203
11368
|
if (value === undefined)
|
|
11204
11369
|
return false;
|
|
11205
11370
|
if (typeof value === "boolean")
|
|
11206
11371
|
return value;
|
|
11207
11372
|
if (value === "true" || value === "false")
|
|
11208
11373
|
return value === "true";
|
|
11209
|
-
throw lineRefusal2(`--${
|
|
11374
|
+
throw lineRefusal2(`--${DRY_RUN_FLAG3} takes no value, and read "${value}" as one`);
|
|
11210
11375
|
}
|
|
11211
11376
|
function dryRunOf(flag, ceiling, hasTerminal) {
|
|
11212
11377
|
if (flag)
|
|
@@ -11258,7 +11423,7 @@ async function runNext(context, seams) {
|
|
|
11258
11423
|
var YES_ID_LIST = YES_ACTIONS.join(", ");
|
|
11259
11424
|
var NEXT_FLAGS = Object.freeze([
|
|
11260
11425
|
{
|
|
11261
|
-
name:
|
|
11426
|
+
name: DRY_RUN_FLAG3,
|
|
11262
11427
|
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
11428
|
type: "boolean"
|
|
11264
11429
|
},
|
|
@@ -11395,7 +11560,7 @@ var wrapped2 = wrapPhaseZeroCommand({
|
|
|
11395
11560
|
var create_default2 = endingWith(wrapped2);
|
|
11396
11561
|
|
|
11397
11562
|
// src/commands/plan/risk.ts
|
|
11398
|
-
import { readFileSync as
|
|
11563
|
+
import { readFileSync as readFileSync16 } from "fs";
|
|
11399
11564
|
import { resolve as resolve11 } from "path";
|
|
11400
11565
|
var COMMAND2 = "rafa plan risk";
|
|
11401
11566
|
var USAGE22 = "rafa plan risk [<plan>] [--strict]";
|
|
@@ -11423,7 +11588,7 @@ function strictRefusal(report2) {
|
|
|
11423
11588
|
}
|
|
11424
11589
|
async function readRisk(path, project, config, context, seams) {
|
|
11425
11590
|
const makeRunners = seams.runners ?? spawningRunners;
|
|
11426
|
-
return assessPlanRisk({ path, text:
|
|
11591
|
+
return assessPlanRisk({ path, text: readFileSync16(path, "utf8") }, {
|
|
11427
11592
|
repoRoot: project.root,
|
|
11428
11593
|
home: project.home,
|
|
11429
11594
|
settingSources: config.settingSources,
|
|
@@ -11506,7 +11671,7 @@ function createPlanRiskCommand(seams = {}) {
|
|
|
11506
11671
|
var risk_default = createPlanRiskCommand();
|
|
11507
11672
|
|
|
11508
11673
|
// src/commands/plan/show.ts
|
|
11509
|
-
import { readFileSync as
|
|
11674
|
+
import { readFileSync as readFileSync17 } from "fs";
|
|
11510
11675
|
import { join as join23 } from "path";
|
|
11511
11676
|
var USAGE23 = "rafa plan show <stub> [--tracker]";
|
|
11512
11677
|
var COMMAND3 = "rafa plan show";
|
|
@@ -11528,7 +11693,7 @@ function showPlan(plans, stub, tracker) {
|
|
|
11528
11693
|
const file = join23(plans.path, name2);
|
|
11529
11694
|
if (!isFile(file))
|
|
11530
11695
|
throw new CommandExit(1, missingText(stub, tracker, join23(plans.label, name2)));
|
|
11531
|
-
const model = parsePlan(
|
|
11696
|
+
const model = parsePlan(readFileSync17(file, "utf8"));
|
|
11532
11697
|
const { header } = model;
|
|
11533
11698
|
return {
|
|
11534
11699
|
stub,
|
|
@@ -11707,6 +11872,7 @@ function openPrContext(context, seams = DEFAULT_PR_SEAMS) {
|
|
|
11707
11872
|
resolveBudget: config.prResolveBudget,
|
|
11708
11873
|
trustedAuthors: config.boardTrustedAuthors,
|
|
11709
11874
|
roadmapIssue: config.roadmapIssue,
|
|
11875
|
+
planDir: config.planDir,
|
|
11710
11876
|
readBranch: () => readBranch2(project.root)
|
|
11711
11877
|
};
|
|
11712
11878
|
}
|
|
@@ -11872,8 +12038,8 @@ function titleCell(title) {
|
|
|
11872
12038
|
return "(no title)";
|
|
11873
12039
|
return trimmed.length > TITLE_WIDTH ? `${trimmed.slice(0, TITLE_WIDTH - CUT.length)}${CUT}` : trimmed;
|
|
11874
12040
|
}
|
|
11875
|
-
function headLine3(
|
|
11876
|
-
return
|
|
12041
|
+
function headLine3(count2) {
|
|
12042
|
+
return count2 === 1 ? "1 open pull request" : `${count2} open pull requests`;
|
|
11877
12043
|
}
|
|
11878
12044
|
function cellsOf(row2, now) {
|
|
11879
12045
|
return [
|
|
@@ -11970,7 +12136,7 @@ function createPrListCommand(seams = DEFAULT_PR_SEAMS) {
|
|
|
11970
12136
|
var list_default8 = createPrListCommand();
|
|
11971
12137
|
|
|
11972
12138
|
// src/commands/pr/merge.ts
|
|
11973
|
-
import { existsSync as
|
|
12139
|
+
import { existsSync as existsSync10, readFileSync as readFileSync19 } from "fs";
|
|
11974
12140
|
import { join as join25 } from "path";
|
|
11975
12141
|
|
|
11976
12142
|
// src/board/roadmap-tick.ts
|
|
@@ -12126,13 +12292,13 @@ function tickSentence(result) {
|
|
|
12126
12292
|
import {
|
|
12127
12293
|
chmodSync,
|
|
12128
12294
|
copyFileSync as copyFileSync3,
|
|
12129
|
-
existsSync as
|
|
12295
|
+
existsSync as existsSync9,
|
|
12130
12296
|
mkdirSync as mkdirSync6,
|
|
12131
12297
|
readdirSync as readdirSync5,
|
|
12132
|
-
readFileSync as
|
|
12298
|
+
readFileSync as readFileSync18,
|
|
12133
12299
|
realpathSync as realpathSync5,
|
|
12134
|
-
renameSync,
|
|
12135
|
-
rmSync as
|
|
12300
|
+
renameSync as renameSync2,
|
|
12301
|
+
rmSync as rmSync3,
|
|
12136
12302
|
statSync as statSync12,
|
|
12137
12303
|
symlinkSync
|
|
12138
12304
|
} from "fs";
|
|
@@ -12202,12 +12368,12 @@ function listTrackers(repoRoot, planDir) {
|
|
|
12202
12368
|
}
|
|
12203
12369
|
function openTrackers(repoRoot, planDir) {
|
|
12204
12370
|
return listTrackers(repoRoot, planDir).flatMap((path) => {
|
|
12205
|
-
const task = findNextTask(
|
|
12371
|
+
const task = findNextTask(readFileSync18(join24(repoRoot, path), "utf8"));
|
|
12206
12372
|
return task ? [{ path, task }] : [];
|
|
12207
12373
|
});
|
|
12208
12374
|
}
|
|
12209
12375
|
function readManifestVersion2(repoRoot) {
|
|
12210
|
-
const manifest = JSON.parse(
|
|
12376
|
+
const manifest = JSON.parse(readFileSync18(join24(repoRoot, "package.json"), "utf8"));
|
|
12211
12377
|
const record = typeof manifest === "object" && manifest !== null ? manifest : {};
|
|
12212
12378
|
if (record["name"] !== name) {
|
|
12213
12379
|
throw new Error(`${join24(repoRoot, "package.json")} names ${JSON.stringify(record["name"])}, not ${name}: this is no rafa checkout`);
|
|
@@ -12238,41 +12404,41 @@ function copyTree(from, to) {
|
|
|
12238
12404
|
}
|
|
12239
12405
|
function replaceTree(from, to) {
|
|
12240
12406
|
const staging = temporaryName(to);
|
|
12241
|
-
|
|
12407
|
+
rmSync3(staging, { recursive: true, force: true });
|
|
12242
12408
|
try {
|
|
12243
12409
|
const copied = copyTree(from, staging);
|
|
12244
|
-
|
|
12410
|
+
swapIn2(staging, to);
|
|
12245
12411
|
return copied;
|
|
12246
12412
|
} catch (err) {
|
|
12247
|
-
|
|
12413
|
+
rmSync3(staging, { recursive: true, force: true });
|
|
12248
12414
|
throw err;
|
|
12249
12415
|
}
|
|
12250
12416
|
}
|
|
12251
|
-
function
|
|
12252
|
-
if (!
|
|
12253
|
-
|
|
12417
|
+
function swapIn2(staging, to) {
|
|
12418
|
+
if (!existsSync9(to)) {
|
|
12419
|
+
renameSync2(staging, to);
|
|
12254
12420
|
return;
|
|
12255
12421
|
}
|
|
12256
12422
|
const outgoing = `${temporaryName(to)}.outgoing`;
|
|
12257
|
-
|
|
12258
|
-
|
|
12423
|
+
rmSync3(outgoing, { recursive: true, force: true });
|
|
12424
|
+
renameSync2(to, outgoing);
|
|
12259
12425
|
try {
|
|
12260
|
-
|
|
12426
|
+
renameSync2(staging, to);
|
|
12261
12427
|
} catch (err) {
|
|
12262
|
-
|
|
12428
|
+
renameSync2(outgoing, to);
|
|
12263
12429
|
throw err;
|
|
12264
12430
|
}
|
|
12265
|
-
|
|
12431
|
+
rmSync3(outgoing, { recursive: true, force: true });
|
|
12266
12432
|
}
|
|
12267
12433
|
function relink(linkPath, target) {
|
|
12268
12434
|
mkdirSync6(dirname4(linkPath), { recursive: true });
|
|
12269
12435
|
const temporary = temporaryName(linkPath);
|
|
12270
|
-
|
|
12436
|
+
rmSync3(temporary, { force: true });
|
|
12271
12437
|
try {
|
|
12272
12438
|
symlinkSync(target, temporary);
|
|
12273
|
-
|
|
12439
|
+
renameSync2(temporary, linkPath);
|
|
12274
12440
|
} catch (err) {
|
|
12275
|
-
|
|
12441
|
+
rmSync3(temporary, { force: true });
|
|
12276
12442
|
throw err;
|
|
12277
12443
|
}
|
|
12278
12444
|
const resolved = realpathSync5(linkPath);
|
|
@@ -12332,7 +12498,7 @@ function runInstall(seams, options) {
|
|
|
12332
12498
|
return { kind: "refused", reason: "trackers", planDir, trackers: open };
|
|
12333
12499
|
const distDir = join24(repoRoot, "dist");
|
|
12334
12500
|
const runtimeDir = join24(runtimeRoot, version2);
|
|
12335
|
-
const installed =
|
|
12501
|
+
const installed = existsSync9(runtimeDir);
|
|
12336
12502
|
if (installed && options.force !== true) {
|
|
12337
12503
|
return { kind: "refused", reason: "runtime-exists", version: version2, runtimeDir };
|
|
12338
12504
|
}
|
|
@@ -12340,7 +12506,7 @@ function runInstall(seams, options) {
|
|
|
12340
12506
|
const code = inStage("build", () => seams.build(repoRoot));
|
|
12341
12507
|
if (code !== 0)
|
|
12342
12508
|
throw new StageFailure("build", `the build exited ${code}`);
|
|
12343
|
-
if (!
|
|
12509
|
+
if (!existsSync9(join24(distDir, RUNTIME_ENTRY))) {
|
|
12344
12510
|
throw new StageFailure("build", `the build exited 0 and left no ${join24(distDir, RUNTIME_ENTRY)}`);
|
|
12345
12511
|
}
|
|
12346
12512
|
log(installed ? `copying ${distDir} over ${runtimeDir}, replacing it whole` : `copying ${distDir} into ${runtimeDir}`);
|
|
@@ -12373,9 +12539,9 @@ function replaceFile(source, target) {
|
|
|
12373
12539
|
try {
|
|
12374
12540
|
copyFileSync3(source, temporary);
|
|
12375
12541
|
chmodSync(temporary, statSync12(source).mode & 4095);
|
|
12376
|
-
|
|
12542
|
+
renameSync2(temporary, target);
|
|
12377
12543
|
} catch (err) {
|
|
12378
|
-
|
|
12544
|
+
rmSync3(temporary, { force: true });
|
|
12379
12545
|
throw err;
|
|
12380
12546
|
}
|
|
12381
12547
|
}
|
|
@@ -12573,11 +12739,11 @@ async function confirmUncheckedMerge(unchecked, options) {
|
|
|
12573
12739
|
}
|
|
12574
12740
|
}
|
|
12575
12741
|
function commentProblemLine(number, problem2, body) {
|
|
12576
|
-
const
|
|
12742
|
+
const quoted2 = body.split(`
|
|
12577
12743
|
`).map((line) => `${INDENT3}${line}`).join(`
|
|
12578
12744
|
`);
|
|
12579
12745
|
return `the unchecked-merge comment was not posted on #${number}: ${problem2}. Post it yourself:
|
|
12580
|
-
${
|
|
12746
|
+
${quoted2}`;
|
|
12581
12747
|
}
|
|
12582
12748
|
async function postUncheckedComment(pulls, number, unchecked, warn) {
|
|
12583
12749
|
const body = unchecked.reading.comment;
|
|
@@ -12671,7 +12837,7 @@ function remoteHoldsBranch(git, branch, warn) {
|
|
|
12671
12837
|
}
|
|
12672
12838
|
function textOf(path) {
|
|
12673
12839
|
try {
|
|
12674
|
-
return
|
|
12840
|
+
return readFileSync19(path, "utf8");
|
|
12675
12841
|
} catch {
|
|
12676
12842
|
return "";
|
|
12677
12843
|
}
|
|
@@ -12685,7 +12851,7 @@ function followUpsFor(pr, git) {
|
|
|
12685
12851
|
version: facts.version,
|
|
12686
12852
|
tagged: tags.ok && tags.stdout.trim() !== "",
|
|
12687
12853
|
rafaCheckout: facts.rafaCheckout,
|
|
12688
|
-
runtimeInstalled:
|
|
12854
|
+
runtimeInstalled: existsSync10(join25(pr.project.home, RUNTIME_SUBDIR, facts.version))
|
|
12689
12855
|
});
|
|
12690
12856
|
}
|
|
12691
12857
|
function openGh(pr, seams) {
|
|
@@ -12810,6 +12976,15 @@ async function runMerge(context, seams) {
|
|
|
12810
12976
|
throw lineRefusal3(`No pull request #${pick.number} at ${pr.project.root}`, USAGE26);
|
|
12811
12977
|
}
|
|
12812
12978
|
const checks = await onProvider(`read the checks of #${pick.number}`, () => pr.pulls.checks(pick.number));
|
|
12979
|
+
recordPlanCi({
|
|
12980
|
+
repoRoot: pr.project.root,
|
|
12981
|
+
planDir: pr.planDir,
|
|
12982
|
+
pullRequest: detail,
|
|
12983
|
+
rows: checks.rows,
|
|
12984
|
+
warn: (message) => {
|
|
12985
|
+
context.output.warn(message);
|
|
12986
|
+
}
|
|
12987
|
+
});
|
|
12813
12988
|
refuseFromGit(git, detail, checks, skipChecks);
|
|
12814
12989
|
const summary = summaryLine2(detail, method);
|
|
12815
12990
|
const answer2 = await askToMerge(context, pr, seams, { number: detail.number, summary, yes, skipChecks });
|
|
@@ -13066,8 +13241,8 @@ function fencedBlock(body, language) {
|
|
|
13066
13241
|
return `${fence}${language}
|
|
13067
13242
|
${text}${fence}`;
|
|
13068
13243
|
}
|
|
13069
|
-
function counted2(
|
|
13070
|
-
return
|
|
13244
|
+
function counted2(count2, noun) {
|
|
13245
|
+
return count2 === 1 ? `1 ${noun}` : `${count2} ${noun}s`;
|
|
13071
13246
|
}
|
|
13072
13247
|
function excerptCaption(reading) {
|
|
13073
13248
|
const shown = counted2(reading.lines.length, "line");
|
|
@@ -13236,17 +13411,17 @@ function readTriageBlock(body) {
|
|
|
13236
13411
|
}
|
|
13237
13412
|
return readFields(document);
|
|
13238
13413
|
}
|
|
13239
|
-
function
|
|
13414
|
+
function quoted2(value) {
|
|
13240
13415
|
return JSON.stringify(value);
|
|
13241
13416
|
}
|
|
13242
13417
|
function writeTriageBlock(fields) {
|
|
13243
13418
|
return [
|
|
13244
|
-
`head: ${
|
|
13245
|
-
`at: ${
|
|
13246
|
-
`class: ${
|
|
13419
|
+
`head: ${quoted2(fields.head)}`,
|
|
13420
|
+
`at: ${quoted2(fields.at)}`,
|
|
13421
|
+
`class: ${quoted2(fields.triageClass)}`,
|
|
13247
13422
|
`simple: ${String(fields.simple)}`,
|
|
13248
13423
|
`attempts: ${String(fields.attempts)}`,
|
|
13249
|
-
`files: [${fields.files.map((file) =>
|
|
13424
|
+
`files: [${fields.files.map((file) => quoted2(file)).join(", ")}]`
|
|
13250
13425
|
].join(`
|
|
13251
13426
|
`);
|
|
13252
13427
|
}
|
|
@@ -13276,10 +13451,10 @@ function noChecksLines(input) {
|
|
|
13276
13451
|
return [];
|
|
13277
13452
|
const number = input.pr.number;
|
|
13278
13453
|
const unchecked = readUnchecked(number, input.workflowCount ?? null);
|
|
13279
|
-
const [
|
|
13454
|
+
const [count2 = "", warning = ""] = unchecked.warning;
|
|
13280
13455
|
const yes = unchecked.yesMayAnswer ? "`--yes` may answer it" : "`--yes` is refused, so a person must answer it";
|
|
13281
13456
|
return [
|
|
13282
|
-
`- Workflows: ${
|
|
13457
|
+
`- Workflows: ${count2}`,
|
|
13283
13458
|
`- Warning: ${warning}`,
|
|
13284
13459
|
`- To merge it anyway: \`${skipChecksCommand(number)}\` (it asks first; ${yes})`
|
|
13285
13460
|
];
|
|
@@ -13671,8 +13846,8 @@ function readsAsConflicting(pr, conflictFiles) {
|
|
|
13671
13846
|
return true;
|
|
13672
13847
|
return conflictFiles.length > 0;
|
|
13673
13848
|
}
|
|
13674
|
-
function checkCount(
|
|
13675
|
-
return
|
|
13849
|
+
function checkCount(count2) {
|
|
13850
|
+
return count2 === 1 ? "1 check" : `${count2} checks`;
|
|
13676
13851
|
}
|
|
13677
13852
|
function fileList(files) {
|
|
13678
13853
|
const shown = files.slice(0, REASON_FILE_LIMIT).join(", ");
|
|
@@ -13683,12 +13858,12 @@ function conflictReason(files) {
|
|
|
13683
13858
|
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
13859
|
}
|
|
13685
13860
|
function failureReason(step, failing) {
|
|
13686
|
-
const
|
|
13687
|
-
return step === undefined ? `${
|
|
13861
|
+
const count2 = checkCount(failing.length);
|
|
13862
|
+
return step === undefined ? `${count2} failing, and no failing step was named` : `${count2} failing, the failing step being "${step.name}"`;
|
|
13688
13863
|
}
|
|
13689
13864
|
function noChecksReason(number, workflowCount) {
|
|
13690
|
-
const
|
|
13691
|
-
return `the head reports no checks at all; ${
|
|
13865
|
+
const count2 = workflowCountLine(workflowCount).replace(/\.$/, "");
|
|
13866
|
+
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
13867
|
}
|
|
13693
13868
|
function decideClass(input, verdict, conflicting) {
|
|
13694
13869
|
const { conflictFiles, rows, step } = input;
|
|
@@ -13770,8 +13945,8 @@ function isSameHead(stored, head) {
|
|
|
13770
13945
|
function shortHead(head) {
|
|
13771
13946
|
return head.trim().slice(0, HEADLINE_HEAD_LENGTH);
|
|
13772
13947
|
}
|
|
13773
|
-
function checkCount2(
|
|
13774
|
-
return
|
|
13948
|
+
function checkCount2(count2) {
|
|
13949
|
+
return count2 === 1 ? "1 check" : `${count2} checks`;
|
|
13775
13950
|
}
|
|
13776
13951
|
function storedTime(comment, block) {
|
|
13777
13952
|
if (comment === null)
|
|
@@ -13873,8 +14048,8 @@ function isFreshCandidate(updatedAt, now) {
|
|
|
13873
14048
|
const age = ageMs(updatedAt, now);
|
|
13874
14049
|
return age !== null && age <= TRIAGE_FRESH_WINDOW_MS;
|
|
13875
14050
|
}
|
|
13876
|
-
function plural4(
|
|
13877
|
-
return
|
|
14051
|
+
function plural4(count2, singular, many) {
|
|
14052
|
+
return count2 === 1 ? `1 ${singular}` : `${count2} ${many}`;
|
|
13878
14053
|
}
|
|
13879
14054
|
function describeAge(updatedAt, now) {
|
|
13880
14055
|
const age = ageMs(updatedAt, now);
|
|
@@ -13938,17 +14113,17 @@ function listing(decision, assess, rest, headline, exitCode = 0) {
|
|
|
13938
14113
|
`)
|
|
13939
14114
|
});
|
|
13940
14115
|
}
|
|
13941
|
-
function refusal6(rest,
|
|
13942
|
-
const headline = `${REFUSAL_PREFIX2}: ${plural4(
|
|
14116
|
+
function refusal6(rest, count2) {
|
|
14117
|
+
const headline = `${REFUSAL_PREFIX2}: ${plural4(count2, "red pull request", "red pull requests")}, ` + "and --resolve acts on one. Run one of:";
|
|
13943
14118
|
return listing("refuse", Object.freeze([]), rest, headline, REFUSE_EXIT_CODE);
|
|
13944
14119
|
}
|
|
13945
|
-
function someReading(fresh, stale,
|
|
14120
|
+
function someReading(fresh, stale, count2) {
|
|
13946
14121
|
const older = stale.length === 0 ? "" : `; ${plural4(stale.length, "older one is", "older ones are")} skipped`;
|
|
13947
|
-
const headline = `${
|
|
14122
|
+
const headline = `${count2} red: assessing ${joinNumbers(fresh)}${older}`;
|
|
13948
14123
|
return listing("some", fresh, stale, headline);
|
|
13949
14124
|
}
|
|
13950
|
-
function listReading(rest,
|
|
13951
|
-
const headline =
|
|
14125
|
+
function listReading(rest, count2) {
|
|
14126
|
+
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
14127
|
return listing("list", Object.freeze([]), rest, headline);
|
|
13953
14128
|
}
|
|
13954
14129
|
function selectTriagePullRequests(input) {
|
|
@@ -13958,24 +14133,24 @@ function selectTriagePullRequests(input) {
|
|
|
13958
14133
|
return plain("branch", Object.freeze([current]), `assessing #${current.number}, the pull request open on ${current.headRefName}`);
|
|
13959
14134
|
}
|
|
13960
14135
|
const candidates = byNumber(input.candidates);
|
|
13961
|
-
const
|
|
14136
|
+
const count2 = candidates.length;
|
|
13962
14137
|
const lines2 = candidates.map((pull) => skipped(pull, now, resolve13));
|
|
13963
|
-
if (resolve13 &&
|
|
13964
|
-
return refusal6(lines2,
|
|
13965
|
-
if (
|
|
14138
|
+
if (resolve13 && count2 > 1)
|
|
14139
|
+
return refusal6(lines2, count2);
|
|
14140
|
+
if (count2 === 0) {
|
|
13966
14141
|
return plain("none", Object.freeze([]), "no red pull request to triage, and no pull request on the current branch");
|
|
13967
14142
|
}
|
|
13968
|
-
if (
|
|
14143
|
+
if (count2 === 1) {
|
|
13969
14144
|
const only = candidates[0];
|
|
13970
14145
|
return plain("single", Object.freeze([only]), `1 red: assessing #${only.number}, last moved ${describeAge(only.updatedAt, now)}`);
|
|
13971
14146
|
}
|
|
13972
|
-
if (
|
|
13973
|
-
return listReading(lines2,
|
|
14147
|
+
if (count2 > MAX_TRIAGE_CANDIDATES)
|
|
14148
|
+
return listReading(lines2, count2);
|
|
13974
14149
|
const fresh = candidates.filter((pull) => isFreshCandidate(pull.updatedAt, now));
|
|
13975
14150
|
const stale = lines2.filter((one) => !one.fresh);
|
|
13976
14151
|
if (fresh.length === 0)
|
|
13977
|
-
return listReading(stale,
|
|
13978
|
-
return someReading(Object.freeze(fresh), stale,
|
|
14152
|
+
return listReading(stale, count2);
|
|
14153
|
+
return someReading(Object.freeze(fresh), stale, count2);
|
|
13979
14154
|
}
|
|
13980
14155
|
|
|
13981
14156
|
// src/pr/triage/conflict.ts
|
|
@@ -13994,10 +14169,10 @@ function parseMessages(records, from) {
|
|
|
13994
14169
|
const countRecord = records[at];
|
|
13995
14170
|
if (countRecord === undefined || countRecord === "")
|
|
13996
14171
|
break;
|
|
13997
|
-
const
|
|
13998
|
-
if (!Number.isInteger(
|
|
14172
|
+
const count2 = Number(countRecord);
|
|
14173
|
+
if (!Number.isInteger(count2) || count2 < 0)
|
|
13999
14174
|
break;
|
|
14000
|
-
const typeAt = at + 1 +
|
|
14175
|
+
const typeAt = at + 1 + count2;
|
|
14001
14176
|
const messageAt = typeAt + 1;
|
|
14002
14177
|
const type = records[typeAt];
|
|
14003
14178
|
const message = records[messageAt];
|
|
@@ -14176,10 +14351,10 @@ function noChecksLines2(reading, assessment) {
|
|
|
14176
14351
|
return [];
|
|
14177
14352
|
const number = reading.detail.number;
|
|
14178
14353
|
const unchecked = readUnchecked(number, workflowCountOf2(reading) ?? null);
|
|
14179
|
-
const [
|
|
14354
|
+
const [count2 = "", warning = ""] = unchecked.warning;
|
|
14180
14355
|
const yes = unchecked.yesMayAnswer ? "--yes may answer it" : "--yes is refused, so a person must answer it";
|
|
14181
14356
|
return [
|
|
14182
|
-
`${INDENT7}Workflows: ${
|
|
14357
|
+
`${INDENT7}Workflows: ${count2}`,
|
|
14183
14358
|
`${INDENT7}Warning: ${warning}`,
|
|
14184
14359
|
`${INDENT7}To merge it anyway: ${skipChecksCommand(number)} (it asks first; ${yes})`
|
|
14185
14360
|
];
|
|
@@ -14295,7 +14470,7 @@ function withTaskBudget(plan2, usd) {
|
|
|
14295
14470
|
}
|
|
14296
14471
|
|
|
14297
14472
|
// src/pr/plans/load.ts
|
|
14298
|
-
import { existsSync as
|
|
14473
|
+
import { existsSync as existsSync11, readFileSync as readFileSync20 } from "fs";
|
|
14299
14474
|
import { dirname as dirname5, join as join26 } from "path";
|
|
14300
14475
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
14301
14476
|
var MODULE_DIR2 = dirname5(fileURLToPath2(import.meta.url));
|
|
@@ -14322,11 +14497,11 @@ function readPinnedPlan(triageClass, lookup = {}) {
|
|
|
14322
14497
|
throw new Error(`No pinned resolve plan ships for ${triageClass}; ` + `one ships for ${PINNED_PLAN_CLASSES.join(", ")}`);
|
|
14323
14498
|
}
|
|
14324
14499
|
const candidates = pinnedPlanCandidates(lookup.moduleDir ?? MODULE_DIR2, triageClass);
|
|
14325
|
-
const found = candidates.find((candidate) =>
|
|
14500
|
+
const found = candidates.find((candidate) => existsSync11(candidate));
|
|
14326
14501
|
if (found === undefined) {
|
|
14327
14502
|
throw new Error(`The pinned resolve plan for ${triageClass} is missing: ` + `no file at ${candidates.join(" or ")}`);
|
|
14328
14503
|
}
|
|
14329
|
-
return
|
|
14504
|
+
return readFileSync20(found, "utf8");
|
|
14330
14505
|
}
|
|
14331
14506
|
var SLOT_PATTERN = /\{[A-Z][A-Z0-9_]*\}/g;
|
|
14332
14507
|
var CONFLICT_SENTENCE_SLOT = "CONFLICT_SENTENCE";
|
|
@@ -14848,11 +15023,11 @@ function readMaxAttempts(flags, usage2) {
|
|
|
14848
15023
|
if (value === undefined)
|
|
14849
15024
|
return DEFAULT_MAX_ATTEMPTS;
|
|
14850
15025
|
const spelled = typeof value === "boolean" ? "--max-attempts with no value" : `"${value}"`;
|
|
14851
|
-
const
|
|
14852
|
-
if (!Number.isSafeInteger(
|
|
15026
|
+
const count2 = typeof value === "string" ? Number(value) : Number.NaN;
|
|
15027
|
+
if (!Number.isSafeInteger(count2) || count2 < 1) {
|
|
14853
15028
|
throw lineRefusal3(`${spelled} is no attempt count, which is a whole number from 1;` + " type the pull request number before the flags", usage2);
|
|
14854
15029
|
}
|
|
14855
|
-
return
|
|
15030
|
+
return count2;
|
|
14856
15031
|
}
|
|
14857
15032
|
function readBranchOrNone(pr, warn) {
|
|
14858
15033
|
const fallback = "so the red pull requests are the candidates";
|
|
@@ -14950,6 +15125,14 @@ async function assessOne(options) {
|
|
|
14950
15125
|
const { git, maxAttempts, number, pr } = options;
|
|
14951
15126
|
const detail = await detailOf6(pr, number);
|
|
14952
15127
|
const checks = await onProvider(`read the checks of #${number}`, () => pr.pulls.checks(number));
|
|
15128
|
+
recordPlanCi({
|
|
15129
|
+
repoRoot: pr.project.root,
|
|
15130
|
+
planDir: pr.planDir,
|
|
15131
|
+
pullRequest: detail,
|
|
15132
|
+
rows: checks.rows,
|
|
15133
|
+
warn: options.warn,
|
|
15134
|
+
now: () => new Date(options.at)
|
|
15135
|
+
});
|
|
14953
15136
|
const found = await triageCommentOf(options, detail);
|
|
14954
15137
|
const existing = found.comment;
|
|
14955
15138
|
const rerun = readTriageRerun({
|
|
@@ -15018,7 +15201,10 @@ async function runTriage(context, seams) {
|
|
|
15018
15201
|
wantsComment,
|
|
15019
15202
|
maxAttempts,
|
|
15020
15203
|
at: now(),
|
|
15021
|
-
permissions
|
|
15204
|
+
permissions,
|
|
15205
|
+
warn: (message) => {
|
|
15206
|
+
context.output.warn(message);
|
|
15207
|
+
}
|
|
15022
15208
|
});
|
|
15023
15209
|
const reading = await assess();
|
|
15024
15210
|
if (!wantsResolve) {
|
|
@@ -15344,7 +15530,7 @@ function createPrWaitCommand(seams = DEFAULT_WAIT_SEAMS) {
|
|
|
15344
15530
|
var wait_default = createPrWaitCommand();
|
|
15345
15531
|
|
|
15346
15532
|
// src/commands/release/status.ts
|
|
15347
|
-
import { existsSync as
|
|
15533
|
+
import { existsSync as existsSync12, readdirSync as readdirSync6, readFileSync as readFileSync21 } from "fs";
|
|
15348
15534
|
import { join as join28 } from "path";
|
|
15349
15535
|
var RELEASE_STATUS_USAGE = "rafa release status [--plan=<stub>]";
|
|
15350
15536
|
var UNREADABLE3 = "?";
|
|
@@ -15446,7 +15632,7 @@ function untaggedVersions(released, tags) {
|
|
|
15446
15632
|
}
|
|
15447
15633
|
function textOf2(path) {
|
|
15448
15634
|
try {
|
|
15449
|
-
return
|
|
15635
|
+
return readFileSync21(path, "utf8");
|
|
15450
15636
|
} catch {
|
|
15451
15637
|
return null;
|
|
15452
15638
|
}
|
|
@@ -15489,7 +15675,7 @@ function readBranch2(git) {
|
|
|
15489
15675
|
}
|
|
15490
15676
|
function planStubsUnder(root, planDir) {
|
|
15491
15677
|
const resolved = join28(root, planDir);
|
|
15492
|
-
if (!
|
|
15678
|
+
if (!existsSync12(resolved))
|
|
15493
15679
|
return [];
|
|
15494
15680
|
try {
|
|
15495
15681
|
return planStubsFromFileNames(readdirSync6(resolved));
|
|
@@ -15560,10 +15746,10 @@ function levelPhrase(level) {
|
|
|
15560
15746
|
function pendingCell(reading) {
|
|
15561
15747
|
if (reading.stub === null)
|
|
15562
15748
|
return `${NOTHING}: no current plan`;
|
|
15563
|
-
const
|
|
15749
|
+
const count2 = reading.notes.length === 1 ? "1 note" : `${reading.notes.length} notes`;
|
|
15564
15750
|
if (reading.notes.length === 0)
|
|
15565
15751
|
return `${NOTHING} for ${reading.stub}`;
|
|
15566
|
-
return `${
|
|
15752
|
+
return `${count2} for ${reading.stub}, ${levelPhrase(reading.level ?? "none")}`;
|
|
15567
15753
|
}
|
|
15568
15754
|
function pendingLines(reading) {
|
|
15569
15755
|
return renderNoteLines(groupChangeNotes(reading.notes));
|
|
@@ -15690,7 +15876,7 @@ function createReleaseStatusCommand(seams = DEFAULT_RELEASE_SEAMS) {
|
|
|
15690
15876
|
var status_default2 = createReleaseStatusCommand();
|
|
15691
15877
|
|
|
15692
15878
|
// src/commands/release/tag.ts
|
|
15693
|
-
import { readFileSync as
|
|
15879
|
+
import { readFileSync as readFileSync22 } from "fs";
|
|
15694
15880
|
import { join as join29 } from "path";
|
|
15695
15881
|
var RELEASE_TAG_USAGE = "rafa release tag";
|
|
15696
15882
|
var DEFAULT_RELEASE_BRANCH = "main";
|
|
@@ -15710,7 +15896,7 @@ function readBranch3(git) {
|
|
|
15710
15896
|
}
|
|
15711
15897
|
function textOf3(path) {
|
|
15712
15898
|
try {
|
|
15713
|
-
return
|
|
15899
|
+
return readFileSync22(path, "utf8");
|
|
15714
15900
|
} catch {
|
|
15715
15901
|
return null;
|
|
15716
15902
|
}
|
|
@@ -16028,11 +16214,11 @@ import { statSync as statSync14 } from "fs";
|
|
|
16028
16214
|
import { join as join34, resolve as resolve15 } from "path";
|
|
16029
16215
|
|
|
16030
16216
|
// src/backfill/backup.ts
|
|
16031
|
-
import { copyFileSync as copyFileSync4, existsSync as
|
|
16217
|
+
import { copyFileSync as copyFileSync4, existsSync as existsSync13, mkdirSync as mkdirSync8 } from "fs";
|
|
16032
16218
|
import { dirname as dirname6, isAbsolute as isAbsolute8, join as join31, relative as relative8, resolve as resolve13, sep as sep5 } from "path";
|
|
16033
16219
|
|
|
16034
16220
|
// src/backfill/proposal-file.ts
|
|
16035
|
-
import { readdirSync as readdirSync7, readFileSync as
|
|
16221
|
+
import { readdirSync as readdirSync7, readFileSync as readFileSync23 } from "fs";
|
|
16036
16222
|
import { join as join30 } from "path";
|
|
16037
16223
|
var BACKFILL_PATH = join30(".rafa", "backfill");
|
|
16038
16224
|
var PROPOSAL_FILE_PREFIX = "proposals-";
|
|
@@ -16198,7 +16384,7 @@ function readProposalFiles(dir) {
|
|
|
16198
16384
|
return names.filter((name2) => isProposalFileName(name2)).sort((left, right) => left.localeCompare(right)).map((name2) => {
|
|
16199
16385
|
const path = join30(dir, name2);
|
|
16200
16386
|
try {
|
|
16201
|
-
return { path, result: parseProposalFile(
|
|
16387
|
+
return { path, result: parseProposalFile(readFileSync23(path, "utf8")) };
|
|
16202
16388
|
} catch (error) {
|
|
16203
16389
|
return { path, result: unreadable(`the file cannot be read (${error instanceof Error ? error.message : String(error)})`) };
|
|
16204
16390
|
}
|
|
@@ -16227,9 +16413,9 @@ function backupFile(path, options) {
|
|
|
16227
16413
|
const backup = backupPathFor(path, options.root, options.backupDir);
|
|
16228
16414
|
if (backup === null)
|
|
16229
16415
|
return { path, kind: "outside", backup: null };
|
|
16230
|
-
if (!
|
|
16416
|
+
if (!existsSync13(path))
|
|
16231
16417
|
return { path, kind: "missing", backup: null };
|
|
16232
|
-
if (
|
|
16418
|
+
if (existsSync13(backup))
|
|
16233
16419
|
return { path, kind: "kept", backup };
|
|
16234
16420
|
mkdirSync8(dirname6(backup), { recursive: true });
|
|
16235
16421
|
copyFileSync4(path, backup);
|
|
@@ -16254,7 +16440,7 @@ function countBackups(results) {
|
|
|
16254
16440
|
}
|
|
16255
16441
|
|
|
16256
16442
|
// src/backfill/derive.ts
|
|
16257
|
-
import { readFileSync as
|
|
16443
|
+
import { readFileSync as readFileSync24, writeFileSync as writeFileSync7 } from "fs";
|
|
16258
16444
|
import { basename as basename8 } from "path";
|
|
16259
16445
|
var DERIVED_FIELDS = ["stack", "paths", "when_to_use"];
|
|
16260
16446
|
function renderWhenToUse(trigger, prevents) {
|
|
@@ -16380,7 +16566,7 @@ function planFile(entry, options) {
|
|
|
16380
16566
|
}
|
|
16381
16567
|
let original;
|
|
16382
16568
|
try {
|
|
16383
|
-
original =
|
|
16569
|
+
original = readFileSync24(entry.path, "utf8");
|
|
16384
16570
|
} catch (error) {
|
|
16385
16571
|
return inert(entry, "skipped", `the file cannot be read (${error instanceof Error ? error.message : String(error)})`);
|
|
16386
16572
|
}
|
|
@@ -16424,7 +16610,7 @@ function planDerivation(root, options) {
|
|
|
16424
16610
|
function applyFile(action, options) {
|
|
16425
16611
|
if (action.text === null || action.original === null)
|
|
16426
16612
|
return action;
|
|
16427
|
-
const current =
|
|
16613
|
+
const current = readFileSync24(action.path, "utf8");
|
|
16428
16614
|
if (current !== action.original) {
|
|
16429
16615
|
return {
|
|
16430
16616
|
...action,
|
|
@@ -16455,7 +16641,7 @@ function applyDerivation(plan2, options) {
|
|
|
16455
16641
|
}
|
|
16456
16642
|
|
|
16457
16643
|
// src/backfill/proposal-batch.ts
|
|
16458
|
-
import { readFileSync as
|
|
16644
|
+
import { readFileSync as readFileSync25 } from "fs";
|
|
16459
16645
|
import { relative as relative9 } from "path";
|
|
16460
16646
|
|
|
16461
16647
|
// src/demote/report.ts
|
|
@@ -16754,7 +16940,7 @@ function readCandidate(root, entry) {
|
|
|
16754
16940
|
return null;
|
|
16755
16941
|
let text;
|
|
16756
16942
|
try {
|
|
16757
|
-
text =
|
|
16943
|
+
text = readFileSync25(entry.path, "utf8");
|
|
16758
16944
|
} catch {
|
|
16759
16945
|
return null;
|
|
16760
16946
|
}
|
|
@@ -16860,7 +17046,7 @@ function parseSessionAnswer(stdout) {
|
|
|
16860
17046
|
}
|
|
16861
17047
|
|
|
16862
17048
|
// src/backfill/propose.ts
|
|
16863
|
-
import { mkdirSync as mkdirSync9, readFileSync as
|
|
17049
|
+
import { mkdirSync as mkdirSync9, readFileSync as readFileSync26, writeFileSync as writeFileSync8 } from "fs";
|
|
16864
17050
|
import { join as join32, resolve as resolve14 } from "path";
|
|
16865
17051
|
var PROPOSAL_ACTION_KINDS = [
|
|
16866
17052
|
"applied",
|
|
@@ -17019,7 +17205,7 @@ function applyRow(root, row2, options) {
|
|
|
17019
17205
|
}
|
|
17020
17206
|
let original;
|
|
17021
17207
|
try {
|
|
17022
|
-
original =
|
|
17208
|
+
original = readFileSync26(path, "utf8");
|
|
17023
17209
|
} catch {
|
|
17024
17210
|
return inert2(path, row2, "refused", "the file the row names is gone");
|
|
17025
17211
|
}
|
|
@@ -17058,7 +17244,7 @@ function applyProposals(files, root, options) {
|
|
|
17058
17244
|
}
|
|
17059
17245
|
|
|
17060
17246
|
// src/demote/select.ts
|
|
17061
|
-
import { readdirSync as readdirSync8, readFileSync as
|
|
17247
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync27, realpathSync as realpathSync6, statSync as statSync13 } from "fs";
|
|
17062
17248
|
import { basename as basename9, dirname as dirname7, join as join33 } from "path";
|
|
17063
17249
|
var SKILLS_DIRECTORY = "skills";
|
|
17064
17250
|
var CLAUDE_DIRECTORY = ".claude";
|
|
@@ -17120,7 +17306,7 @@ function readSelected(absolute, path, entries) {
|
|
|
17120
17306
|
let text;
|
|
17121
17307
|
let mtime;
|
|
17122
17308
|
try {
|
|
17123
|
-
text =
|
|
17309
|
+
text = readFileSync27(absolute, "utf8");
|
|
17124
17310
|
mtime = statSync13(absolute).mtime.toISOString();
|
|
17125
17311
|
} catch {
|
|
17126
17312
|
return null;
|
|
@@ -17505,11 +17691,11 @@ function createSkillCheckCommand(seams = DEFAULT_CHECK_SEAMS) {
|
|
|
17505
17691
|
var check_default3 = createSkillCheckCommand();
|
|
17506
17692
|
|
|
17507
17693
|
// src/commands/skill/demote.ts
|
|
17508
|
-
import { existsSync as
|
|
17694
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync11, readFileSync as readFileSync29, statSync as statSync16, writeFileSync as writeFileSync10 } from "fs";
|
|
17509
17695
|
import { dirname as dirname9, resolve as resolve16 } from "path";
|
|
17510
17696
|
|
|
17511
17697
|
// src/demote/apply.ts
|
|
17512
|
-
import { copyFileSync as copyFileSync5, existsSync as
|
|
17698
|
+
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
17699
|
import { tmpdir as tmpdir2 } from "os";
|
|
17514
17700
|
import { dirname as dirname8, join as join35 } from "path";
|
|
17515
17701
|
var DEMOTION_ACTION_KINDS = [
|
|
@@ -17551,7 +17737,7 @@ function takenInstinctIds(dir) {
|
|
|
17551
17737
|
}
|
|
17552
17738
|
function readText4(path) {
|
|
17553
17739
|
try {
|
|
17554
|
-
return statSync15(path).isFile() ?
|
|
17740
|
+
return statSync15(path).isFile() ? readFileSync28(path, "utf8") : null;
|
|
17555
17741
|
} catch {
|
|
17556
17742
|
return null;
|
|
17557
17743
|
}
|
|
@@ -17579,7 +17765,7 @@ function planKept(scope, row2, file) {
|
|
|
17579
17765
|
return inert3(row2.path, "procedure", "kept", "procedure-shaped: left where it is, for the backfill");
|
|
17580
17766
|
}
|
|
17581
17767
|
const to = promotedPath(scope, row2.path);
|
|
17582
|
-
if (
|
|
17768
|
+
if (existsSync14(to) || existsSync14(dirname8(to))) {
|
|
17583
17769
|
return inert3(row2.path, "procedure", "refused", `kept as a skill, but ${to} is already there`);
|
|
17584
17770
|
}
|
|
17585
17771
|
return {
|
|
@@ -17616,9 +17802,9 @@ function planDemoted(scope, row2, file, context) {
|
|
|
17616
17802
|
}
|
|
17617
17803
|
const destination = join35(scope.instinctsDir, `${id}${MARKDOWN_EXTENSION}`);
|
|
17618
17804
|
const kept = demotedPath(scope, row2.path);
|
|
17619
|
-
if (
|
|
17805
|
+
if (existsSync14(destination))
|
|
17620
17806
|
return inert3(row2.path, "observation", "refused", `${destination} is already there`);
|
|
17621
|
-
if (
|
|
17807
|
+
if (existsSync14(kept))
|
|
17622
17808
|
return inert3(row2.path, "observation", "refused", `${kept} is already there`);
|
|
17623
17809
|
context.taken.push(id);
|
|
17624
17810
|
return {
|
|
@@ -17667,13 +17853,13 @@ function planDemotion(report3, scope, seams = DEFAULT_APPLY_SEAMS) {
|
|
|
17667
17853
|
const actions = report3.rows.map((row2) => planRow(scope, row2, { temp, taken, seams }));
|
|
17668
17854
|
return { scope, actions, counts: countActions(actions) };
|
|
17669
17855
|
} finally {
|
|
17670
|
-
|
|
17856
|
+
rmSync4(temp, { recursive: true, force: true });
|
|
17671
17857
|
}
|
|
17672
17858
|
}
|
|
17673
17859
|
function moveFile(move3) {
|
|
17674
17860
|
mkdirSync10(dirname8(move3.to), { recursive: true });
|
|
17675
17861
|
try {
|
|
17676
|
-
|
|
17862
|
+
renameSync3(move3.from, move3.to);
|
|
17677
17863
|
} catch {
|
|
17678
17864
|
copyFileSync5(move3.from, move3.to);
|
|
17679
17865
|
unlinkSync(move3.from);
|
|
@@ -17780,9 +17966,9 @@ function verdictLine(report3) {
|
|
|
17780
17966
|
return `${String(report3.rows.length)} file(s): ${parts.join(", ")}`;
|
|
17781
17967
|
}
|
|
17782
17968
|
function previousReport(path, context) {
|
|
17783
|
-
if (!
|
|
17969
|
+
if (!existsSync15(path))
|
|
17784
17970
|
return null;
|
|
17785
|
-
const parsed = parseDemotionReport(
|
|
17971
|
+
const parsed = parseDemotionReport(readFileSync29(path, "utf8"));
|
|
17786
17972
|
if (parsed.report !== null)
|
|
17787
17973
|
return parsed.report;
|
|
17788
17974
|
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 +18001,10 @@ function runWrite(context, scope) {
|
|
|
17815
18001
|
context.output.info(line);
|
|
17816
18002
|
}
|
|
17817
18003
|
function reviewedReport(scope) {
|
|
17818
|
-
if (!
|
|
18004
|
+
if (!existsSync15(scope.reportPath)) {
|
|
17819
18005
|
throw new CommandExit(1, `\u274C No report at ${scope.reportPath}; run "rafa skill demote ${scope.dir}" first, then review it`);
|
|
17820
18006
|
}
|
|
17821
|
-
const parsed = parseDemotionReport(
|
|
18007
|
+
const parsed = parseDemotionReport(readFileSync29(scope.reportPath, "utf8"));
|
|
17822
18008
|
if (parsed.report === null) {
|
|
17823
18009
|
const lines2 = parsed.issues.map((issue2) => ` line ${String(issue2.line)} ${issue2.code}: ${issue2.message}`);
|
|
17824
18010
|
throw new CommandExit(1, [`\u274C ${scope.reportPath} does not parse:`, ...lines2].join(`
|
|
@@ -17924,7 +18110,7 @@ var demote_default = createSkillDemoteCommand();
|
|
|
17924
18110
|
|
|
17925
18111
|
// src/commands/skill/show.ts
|
|
17926
18112
|
var DEFAULT_SKILL_SHOW_SEAMS = DEFAULT_SKILL_LIST_SEAMS;
|
|
17927
|
-
var
|
|
18113
|
+
var COMMAND_NAME6 = "rafa skill show";
|
|
17928
18114
|
var USAGE32 = "rafa skill show <name> [--full]";
|
|
17929
18115
|
function unknownSkillMessage(name2, inventory) {
|
|
17930
18116
|
const agent = findShown(inventory.records, "agent", name2);
|
|
@@ -17952,7 +18138,7 @@ async function runShow3(context, seams) {
|
|
|
17952
18138
|
const full = readSwitch("full", context.flags["full"], `Type the name ahead of it: ${USAGE32}`);
|
|
17953
18139
|
const name2 = expectOneArgument(context.args, USAGE32);
|
|
17954
18140
|
const project = projectOf14(context);
|
|
17955
|
-
const { inventory, settingSources } = await projectInventory(project, context, seams,
|
|
18141
|
+
const { inventory, settingSources } = await projectInventory(project, context, seams, COMMAND_NAME6);
|
|
17956
18142
|
const warnings = warningLines(inventory);
|
|
17957
18143
|
for (const warning of warnings)
|
|
17958
18144
|
context.output.warn(warning);
|
|
@@ -18030,8 +18216,8 @@ var VERDICT_WORDS = Object.freeze({
|
|
|
18030
18216
|
pending: "checks pending",
|
|
18031
18217
|
none: "no checks"
|
|
18032
18218
|
});
|
|
18033
|
-
function counted3(
|
|
18034
|
-
return `${String(
|
|
18219
|
+
function counted3(count2, noun, plural5 = `${noun}s`) {
|
|
18220
|
+
return `${String(count2)} ${count2 === 1 ? noun : plural5}`;
|
|
18035
18221
|
}
|
|
18036
18222
|
function info(text) {
|
|
18037
18223
|
return { level: "info", text };
|
|
@@ -18279,7 +18465,7 @@ async function readStatusSections(input, seams = {}) {
|
|
|
18279
18465
|
}
|
|
18280
18466
|
|
|
18281
18467
|
// src/commands/status.ts
|
|
18282
|
-
var
|
|
18468
|
+
var COMMAND_NAME7 = "rafa status";
|
|
18283
18469
|
var STATUS_USAGE = "rafa status";
|
|
18284
18470
|
var STATUS_ARGUMENT_EXIT = 2;
|
|
18285
18471
|
var DEFAULT_STATUS_SEAMS = Object.freeze({});
|
|
@@ -18291,13 +18477,13 @@ function projectOf15(context) {
|
|
|
18291
18477
|
function expectNoWord(args) {
|
|
18292
18478
|
if (args.length === 0)
|
|
18293
18479
|
return;
|
|
18294
|
-
throw new CommandExit(STATUS_ARGUMENT_EXIT, `\u274C ${
|
|
18480
|
+
throw new CommandExit(STATUS_ARGUMENT_EXIT, `\u274C ${COMMAND_NAME7}: expected no argument, got ${String(args.length)}: ${args.join(" ")}
|
|
18295
18481
|
Usage: ${STATUS_USAGE}`);
|
|
18296
18482
|
}
|
|
18297
18483
|
async function runStatus2(context, seams) {
|
|
18298
18484
|
expectNoWord(context.args);
|
|
18299
18485
|
const project = projectOf15(context);
|
|
18300
|
-
const config = resolveProjectConfig(project,
|
|
18486
|
+
const config = resolveProjectConfig(project, COMMAND_NAME7, (message) => {
|
|
18301
18487
|
context.output.warn(message);
|
|
18302
18488
|
});
|
|
18303
18489
|
const read3 = seams.read ?? ((input) => readStatusSections(input));
|
|
@@ -18363,7 +18549,7 @@ var CORE_SUBJECTS = Object.freeze([
|
|
|
18363
18549
|
{ name: "loop", summary: "start a plan; stop, pause, resume, show and list its sessions" },
|
|
18364
18550
|
{ name: "issue", summary: "the tracker: list, show, create, comment on and move issues; mark one ready, unblock it and check its references" },
|
|
18365
18551
|
{ 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" },
|
|
18552
|
+
{ name: "effort", summary: "collect session and commit rows; report per plan; repair a store a newer rafa migrated" },
|
|
18367
18553
|
{ name: "module", summary: "list the configured modules; run an action a module provides" },
|
|
18368
18554
|
{ name: "agent", summary: "copy an agent definition into the project; list what a session sees" },
|
|
18369
18555
|
{ name: "skill", summary: "check a skills directory; list each tier; demote and backfill it" },
|
|
@@ -18400,6 +18586,7 @@ var CORE_COMMANDS = Object.freeze([
|
|
|
18400
18586
|
triage_default,
|
|
18401
18587
|
collect_default,
|
|
18402
18588
|
report_default,
|
|
18589
|
+
fix_schema_default,
|
|
18403
18590
|
list_default7,
|
|
18404
18591
|
exec_default,
|
|
18405
18592
|
vendor_default,
|