@open-tomato/rafa 0.19.0 → 0.20.0

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