@open-tomato/rafa 0.18.0 → 0.19.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 +13 -10
- package/dist/PROMPT.md +2 -1
- package/dist/bundled/skills/dev-planner/SKILL.md +2 -0
- package/dist/cli.js +2212 -950
- package/dist/{describe-vq037dyt.js → describe-cenk70n5.js} +4 -3
- package/dist/effort/store/index.js +6 -4
- package/dist/{index-0pdsq2hy.js → index-09p41s0n.js} +11 -224
- package/dist/{index-kvnggvyk.js → index-c5cecsga.js} +2 -2
- package/dist/{index-6vkd153j.js → index-ca0fccvr.js} +1220 -1104
- package/dist/{index-944pncd8.js → index-cedghpva.js} +10 -2
- package/dist/index-d6d0942q.js +218 -0
- package/dist/{index-at9f1z2z.js → index-gb51x34c.js} +1007 -51
- package/dist/{index-cvpdvmtg.js → index-mh5hyw8g.js} +602 -665
- package/dist/{index-jva32qe6.js → index-pqrpcfaz.js} +246 -2
- package/dist/{index-ddf85qac.js → index-vg7ycs94.js} +1 -1
- package/dist/index-wp8c28fd.js +18 -0
- package/dist/index.js +13 -11
- package/dist/learning/index.js +25 -0
- package/dist/plan/index.js +8 -7
- package/package.json +4 -3
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
|
-
ACTION_HEADING,
|
|
4
3
|
AGENT_DEFINITION_DIR,
|
|
5
4
|
BRANCH_PREFIX,
|
|
6
|
-
CAUSE_HEADING,
|
|
7
5
|
CI_POLL_INTERVAL_MS,
|
|
8
6
|
DEFAULT_BASE_BRANCH,
|
|
9
7
|
DEFAULT_CI_ATTEMPTS,
|
|
10
8
|
DEFAULT_CI_TIMEOUT_MIN,
|
|
11
9
|
DEFAULT_ISSUE_SEAMS,
|
|
12
10
|
DEFAULT_PLAN_FILE,
|
|
11
|
+
DEMOTION_VERDICTS,
|
|
13
12
|
DESCRIPTION_LIMIT,
|
|
14
13
|
DISK_FILE_SYSTEM,
|
|
15
14
|
HINT_FLAG_SPEC,
|
|
16
15
|
ID_PREFIX,
|
|
16
|
+
LEARNED_DIRECTORY,
|
|
17
17
|
LISTING_LIMIT,
|
|
18
|
-
MARKDOWN_EXTENSION,
|
|
19
18
|
MECHANICAL_CONFLICT_SENTENCE,
|
|
20
19
|
NEXT_COMMAND_ACTIONS,
|
|
20
|
+
ORIGIN_FIELD,
|
|
21
21
|
PREVIOUS_COPY_WARN_ABOVE,
|
|
22
22
|
PROVENANCE_FIELD,
|
|
23
23
|
REMOTE,
|
|
@@ -32,8 +32,7 @@ import {
|
|
|
32
32
|
SCOPE_DIR,
|
|
33
33
|
SERVE_CLI_VERSION,
|
|
34
34
|
SESSION_ID_FLAG,
|
|
35
|
-
SKILL_FILE,
|
|
36
|
-
SKILL_FILE1 as SKILL_FILE2,
|
|
35
|
+
SKILL_FILE as SKILL_FILE2,
|
|
37
36
|
SKILL_SIGNALS,
|
|
38
37
|
SPEC_BLOCKED_LABEL,
|
|
39
38
|
SPEC_EXTENSION,
|
|
@@ -46,7 +45,7 @@ import {
|
|
|
46
45
|
UNREADABLE,
|
|
47
46
|
VENDOR_COMMAND,
|
|
48
47
|
VERSION_SHAPE,
|
|
49
|
-
|
|
48
|
+
WHEN_TO_USE_HEADING,
|
|
50
49
|
actionInvocation,
|
|
51
50
|
actionOutput,
|
|
52
51
|
announceRiskTotal,
|
|
@@ -54,6 +53,7 @@ import {
|
|
|
54
53
|
blockedFaultMessage,
|
|
55
54
|
blockedLineSentence,
|
|
56
55
|
boardId,
|
|
56
|
+
bodySections,
|
|
57
57
|
branchClaims,
|
|
58
58
|
bundledAgentsDirectory,
|
|
59
59
|
byName,
|
|
@@ -62,13 +62,14 @@ import {
|
|
|
62
62
|
checkReferences,
|
|
63
63
|
checkbox,
|
|
64
64
|
checkboxAt,
|
|
65
|
+
classifySkill,
|
|
65
66
|
cleanUpSteps,
|
|
66
67
|
closedIssuesIn,
|
|
67
68
|
collect,
|
|
68
|
-
collectReferences,
|
|
69
69
|
collectSessionRow,
|
|
70
70
|
commandLine,
|
|
71
71
|
commandWords,
|
|
72
|
+
convertToInstinct,
|
|
72
73
|
coreRoster,
|
|
73
74
|
countCharacters,
|
|
74
75
|
countPreviousCopies,
|
|
@@ -95,6 +96,7 @@ import {
|
|
|
95
96
|
failingRows,
|
|
96
97
|
findReadinessGaps,
|
|
97
98
|
fingerprintText,
|
|
99
|
+
firstSentence,
|
|
98
100
|
formatCounts,
|
|
99
101
|
formatRows,
|
|
100
102
|
ghHostOf,
|
|
@@ -104,7 +106,6 @@ import {
|
|
|
104
106
|
ghPreflightItems,
|
|
105
107
|
ghPullRequestsIn,
|
|
106
108
|
ghUnauthenticatedMessage,
|
|
107
|
-
gitRemoteUrl,
|
|
108
109
|
gitSaid,
|
|
109
110
|
groupChangeNotes,
|
|
110
111
|
hasDiverged,
|
|
@@ -125,16 +126,13 @@ import {
|
|
|
125
126
|
list_default,
|
|
126
127
|
loadConfig,
|
|
127
128
|
memoiseVerifier,
|
|
128
|
-
mergeFrontmatter,
|
|
129
129
|
missingPlanAgents,
|
|
130
130
|
name,
|
|
131
131
|
nextQuestion,
|
|
132
|
-
normalizeRemote,
|
|
133
132
|
notesFileName,
|
|
134
133
|
onTracker,
|
|
135
134
|
openNextSources,
|
|
136
135
|
parseBaseStanding,
|
|
137
|
-
parseInstinct,
|
|
138
136
|
parseRoadmapBody,
|
|
139
137
|
parseSemanticVersion,
|
|
140
138
|
parseWorkingTree,
|
|
@@ -158,8 +156,6 @@ import {
|
|
|
158
156
|
readChoice,
|
|
159
157
|
readChoiceFlag,
|
|
160
158
|
readCopyRefs,
|
|
161
|
-
readFrontmatter,
|
|
162
|
-
readFrontmatterDocument,
|
|
163
159
|
readInventoryFrontmatter,
|
|
164
160
|
readManifestVersion,
|
|
165
161
|
readMergeRefusal,
|
|
@@ -182,7 +178,6 @@ import {
|
|
|
182
178
|
refusal,
|
|
183
179
|
refuseMisplacedRuntime,
|
|
184
180
|
remainingFrom,
|
|
185
|
-
renderFrontmatter,
|
|
186
181
|
renderNoteLines,
|
|
187
182
|
renderRiskText,
|
|
188
183
|
report,
|
|
@@ -204,7 +199,6 @@ import {
|
|
|
204
199
|
runAction,
|
|
205
200
|
runsDir,
|
|
206
201
|
scanClaimBranches,
|
|
207
|
-
scanLayout,
|
|
208
202
|
scopeAt,
|
|
209
203
|
selfAndAncestors,
|
|
210
204
|
serveVerdict,
|
|
@@ -230,10 +224,8 @@ import {
|
|
|
230
224
|
version,
|
|
231
225
|
versionLine,
|
|
232
226
|
waitForChecks,
|
|
233
|
-
writeFrontmatter,
|
|
234
|
-
writeInstinct,
|
|
235
227
|
writeSession
|
|
236
|
-
} from "./index-
|
|
228
|
+
} from "./index-ca0fccvr.js";
|
|
237
229
|
import {
|
|
238
230
|
PROBE_TIMEOUT_MS,
|
|
239
231
|
findNextTask,
|
|
@@ -247,8 +239,10 @@ import {
|
|
|
247
239
|
runPreflight,
|
|
248
240
|
splitBlockerComment,
|
|
249
241
|
trackerPathFor
|
|
250
|
-
} from "./index-
|
|
242
|
+
} from "./index-09p41s0n.js";
|
|
251
243
|
import {
|
|
244
|
+
ACTION_HEADING,
|
|
245
|
+
CAUSE_HEADING,
|
|
252
246
|
CLAUDE_BIN,
|
|
253
247
|
CORE_ADAPTER_REGISTRY,
|
|
254
248
|
EFFORT_STORE_DIR,
|
|
@@ -256,17 +250,32 @@ import {
|
|
|
256
250
|
ISSUE_PRIORITIES,
|
|
257
251
|
ISSUE_STATES,
|
|
258
252
|
ISSUE_TYPES,
|
|
253
|
+
MARKDOWN_EXTENSION,
|
|
254
|
+
SKILL_FILE,
|
|
255
|
+
allRecords,
|
|
259
256
|
claudeArgs,
|
|
260
257
|
createGhRunner,
|
|
261
258
|
effortStorePath,
|
|
259
|
+
findRecords,
|
|
260
|
+
gitRemoteUrl,
|
|
261
|
+
instinctProject,
|
|
262
|
+
mergeFrontmatter,
|
|
262
263
|
moduleOfLabels,
|
|
264
|
+
normalizeRemote,
|
|
265
|
+
readFrontmatter,
|
|
266
|
+
readFrontmatterDocument,
|
|
267
|
+
readScopes,
|
|
268
|
+
renderFrontmatter,
|
|
263
269
|
runClaudeCaptured,
|
|
270
|
+
scanLayout,
|
|
264
271
|
selectEffortStore,
|
|
265
272
|
sessionSpawnEnv,
|
|
266
273
|
spawnClaudeCaptured,
|
|
267
274
|
sqliteStorePath,
|
|
268
|
-
|
|
269
|
-
|
|
275
|
+
toHeldRecords,
|
|
276
|
+
typeOfLabels,
|
|
277
|
+
writeFrontmatter
|
|
278
|
+
} from "./index-gb51x34c.js";
|
|
270
279
|
import {
|
|
271
280
|
CONFIG_DEFAULTS,
|
|
272
281
|
CONFIG_FILE,
|
|
@@ -280,15 +289,18 @@ import {
|
|
|
280
289
|
readItemBytes,
|
|
281
290
|
readRafaBlocks,
|
|
282
291
|
resolveTiers
|
|
283
|
-
} from "./index-
|
|
292
|
+
} from "./index-pqrpcfaz.js";
|
|
293
|
+
import {
|
|
294
|
+
promotable
|
|
295
|
+
} from "./index-d6d0942q.js";
|
|
284
296
|
import {
|
|
285
297
|
createCommandRegistry,
|
|
286
298
|
describeRegistry,
|
|
287
299
|
mountKey
|
|
288
|
-
} from "./index-
|
|
300
|
+
} from "./index-c5cecsga.js";
|
|
289
301
|
import {
|
|
290
302
|
CommandExit
|
|
291
|
-
} from "./index-
|
|
303
|
+
} from "./index-vg7ycs94.js";
|
|
292
304
|
import {
|
|
293
305
|
MERGE_METHODS,
|
|
294
306
|
RELEASE_AUTO,
|
|
@@ -299,10 +311,11 @@ import {
|
|
|
299
311
|
isMergeMethod,
|
|
300
312
|
isSkillTier,
|
|
301
313
|
messageOf,
|
|
302
|
-
parseBudgetUsd
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
314
|
+
parseBudgetUsd
|
|
315
|
+
} from "./index-cedghpva.js";
|
|
316
|
+
import {
|
|
317
|
+
triggerKey
|
|
318
|
+
} from "./index-wp8c28fd.js";
|
|
306
319
|
|
|
307
320
|
// src/inventory/disabled.ts
|
|
308
321
|
import { readFileSync } from "fs";
|
|
@@ -4956,7 +4969,7 @@ function readScope2(scope, path, loaded) {
|
|
|
4956
4969
|
}
|
|
4957
4970
|
return { read: { scope, path, loaded, entries }, warnings };
|
|
4958
4971
|
}
|
|
4959
|
-
function
|
|
4972
|
+
function readScopes2(seams) {
|
|
4960
4973
|
const read = OVERRIDE_SCOPES.flatMap((scope) => {
|
|
4961
4974
|
const path = overrideSettingsPath(scope, { home: seams.home, projectRoot: seams.projectRoot });
|
|
4962
4975
|
return path === null ? [] : [readScope2(scope, path, seams.settingSources.includes(scope))];
|
|
@@ -5009,7 +5022,7 @@ function pathDifference(shell, session, layer) {
|
|
|
5009
5022
|
return Object.freeze({ layer, added: Object.freeze(added), removed: Object.freeze(removed), reordered });
|
|
5010
5023
|
}
|
|
5011
5024
|
function readSessionEnv(seams) {
|
|
5012
|
-
const { scopes, warnings } =
|
|
5025
|
+
const { scopes, warnings } = readScopes2(seams);
|
|
5013
5026
|
const { env, layers } = overlay(sessionSpawnEnv(seams.env), seams.env, scopes);
|
|
5014
5027
|
return Object.freeze({
|
|
5015
5028
|
env: Object.freeze(env),
|
|
@@ -7799,6 +7812,11 @@ var CONFIG_SETTINGS_LINES = Object.freeze([
|
|
|
7799
7812
|
`# fallback: [${CONFIG_DEFAULTS.trackerFallback.join(", ")}]`,
|
|
7800
7813
|
"# learning:",
|
|
7801
7814
|
`# adapter: ${CONFIG_DEFAULTS.learningAdapter}`,
|
|
7815
|
+
"# bless:",
|
|
7816
|
+
`# minConfidence: ${String(CONFIG_DEFAULTS.learningBlessMinConfidence)} # 0.3..0.9, the least confidence of a lesson tasks may use`,
|
|
7817
|
+
"# promote:",
|
|
7818
|
+
`# after: ${String(CONFIG_DEFAULTS.learningPromoteAfter)} # distinct sources a lesson needs before the wrap-up promotes it`,
|
|
7819
|
+
`# minConfidence: ${String(CONFIG_DEFAULTS.learningPromoteMinConfidence)} # 0.3..0.9, the least confidence of a lesson to promote`,
|
|
7802
7820
|
"# output:",
|
|
7803
7821
|
`# mode: ${CONFIG_DEFAULTS.outputMode} # text | json`,
|
|
7804
7822
|
"# prerequisites:",
|
|
@@ -8558,72 +8576,196 @@ function createInstinctCheckCommand(seams = DEFAULT_CHECK_SEAMS) {
|
|
|
8558
8576
|
}
|
|
8559
8577
|
var check_default = createInstinctCheckCommand();
|
|
8560
8578
|
|
|
8561
|
-
// src/commands/instinct/
|
|
8562
|
-
|
|
8563
|
-
|
|
8564
|
-
function
|
|
8565
|
-
return
|
|
8566
|
-
}
|
|
8567
|
-
|
|
8568
|
-
|
|
8579
|
+
// src/commands/instinct/flag.ts
|
|
8580
|
+
var NAME = "rafa instinct flag";
|
|
8581
|
+
var USAGE6 = "rafa instinct flag <id> <reason>";
|
|
8582
|
+
function refusedFlagMessage(id, kind, reason) {
|
|
8583
|
+
return [
|
|
8584
|
+
`\u274C ${NAME}: the \`${kind}\` learning adapter did not flag "${id}": ${reason}`,
|
|
8585
|
+
"Run `rafa instinct list` to see the ids the project holds."
|
|
8586
|
+
].join(`
|
|
8587
|
+
`);
|
|
8569
8588
|
}
|
|
8570
|
-
function
|
|
8571
|
-
return {
|
|
8589
|
+
function blankReasonMessage(id) {
|
|
8590
|
+
return `\u274C ${NAME}: the reason to flag "${id}" is blank; say why the lesson is wrong.
|
|
8591
|
+
Usage: ${USAGE6}`;
|
|
8572
8592
|
}
|
|
8573
|
-
function
|
|
8574
|
-
let text;
|
|
8593
|
+
function makeAdapter(registry, kind, context) {
|
|
8575
8594
|
try {
|
|
8576
|
-
|
|
8595
|
+
return registry.resolve("learning", kind).create({
|
|
8596
|
+
repoRoot: context.repoRoot,
|
|
8597
|
+
home: context.home,
|
|
8598
|
+
learningBlessMinConfidence: context.minConfidence
|
|
8599
|
+
});
|
|
8577
8600
|
} catch (error) {
|
|
8578
|
-
|
|
8579
|
-
return { scope, path, id, instinct: null, issues: [unreadableIssue(message)] };
|
|
8601
|
+
throw new CommandExit(1, `\u274C ${NAME}: the \`${kind}\` learning adapter cannot be made: ${messageOf(error)}`);
|
|
8580
8602
|
}
|
|
8581
|
-
const parsed = parseInstinct(text);
|
|
8582
|
-
return { scope, path, id, instinct: parsed.instinct, issues: parsed.issues };
|
|
8583
8603
|
}
|
|
8584
|
-
function
|
|
8604
|
+
async function flagInstinct(context, seams) {
|
|
8605
|
+
const [id, reason] = expectTwoArguments(context.args, USAGE6);
|
|
8606
|
+
if (reason.trim() === "")
|
|
8607
|
+
throw new CommandExit(1, blankReasonMessage(id));
|
|
8608
|
+
const project = requireProject(context, NAME);
|
|
8609
|
+
const config = resolveProjectConfig(project, NAME, (message) => {
|
|
8610
|
+
context.output.warn(message);
|
|
8611
|
+
});
|
|
8612
|
+
const kind = config.learningAdapter;
|
|
8613
|
+
const adapter = makeAdapter(seams.registry ?? CORE_ADAPTER_REGISTRY, kind, {
|
|
8614
|
+
repoRoot: project.root,
|
|
8615
|
+
home: project.home,
|
|
8616
|
+
minConfidence: config.learningBlessMinConfidence
|
|
8617
|
+
});
|
|
8585
8618
|
try {
|
|
8586
|
-
|
|
8587
|
-
} catch {
|
|
8588
|
-
|
|
8619
|
+
await adapter.flag(id, reason);
|
|
8620
|
+
} catch (error) {
|
|
8621
|
+
throw new CommandExit(1, refusedFlagMessage(id, kind, messageOf(error)));
|
|
8589
8622
|
}
|
|
8623
|
+
return { id, reason, adapter: kind };
|
|
8590
8624
|
}
|
|
8591
|
-
function
|
|
8592
|
-
|
|
8593
|
-
|
|
8594
|
-
|
|
8595
|
-
|
|
8596
|
-
|
|
8597
|
-
|
|
8598
|
-
|
|
8599
|
-
|
|
8600
|
-
|
|
8601
|
-
|
|
8625
|
+
function createInstinctFlagCommand(seams = {}) {
|
|
8626
|
+
const command = {
|
|
8627
|
+
name: "instinct flag",
|
|
8628
|
+
subject: "instinct",
|
|
8629
|
+
action: "flag",
|
|
8630
|
+
summary: "flag one held lesson as wrong, so no later bundle blesses it",
|
|
8631
|
+
description: "Flags one lesson the project holds as wrong, through the learning adapter" + " `learning.adapter` names in `.rafa/config.yaml`. A flagged id is left out of every bundle the" + " loop pulls afterwards, whatever a later merge writes under it; under the `local` adapter the" + " flag is one line appended to `.rafa/instincts/flags.ndjson` and no record file changes. An id" + " no held record carries is refused with exit code 1 in the adapter's words, a user-scope id" + " included, as is a blank reason. With `--output=json` the id, the reason and the adapter kind" + " are the data of the terminal result event.",
|
|
8632
|
+
args: [
|
|
8633
|
+
{
|
|
8634
|
+
name: "id",
|
|
8635
|
+
description: "The id of a lesson the project holds, as `rafa instinct list` prints it.",
|
|
8636
|
+
type: "string",
|
|
8637
|
+
required: true
|
|
8638
|
+
},
|
|
8639
|
+
{
|
|
8640
|
+
name: "reason",
|
|
8641
|
+
description: "Why the lesson is wrong, quoted as one word; stored beside the flag.",
|
|
8642
|
+
type: "string",
|
|
8643
|
+
required: true
|
|
8644
|
+
}
|
|
8645
|
+
],
|
|
8646
|
+
flags: [],
|
|
8647
|
+
examples: [
|
|
8648
|
+
{
|
|
8649
|
+
cmd: 'rafa instinct flag worktree-missing-node-modules "bun install runs on fork since 0.9"',
|
|
8650
|
+
note: "Keeps that lesson out of every bundle the loop pulls from now on."
|
|
8651
|
+
},
|
|
8652
|
+
{
|
|
8653
|
+
cmd: 'rafa instinct flag worktree-missing-node-modules "stale" --output=json',
|
|
8654
|
+
note: "Gives the id, the reason and the adapter kind as the data of the terminal result event."
|
|
8655
|
+
}
|
|
8656
|
+
],
|
|
8657
|
+
outputs: ["text", "json"],
|
|
8658
|
+
run: async (context) => {
|
|
8659
|
+
const result = await flagInstinct(context, seams);
|
|
8660
|
+
if (context.outputMode === "json") {
|
|
8661
|
+
context.output.result(result);
|
|
8662
|
+
return;
|
|
8663
|
+
}
|
|
8664
|
+
context.output.info(`\uD83D\uDEA9 Flagged ${result.id}: ${result.reason}`);
|
|
8665
|
+
context.output.info(` The \`${result.adapter}\` learning adapter leaves it out of every later bundle.`);
|
|
8666
|
+
}
|
|
8602
8667
|
};
|
|
8668
|
+
return Object.freeze(command);
|
|
8603
8669
|
}
|
|
8604
|
-
|
|
8605
|
-
|
|
8670
|
+
var flag_default = createInstinctFlagCommand();
|
|
8671
|
+
|
|
8672
|
+
// src/commands/instinct/promote.ts
|
|
8673
|
+
var NAME2 = "rafa instinct promote";
|
|
8674
|
+
var USAGE7 = "rafa instinct promote";
|
|
8675
|
+
var CONFIDENCE_DIGITS = 2;
|
|
8676
|
+
function refusedPullMessage(kind, reason, name2 = NAME2) {
|
|
8677
|
+
return `\u274C ${name2}: the \`${kind}\` learning adapter answered no blessed set: ${reason}`;
|
|
8606
8678
|
}
|
|
8607
|
-
function
|
|
8608
|
-
|
|
8679
|
+
function makeLearningAdapter(registry, kind, context, name2 = NAME2) {
|
|
8680
|
+
try {
|
|
8681
|
+
return registry.resolve("learning", kind).create({
|
|
8682
|
+
repoRoot: context.repoRoot,
|
|
8683
|
+
home: context.home,
|
|
8684
|
+
learningBlessMinConfidence: context.minConfidence
|
|
8685
|
+
});
|
|
8686
|
+
} catch (error) {
|
|
8687
|
+
throw new CommandExit(1, `\u274C ${name2}: the \`${kind}\` learning adapter cannot be made: ${messageOf(error)}`);
|
|
8688
|
+
}
|
|
8609
8689
|
}
|
|
8610
|
-
function
|
|
8611
|
-
|
|
8690
|
+
async function promotableLessons(context, seams) {
|
|
8691
|
+
expectNoArgument(context.args, USAGE7);
|
|
8692
|
+
const project = requireProject(context, NAME2);
|
|
8693
|
+
const config = resolveProjectConfig(project, NAME2, (message) => {
|
|
8694
|
+
context.output.warn(message);
|
|
8695
|
+
});
|
|
8696
|
+
const kind = config.learningAdapter;
|
|
8697
|
+
const adapter = makeLearningAdapter(seams.registry ?? CORE_ADAPTER_REGISTRY, kind, {
|
|
8698
|
+
repoRoot: project.root,
|
|
8699
|
+
home: project.home,
|
|
8700
|
+
minConfidence: config.learningBlessMinConfidence
|
|
8701
|
+
});
|
|
8702
|
+
const after = config.learningPromoteAfter;
|
|
8703
|
+
const minConfidence = config.learningPromoteMinConfidence;
|
|
8704
|
+
let blessed;
|
|
8705
|
+
try {
|
|
8706
|
+
blessed = (await adapter.pullBlessed()).instincts;
|
|
8707
|
+
} catch (error) {
|
|
8708
|
+
throw new CommandExit(1, refusedPullMessage(kind, messageOf(error)));
|
|
8709
|
+
}
|
|
8710
|
+
return { adapter: kind, after, minConfidence, lessons: promotable(blessed, { after, minConfidence }) };
|
|
8612
8711
|
}
|
|
8613
|
-
function
|
|
8614
|
-
|
|
8615
|
-
|
|
8616
|
-
|
|
8712
|
+
function renderPromotable(result) {
|
|
8713
|
+
const keys = `learning.promote.after ${String(result.after)},` + ` learning.promote.minConfidence ${result.minConfidence.toFixed(CONFIDENCE_DIGITS)}`;
|
|
8714
|
+
if (result.lessons.length === 0) {
|
|
8715
|
+
return [`No lesson the \`${result.adapter}\` learning adapter holds is promotable at ${keys}.`];
|
|
8716
|
+
}
|
|
8717
|
+
return [
|
|
8718
|
+
`${String(result.lessons.length)} lesson(s) to promote from the \`${result.adapter}\` learning adapter, at ${keys}:`,
|
|
8719
|
+
...result.lessons.flatMap((lesson) => [
|
|
8720
|
+
` ${lesson.id} ${lesson.confidence.toFixed(CONFIDENCE_DIGITS)} used ${String(lesson.usage_count)} ${lesson.trigger}`,
|
|
8721
|
+
` ${lesson.action}`
|
|
8722
|
+
])
|
|
8723
|
+
];
|
|
8617
8724
|
}
|
|
8725
|
+
function createInstinctPromoteCommand(seams = {}) {
|
|
8726
|
+
const command = {
|
|
8727
|
+
name: "instinct promote",
|
|
8728
|
+
subject: "instinct",
|
|
8729
|
+
action: "promote",
|
|
8730
|
+
summary: "print the lessons that recurred enough to promote, writing nothing",
|
|
8731
|
+
description: "Prints the lessons the project holds that recurred enough to promote: the blessed set" + " of the learning adapter `learning.adapter` names in `.rafa/config.yaml`, narrowed to the" + " lessons at least `learning.promote.after` distinct sources confirmed at a confidence of at least" + " `learning.promote.minConfidence`, most trusted first. It is the list the next wrap-up session" + " would be asked to promote. Nothing is written: no lesson is marked promoted and no file" + " changes. A kind no registry holds, an adapter that cannot be made or a pull it refuses is exit" + " code 1. With `--output=json` the adapter kind, the two keys' values and the lessons are the" + " data of the terminal result event.",
|
|
8732
|
+
args: [],
|
|
8733
|
+
flags: [],
|
|
8734
|
+
examples: [
|
|
8735
|
+
{
|
|
8736
|
+
cmd: "rafa instinct promote",
|
|
8737
|
+
note: "Lists each promotable lesson with its confidence, usage, trigger and action."
|
|
8738
|
+
},
|
|
8739
|
+
{
|
|
8740
|
+
cmd: "rafa instinct promote --output=json",
|
|
8741
|
+
note: "Gives the adapter kind, the two keys' values and the lessons as the data of the terminal result event."
|
|
8742
|
+
}
|
|
8743
|
+
],
|
|
8744
|
+
outputs: ["text", "json"],
|
|
8745
|
+
run: async (context) => {
|
|
8746
|
+
const result = await promotableLessons(context, seams);
|
|
8747
|
+
if (context.outputMode === "json") {
|
|
8748
|
+
context.output.result(result);
|
|
8749
|
+
return;
|
|
8750
|
+
}
|
|
8751
|
+
for (const line of renderPromotable(result))
|
|
8752
|
+
context.output.info(line);
|
|
8753
|
+
}
|
|
8754
|
+
};
|
|
8755
|
+
return Object.freeze(command);
|
|
8756
|
+
}
|
|
8757
|
+
var promote_default = createInstinctPromoteCommand();
|
|
8618
8758
|
|
|
8619
8759
|
// src/commands/instinct/list.ts
|
|
8620
|
-
var
|
|
8621
|
-
var
|
|
8760
|
+
var NAME3 = "rafa instinct list";
|
|
8761
|
+
var USAGE8 = "rafa instinct list [--blessed | --conflicts]";
|
|
8762
|
+
var CONFIDENCE_DIGITS2 = 2;
|
|
8763
|
+
var HUNDREDTHS = 100;
|
|
8622
8764
|
function instinctRowLine(entry) {
|
|
8623
8765
|
const record = entry.instinct;
|
|
8624
8766
|
if (record === null)
|
|
8625
8767
|
return ` \u274C ${entry.id} ${String(entry.issues.length)} issue(s)`;
|
|
8626
|
-
const confidence = record.confidence.toFixed(
|
|
8768
|
+
const confidence = record.confidence.toFixed(CONFIDENCE_DIGITS2);
|
|
8627
8769
|
return ` \u2705 ${entry.id} ${record.kind}/${record.domain} ${record.signal}` + ` ${confidence} ${record.trigger}`;
|
|
8628
8770
|
}
|
|
8629
8771
|
function scopeLines(listing) {
|
|
@@ -8643,38 +8785,171 @@ function renderInstinctList(result) {
|
|
|
8643
8785
|
`${String(result.total)} instinct(s): ${String(result.clean)} read as records,` + ` ${String(result.total - result.clean)} do not`
|
|
8644
8786
|
];
|
|
8645
8787
|
}
|
|
8646
|
-
function
|
|
8647
|
-
|
|
8648
|
-
|
|
8649
|
-
|
|
8788
|
+
function readViewFlag(name2, value) {
|
|
8789
|
+
if (value === undefined || value === false || value === "false")
|
|
8790
|
+
return false;
|
|
8791
|
+
if (value === true || value === "true")
|
|
8792
|
+
return true;
|
|
8793
|
+
throw new CommandExit(1, `\u274C --${name2} takes no value, and read "${value}" as one
|
|
8794
|
+
Usage: ${USAGE8}`);
|
|
8795
|
+
}
|
|
8796
|
+
function readListView(flags) {
|
|
8797
|
+
const blessed = readViewFlag("blessed", flags["blessed"]);
|
|
8798
|
+
const conflicts = readViewFlag("conflicts", flags["conflicts"]);
|
|
8799
|
+
if (blessed && conflicts) {
|
|
8800
|
+
throw new CommandExit(1, `\u274C --blessed and --conflicts are two views; give one
|
|
8801
|
+
Usage: ${USAGE8}`);
|
|
8802
|
+
}
|
|
8803
|
+
if (blessed)
|
|
8804
|
+
return "blessed";
|
|
8805
|
+
return conflicts ? "conflicts" : "all";
|
|
8806
|
+
}
|
|
8807
|
+
function oneLine(text) {
|
|
8808
|
+
return text.trim().replace(/\s+/gu, " ");
|
|
8809
|
+
}
|
|
8810
|
+
function byConfidence(left, right) {
|
|
8811
|
+
const gap = Math.round(right.confidence * HUNDREDTHS) - Math.round(left.confidence * HUNDREDTHS);
|
|
8812
|
+
if (gap !== 0)
|
|
8813
|
+
return gap;
|
|
8814
|
+
if (left.id < right.id)
|
|
8815
|
+
return -1;
|
|
8816
|
+
return left.id > right.id ? 1 : 0;
|
|
8817
|
+
}
|
|
8818
|
+
function scopeConflicts(listing) {
|
|
8819
|
+
const clean = listing.records.map((entry) => entry.instinct).filter((instinct) => instinct !== null);
|
|
8820
|
+
const groups = new Map;
|
|
8821
|
+
for (const record of toHeldRecords(clean)) {
|
|
8822
|
+
if (record.status !== "flagged")
|
|
8823
|
+
continue;
|
|
8824
|
+
const key = triggerKey(record.trigger);
|
|
8825
|
+
groups.set(key, [...groups.get(key) ?? [], record]);
|
|
8826
|
+
}
|
|
8827
|
+
return [...groups.values()].map((records) => ({
|
|
8828
|
+
scope: listing.scope,
|
|
8829
|
+
trigger: records[0].trigger,
|
|
8830
|
+
records: [...records].sort(byConfidence)
|
|
8831
|
+
}));
|
|
8832
|
+
}
|
|
8833
|
+
function lessonLine(indent, record, width, tail) {
|
|
8834
|
+
return `${indent}${record.id.padEnd(width)} ${record.confidence.toFixed(CONFIDENCE_DIGITS2)}` + ` used ${String(record.usage_count)} ${tail}`;
|
|
8835
|
+
}
|
|
8836
|
+
function conflictLines(conflict) {
|
|
8837
|
+
const width = Math.max(...conflict.records.map((record) => record.id.length));
|
|
8838
|
+
return [
|
|
8839
|
+
` ${conflict.scope} ${conflict.trigger}`,
|
|
8840
|
+
...conflict.records.map((record) => lessonLine(" ", record, width, oneLine(record.action)))
|
|
8841
|
+
];
|
|
8842
|
+
}
|
|
8843
|
+
function renderConflicts(result) {
|
|
8844
|
+
if (result.conflicts.length === 0) {
|
|
8845
|
+
return [`No trigger either instinct scope holds carries more than one action (project: ${result.projectRoot}).`];
|
|
8846
|
+
}
|
|
8847
|
+
return [
|
|
8848
|
+
`Triggers held with more than one action (project: ${result.projectRoot}):`,
|
|
8849
|
+
...result.conflicts.flatMap((conflict) => conflictLines(conflict)),
|
|
8850
|
+
`${String(result.conflicts.length)} flagged trigger(s): no bundle blesses any of their actions`
|
|
8851
|
+
];
|
|
8852
|
+
}
|
|
8853
|
+
function renderBlessed(result) {
|
|
8854
|
+
const floor = `learning.bless.minConfidence ${result.minConfidence.toFixed(CONFIDENCE_DIGITS2)}`;
|
|
8855
|
+
if (result.lessons.length === 0) {
|
|
8856
|
+
return [`No lesson the \`${result.adapter}\` learning adapter holds is blessed at ${floor}.`];
|
|
8857
|
+
}
|
|
8858
|
+
return [
|
|
8859
|
+
`${String(result.lessons.length)} lesson(s) blessed by the \`${result.adapter}\` learning adapter, at ${floor}:`,
|
|
8860
|
+
...result.lessons.flatMap((lesson) => [
|
|
8861
|
+
lessonLine(" ", lesson, 0, lesson.trigger),
|
|
8862
|
+
` ${lesson.action}`
|
|
8863
|
+
])
|
|
8864
|
+
];
|
|
8865
|
+
}
|
|
8866
|
+
async function blessedLessons(context, seams) {
|
|
8867
|
+
const project = instinctProject(context, NAME3);
|
|
8868
|
+
const config = resolveProjectConfig(project, NAME3, (message) => {
|
|
8869
|
+
context.output.warn(message);
|
|
8870
|
+
});
|
|
8871
|
+
const kind = config.learningAdapter;
|
|
8872
|
+
const minConfidence = config.learningBlessMinConfidence;
|
|
8873
|
+
const adapter = makeLearningAdapter(seams.registry ?? CORE_ADAPTER_REGISTRY, kind, { repoRoot: project.root, home: project.home, minConfidence }, NAME3);
|
|
8874
|
+
try {
|
|
8875
|
+
return { adapter: kind, minConfidence, lessons: (await adapter.pullBlessed()).instincts };
|
|
8876
|
+
} catch (error) {
|
|
8877
|
+
throw new CommandExit(1, refusedPullMessage(kind, messageOf(error), NAME3));
|
|
8878
|
+
}
|
|
8879
|
+
}
|
|
8880
|
+
function conflicts(context) {
|
|
8881
|
+
const project = instinctProject(context, NAME3);
|
|
8882
|
+
const scopes = readScopes({ home: project.home, projectRoot: project.root });
|
|
8883
|
+
return { projectRoot: project.root, conflicts: scopes.flatMap((listing) => scopeConflicts(listing)) };
|
|
8884
|
+
}
|
|
8885
|
+
function everyRecord(context) {
|
|
8886
|
+
const project = instinctProject(context, NAME3);
|
|
8887
|
+
const scopes = readScopes({ home: project.home, projectRoot: project.root });
|
|
8650
8888
|
const records = allRecords(scopes);
|
|
8651
|
-
|
|
8889
|
+
return {
|
|
8652
8890
|
projectRoot: project.root,
|
|
8653
8891
|
scopes,
|
|
8654
8892
|
total: records.length,
|
|
8655
8893
|
clean: records.filter((entry) => entry.instinct !== null).length
|
|
8656
8894
|
};
|
|
8895
|
+
}
|
|
8896
|
+
function answer(context, result, lines2) {
|
|
8657
8897
|
if (context.outputMode === "json") {
|
|
8658
8898
|
context.output.result(result);
|
|
8659
8899
|
return;
|
|
8660
8900
|
}
|
|
8661
|
-
for (const line of
|
|
8901
|
+
for (const line of lines2())
|
|
8662
8902
|
context.output.info(line);
|
|
8663
8903
|
}
|
|
8664
|
-
function
|
|
8904
|
+
async function runList4(context, seams) {
|
|
8905
|
+
expectNoArgument(context.args, USAGE8);
|
|
8906
|
+
const view = readListView(context.flags);
|
|
8907
|
+
if (view === "blessed") {
|
|
8908
|
+
const result2 = await blessedLessons(context, seams);
|
|
8909
|
+
answer(context, result2, () => renderBlessed(result2));
|
|
8910
|
+
return;
|
|
8911
|
+
}
|
|
8912
|
+
if (view === "conflicts") {
|
|
8913
|
+
const result2 = conflicts(context);
|
|
8914
|
+
answer(context, result2, () => renderConflicts(result2));
|
|
8915
|
+
return;
|
|
8916
|
+
}
|
|
8917
|
+
const result = everyRecord(context);
|
|
8918
|
+
answer(context, result, () => renderInstinctList(result));
|
|
8919
|
+
}
|
|
8920
|
+
function createInstinctListCommand(seams = {}) {
|
|
8665
8921
|
const command = {
|
|
8666
8922
|
name: "instinct list",
|
|
8667
8923
|
subject: "instinct",
|
|
8668
8924
|
action: "list",
|
|
8669
8925
|
summary: "list the records the project and user instinct scopes hold",
|
|
8670
|
-
description: "Lists every instinct record the two scopes hold \u2014 this project's `.rafa/instincts` and" + " `~/.rafa/instincts` \u2014 with, for each, the id its file name gives it, its `kind/domain` pair, its" + " `signal`, its `confidence` and its `trigger`. A record that breaks a rule of the instinct schema" + " shows the number of rules it broke instead, which `rafa instinct check` then names. The local" + " Learning adapter's `instincts.ndjson` and `flags.ndjson` are its store and no records, and are" + " passed over. A scope whose directory is not there says so. The exit code is 0 whatever the rows" + " say: this command reports and `rafa instinct check` gates. With `--output=json` the scopes and" + "
|
|
8926
|
+
description: "Lists every instinct record the two scopes hold \u2014 this project's `.rafa/instincts` and" + " `~/.rafa/instincts` \u2014 with, for each, the id its file name gives it, its `kind/domain` pair, its" + " `signal`, its `confidence` and its `trigger`. A record that breaks a rule of the instinct schema" + " shows the number of rules it broke instead, which `rafa instinct check` then names. The local" + " Learning adapter's `instincts.ndjson` and `flags.ndjson` are its store and no records, and are" + " passed over. A scope whose directory is not there says so. The exit code is 0 whatever the rows" + " say: this command reports and `rafa instinct check` gates. `--blessed` lists instead the lessons" + " the learning adapter `learning.adapter` names would hand a task, at `learning.bless.minConfidence`," + " most trusted first, writing nothing; an adapter that cannot be made or a pull it refuses is exit" + " code 1. `--conflicts` lists instead each trigger a scope holds with more than one action, which a" + " merge flagged and no bundle blesses, its actions side by side with their confidence and usage." + " The two views are one at a time. With `--output=json` the scopes and their records, or the view" + " asked for, are the data of the terminal result event.",
|
|
8671
8927
|
args: [],
|
|
8672
|
-
flags: [
|
|
8928
|
+
flags: [
|
|
8929
|
+
{
|
|
8930
|
+
name: "blessed",
|
|
8931
|
+
description: "List the lessons the configured learning adapter blesses, each with its confidence, usage," + " trigger and action, instead of every record. Takes no value.",
|
|
8932
|
+
type: "boolean"
|
|
8933
|
+
},
|
|
8934
|
+
{
|
|
8935
|
+
name: "conflicts",
|
|
8936
|
+
description: "List each trigger held with more than one action, its actions side by side with their" + " confidence and usage, instead of every record. Takes no value.",
|
|
8937
|
+
type: "boolean"
|
|
8938
|
+
}
|
|
8939
|
+
],
|
|
8673
8940
|
examples: [
|
|
8674
8941
|
{
|
|
8675
8942
|
cmd: "rafa instinct list",
|
|
8676
8943
|
note: "Lists both scopes, each record with what it is about."
|
|
8677
8944
|
},
|
|
8945
|
+
{
|
|
8946
|
+
cmd: "rafa instinct list --blessed",
|
|
8947
|
+
note: "Lists the lessons a task would be handed, most trusted first."
|
|
8948
|
+
},
|
|
8949
|
+
{
|
|
8950
|
+
cmd: "rafa instinct list --conflicts",
|
|
8951
|
+
note: "Lists each flagged trigger with its actions side by side."
|
|
8952
|
+
},
|
|
8678
8953
|
{
|
|
8679
8954
|
cmd: "rafa instinct list --output=json",
|
|
8680
8955
|
note: "Gives the scopes and every record parsed as the data of the terminal result event."
|
|
@@ -8682,7 +8957,7 @@ function createInstinctListCommand() {
|
|
|
8682
8957
|
],
|
|
8683
8958
|
outputs: ["text", "json"],
|
|
8684
8959
|
run: async (context) => {
|
|
8685
|
-
runList4(context);
|
|
8960
|
+
await runList4(context, seams);
|
|
8686
8961
|
}
|
|
8687
8962
|
};
|
|
8688
8963
|
return Object.freeze(command);
|
|
@@ -8690,7 +8965,7 @@ function createInstinctListCommand() {
|
|
|
8690
8965
|
var list_default4 = createInstinctListCommand();
|
|
8691
8966
|
|
|
8692
8967
|
// src/commands/instinct/show.ts
|
|
8693
|
-
var
|
|
8968
|
+
var USAGE9 = "rafa instinct show <id>";
|
|
8694
8969
|
var FIELD_ORDER = [
|
|
8695
8970
|
"trigger",
|
|
8696
8971
|
"kind",
|
|
@@ -8762,13 +9037,13 @@ function unreadableMessage(entry) {
|
|
|
8762
9037
|
}
|
|
8763
9038
|
function unknownIdMessage(id, scopes) {
|
|
8764
9039
|
const looked = scopes.map((listing) => ` ${listing.scope} ${listing.dir}${listing.exists ? "" : " (no such directory)"}`);
|
|
8765
|
-
return [`\u274C No instinct is filed under "${id}". Looked in:`, ...looked, `Usage: ${
|
|
9040
|
+
return [`\u274C No instinct is filed under "${id}". Looked in:`, ...looked, `Usage: ${USAGE9}`].join(`
|
|
8766
9041
|
`);
|
|
8767
9042
|
}
|
|
8768
9043
|
function runShow2(context) {
|
|
8769
|
-
const id = expectOneArgument(context.args,
|
|
9044
|
+
const id = expectOneArgument(context.args, USAGE9);
|
|
8770
9045
|
const project = instinctProject(context, "rafa instinct show");
|
|
8771
|
-
const scopes =
|
|
9046
|
+
const scopes = readScopes({ home: project.home, projectRoot: project.root });
|
|
8772
9047
|
const found = findRecords(scopes, id);
|
|
8773
9048
|
if (found.length === 0)
|
|
8774
9049
|
throw new CommandExit(1, unknownIdMessage(id, scopes));
|
|
@@ -8825,8 +9100,8 @@ function createInstinctShowCommand() {
|
|
|
8825
9100
|
var show_default2 = createInstinctShowCommand();
|
|
8826
9101
|
|
|
8827
9102
|
// src/commands/issue/check.ts
|
|
8828
|
-
import { readdirSync as
|
|
8829
|
-
import { join as
|
|
9103
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync16, statSync as statSync11 } from "fs";
|
|
9104
|
+
import { join as join22, resolve as resolve10 } from "path";
|
|
8830
9105
|
var CHECK_USAGE = "rafa issue check <n> [--stamp]";
|
|
8831
9106
|
var STAMP_FLAG = "stamp";
|
|
8832
9107
|
var ISSUE_NUMBER = /^[1-9]\d*$/u;
|
|
@@ -8850,7 +9125,7 @@ function missingCopyMessage(issue, specsDir) {
|
|
|
8850
9125
|
function copyNames(dir, issue) {
|
|
8851
9126
|
let names;
|
|
8852
9127
|
try {
|
|
8853
|
-
names =
|
|
9128
|
+
names = readdirSync3(dir);
|
|
8854
9129
|
} catch (error) {
|
|
8855
9130
|
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
8856
9131
|
return [];
|
|
@@ -8858,7 +9133,7 @@ function copyNames(dir, issue) {
|
|
|
8858
9133
|
}
|
|
8859
9134
|
const prefix = `${boardId(issue)}-`;
|
|
8860
9135
|
const notes = notesFileName(issue);
|
|
8861
|
-
return names.filter((name2) => name2.startsWith(prefix) && name2.endsWith(SPEC_EXTENSION) && name2 !== notes).filter((name2) => name2.length > prefix.length + SPEC_EXTENSION.length).filter((name2) =>
|
|
9136
|
+
return names.filter((name2) => name2.startsWith(prefix) && name2.endsWith(SPEC_EXTENSION) && name2 !== notes).filter((name2) => name2.length > prefix.length + SPEC_EXTENSION.length).filter((name2) => statSync11(join22(dir, name2)).isFile()).sort();
|
|
8862
9137
|
}
|
|
8863
9138
|
function findSavedCopy(root, specsDir, issue) {
|
|
8864
9139
|
const names = copyNames(resolve10(root, specsDir), issue);
|
|
@@ -8868,11 +9143,11 @@ function findSavedCopy(root, specsDir, issue) {
|
|
|
8868
9143
|
if (names.length > 1) {
|
|
8869
9144
|
throw new CommandExit(1, [
|
|
8870
9145
|
`\u274C Issue #${String(issue)} has ${String(names.length)} saved copies under ${specsDir}; remove the stale one:`,
|
|
8871
|
-
...names.map((name2) => ` ${
|
|
9146
|
+
...names.map((name2) => ` ${join22(specsDir, name2)}`)
|
|
8872
9147
|
].join(`
|
|
8873
9148
|
`));
|
|
8874
9149
|
}
|
|
8875
|
-
const path =
|
|
9150
|
+
const path = join22(specsDir, only);
|
|
8876
9151
|
return { path, absolute: resolve10(root, path) };
|
|
8877
9152
|
}
|
|
8878
9153
|
function liveText(live) {
|
|
@@ -8921,7 +9196,7 @@ async function readReferences(absolute, issue, verify, stamp) {
|
|
|
8921
9196
|
return rows.map((row2) => checkedRef(row2, row2.stamp));
|
|
8922
9197
|
}
|
|
8923
9198
|
const once = memoiseVerifier(verify);
|
|
8924
|
-
const before = await readRefsText({ copy:
|
|
9199
|
+
const before = await readRefsText({ copy: readFileSync16(absolute, "utf8"), issue, verify: once });
|
|
8925
9200
|
const after = await restampCopyRefs({ path: absolute, issue, verify: once });
|
|
8926
9201
|
return before.rows.map((row2, index) => checkedRef(row2, after.rows[index]?.stamp ?? null));
|
|
8927
9202
|
}
|
|
@@ -8996,10 +9271,10 @@ function createIssueCheckCommand(seams = {}) {
|
|
|
8996
9271
|
var check_default2 = createIssueCheckCommand();
|
|
8997
9272
|
|
|
8998
9273
|
// src/commands/issue/comment.ts
|
|
8999
|
-
var
|
|
9274
|
+
var USAGE10 = "rafa issue comment <id> --body=<text>";
|
|
9000
9275
|
async function commentOnIssue(context, seams) {
|
|
9001
|
-
const id = expectOneArgument(context.args,
|
|
9002
|
-
const body = readRequiredFlag(context.flags, "body",
|
|
9276
|
+
const id = expectOneArgument(context.args, USAGE10);
|
|
9277
|
+
const body = readRequiredFlag(context.flags, "body", USAGE10);
|
|
9003
9278
|
const { tracker, data } = await resolveIssueTracker(context, seams);
|
|
9004
9279
|
const ref = issueRef(tracker, id);
|
|
9005
9280
|
await onTracker(tracker, `comment on issue ${id}`, () => tracker.comment(ref, body));
|
|
@@ -9053,16 +9328,16 @@ function createIssueCommentCommand(seams = DEFAULT_ISSUE_SEAMS) {
|
|
|
9053
9328
|
var comment_default = createIssueCommentCommand();
|
|
9054
9329
|
|
|
9055
9330
|
// src/commands/issue/create.ts
|
|
9056
|
-
var
|
|
9331
|
+
var USAGE11 = "rafa issue create --title=<text> [--body=<text>] [--type=<type>] [--module=<name>] [--priority=<priority>]";
|
|
9057
9332
|
var DEFAULT_ISSUE_TYPE = "code";
|
|
9058
9333
|
function readIssueDraft(flags) {
|
|
9059
9334
|
return {
|
|
9060
9335
|
opt: 0,
|
|
9061
|
-
title: readRequiredFlag(flags, "title",
|
|
9062
|
-
body: readTextFlag(flags, "body",
|
|
9063
|
-
type: readChoiceFlag(flags, "type", ISSUE_TYPES,
|
|
9064
|
-
module: readNonBlankFlag(flags, "module",
|
|
9065
|
-
priority: readChoiceFlag(flags, "priority", ISSUE_PRIORITIES,
|
|
9336
|
+
title: readRequiredFlag(flags, "title", USAGE11),
|
|
9337
|
+
body: readTextFlag(flags, "body", USAGE11) ?? "",
|
|
9338
|
+
type: readChoiceFlag(flags, "type", ISSUE_TYPES, USAGE11) ?? DEFAULT_ISSUE_TYPE,
|
|
9339
|
+
module: readNonBlankFlag(flags, "module", USAGE11) ?? TRIAGE_MODULE,
|
|
9340
|
+
priority: readChoiceFlag(flags, "priority", ISSUE_PRIORITIES, USAGE11) ?? null,
|
|
9066
9341
|
project: null,
|
|
9067
9342
|
blockedBy: []
|
|
9068
9343
|
};
|
|
@@ -9071,7 +9346,7 @@ function renderCreated(ref) {
|
|
|
9071
9346
|
return [`Created ${issueName(ref)}.`, ...urlLines(ref)];
|
|
9072
9347
|
}
|
|
9073
9348
|
async function createIssue(context, seams) {
|
|
9074
|
-
expectNoArgument(context.args,
|
|
9349
|
+
expectNoArgument(context.args, USAGE11);
|
|
9075
9350
|
const draft = readIssueDraft(context.flags);
|
|
9076
9351
|
const { tracker, data } = await resolveIssueTracker(context, seams);
|
|
9077
9352
|
const ref = await onTracker(tracker, "create the issue", () => tracker.create(draft));
|
|
@@ -9223,7 +9498,7 @@ function createGhBoardListing(options) {
|
|
|
9223
9498
|
}
|
|
9224
9499
|
|
|
9225
9500
|
// src/board/roadmap-rows.ts
|
|
9226
|
-
import { readdirSync as
|
|
9501
|
+
import { readdirSync as readdirSync4 } from "fs";
|
|
9227
9502
|
var OUTLINE_HEADINGS = 3;
|
|
9228
9503
|
var UNKNOWN_STATE = "unknown";
|
|
9229
9504
|
function isMissing(error) {
|
|
@@ -9232,7 +9507,7 @@ function isMissing(error) {
|
|
|
9232
9507
|
function createPlanDirNames(dir) {
|
|
9233
9508
|
return () => {
|
|
9234
9509
|
try {
|
|
9235
|
-
return Object.freeze(
|
|
9510
|
+
return Object.freeze(readdirSync4(dir));
|
|
9236
9511
|
} catch (error) {
|
|
9237
9512
|
if (isMissing(error))
|
|
9238
9513
|
return Object.freeze([]);
|
|
@@ -9463,24 +9738,24 @@ function renderRoadmapTable(rows, width) {
|
|
|
9463
9738
|
}
|
|
9464
9739
|
|
|
9465
9740
|
// src/commands/issue/list.ts
|
|
9466
|
-
var
|
|
9467
|
-
var SWITCH_HINT = `Type it bare: ${
|
|
9741
|
+
var USAGE12 = "rafa issue list [--roadmap [--all]] [--state=<state>] [--type=<type>] [--module=<name>]" + " [--search=<text>] [--limit=<n>]";
|
|
9742
|
+
var SWITCH_HINT = `Type it bare: ${USAGE12}`;
|
|
9468
9743
|
var LIMIT = /^[1-9]\d*$/;
|
|
9469
9744
|
function readLimit(flags) {
|
|
9470
|
-
const value = readTextFlag(flags, "limit",
|
|
9745
|
+
const value = readTextFlag(flags, "limit", USAGE12);
|
|
9471
9746
|
if (value === undefined)
|
|
9472
9747
|
return;
|
|
9473
9748
|
const limit = Number(value);
|
|
9474
9749
|
if (LIMIT.test(value) && Number.isSafeInteger(limit))
|
|
9475
9750
|
return limit;
|
|
9476
|
-
throw lineRefusal(`--limit is "${value}", expected a positive whole number`,
|
|
9751
|
+
throw lineRefusal(`--limit is "${value}", expected a positive whole number`, USAGE12);
|
|
9477
9752
|
}
|
|
9478
9753
|
function readIssueQuery(flags) {
|
|
9479
9754
|
const narrowed = {
|
|
9480
|
-
state: readChoiceFlag(flags, "state", ISSUE_STATES,
|
|
9481
|
-
type: readChoiceFlag(flags, "type", ISSUE_TYPES,
|
|
9482
|
-
module: readNonBlankFlag(flags, "module",
|
|
9483
|
-
text: readNonBlankFlag(flags, "search",
|
|
9755
|
+
state: readChoiceFlag(flags, "state", ISSUE_STATES, USAGE12),
|
|
9756
|
+
type: readChoiceFlag(flags, "type", ISSUE_TYPES, USAGE12),
|
|
9757
|
+
module: readNonBlankFlag(flags, "module", USAGE12),
|
|
9758
|
+
text: readNonBlankFlag(flags, "search", USAGE12),
|
|
9484
9759
|
limit: readLimit(flags)
|
|
9485
9760
|
};
|
|
9486
9761
|
return Object.fromEntries(Object.entries(narrowed).filter(([, value]) => value !== undefined));
|
|
@@ -9489,10 +9764,10 @@ function readIssueListLine(flags) {
|
|
|
9489
9764
|
const roadmap = readSwitch("roadmap", flags["roadmap"], SWITCH_HINT);
|
|
9490
9765
|
const all = readSwitch("all", flags["all"], SWITCH_HINT);
|
|
9491
9766
|
if (roadmap && flags["state"] !== undefined) {
|
|
9492
|
-
throw lineRefusal("--state cannot narrow --roadmap: the Roadmap is read off the GitHub board, which holds an issue open or" + " closed and so no state of the tracker",
|
|
9767
|
+
throw lineRefusal("--state cannot narrow --roadmap: the Roadmap is read off the GitHub board, which holds an issue open or" + " closed and so no state of the tracker", USAGE12);
|
|
9493
9768
|
}
|
|
9494
9769
|
if (all && !roadmap)
|
|
9495
|
-
throw lineRefusal("--all keeps the ticked Roadmap lines, so it needs --roadmap",
|
|
9770
|
+
throw lineRefusal("--all keeps the ticked Roadmap lines, so it needs --roadmap", USAGE12);
|
|
9496
9771
|
return { roadmap, all };
|
|
9497
9772
|
}
|
|
9498
9773
|
function renderIssueList(kind, issues) {
|
|
@@ -9571,7 +9846,7 @@ async function listRoadmap(context, seams, all, filter) {
|
|
|
9571
9846
|
});
|
|
9572
9847
|
}
|
|
9573
9848
|
async function listIssues(context, seams) {
|
|
9574
|
-
expectNoArgument(context.args,
|
|
9849
|
+
expectNoArgument(context.args, USAGE12);
|
|
9575
9850
|
const query = readIssueQuery(context.flags);
|
|
9576
9851
|
const { tracker, data } = await resolveIssueTracker(context, seams);
|
|
9577
9852
|
const refs = await onTracker(tracker, "list issues", () => tracker.find(query));
|
|
@@ -9590,7 +9865,7 @@ async function runIssueList(context, seams) {
|
|
|
9590
9865
|
context.output.info(text);
|
|
9591
9866
|
return;
|
|
9592
9867
|
}
|
|
9593
|
-
expectNoArgument(context.args,
|
|
9868
|
+
expectNoArgument(context.args, USAGE12);
|
|
9594
9869
|
const filter = readIssueQuery(context.flags);
|
|
9595
9870
|
const listed2 = await listRoadmap(context, seams, line.all, filter);
|
|
9596
9871
|
if (context.outputMode === "json") {
|
|
@@ -9677,10 +9952,10 @@ function createIssueListCommand(seams = DEFAULT_ISSUE_SEAMS) {
|
|
|
9677
9952
|
var list_default5 = createIssueListCommand();
|
|
9678
9953
|
|
|
9679
9954
|
// src/commands/issue/move.ts
|
|
9680
|
-
var
|
|
9955
|
+
var USAGE13 = "rafa issue move <id> <state>";
|
|
9681
9956
|
async function moveIssue(context, seams) {
|
|
9682
|
-
const [id, word] = expectTwoArguments(context.args,
|
|
9683
|
-
const state = readChoice(word, "The state", ISSUE_STATES,
|
|
9957
|
+
const [id, word] = expectTwoArguments(context.args, USAGE13);
|
|
9958
|
+
const state = readChoice(word, "The state", ISSUE_STATES, USAGE13);
|
|
9684
9959
|
const { tracker, data } = await resolveIssueTracker(context, seams);
|
|
9685
9960
|
const ref = issueRef(tracker, id);
|
|
9686
9961
|
const moved = await onTracker(tracker, `move issue ${id} to ${state}`, () => tracker.transition(ref, state));
|
|
@@ -9739,7 +10014,7 @@ function createIssueMoveCommand(seams = DEFAULT_ISSUE_SEAMS) {
|
|
|
9739
10014
|
var move_default = createIssueMoveCommand();
|
|
9740
10015
|
|
|
9741
10016
|
// src/commands/issue/show.ts
|
|
9742
|
-
var
|
|
10017
|
+
var USAGE14 = "rafa issue show <id>";
|
|
9743
10018
|
var NO_PRIORITY = "needs-triage";
|
|
9744
10019
|
function renderIssue(kind, issue) {
|
|
9745
10020
|
const project = issue.project === null ? [] : [`Project: ${issue.project}`];
|
|
@@ -9761,7 +10036,7 @@ function renderIssue(kind, issue) {
|
|
|
9761
10036
|
];
|
|
9762
10037
|
}
|
|
9763
10038
|
async function showIssue(context, seams) {
|
|
9764
|
-
const id = expectOneArgument(context.args,
|
|
10039
|
+
const id = expectOneArgument(context.args, USAGE14);
|
|
9765
10040
|
const { tracker, data } = await resolveIssueTracker(context, seams);
|
|
9766
10041
|
const issue = await onTracker(tracker, `read issue ${id}`, () => tracker.get(issueRef(tracker, id)));
|
|
9767
10042
|
return { tracker: data, issue };
|
|
@@ -10050,8 +10325,8 @@ function projectRoot2(context) {
|
|
|
10050
10325
|
throw new Error("rafa issue unblock runs inside a project, and was handed none");
|
|
10051
10326
|
return context.project.root;
|
|
10052
10327
|
}
|
|
10053
|
-
function isYes(
|
|
10054
|
-
return
|
|
10328
|
+
function isYes(answer2) {
|
|
10329
|
+
return answer2 !== null && YES_ANSWERS2.includes(answer2.trim().toLowerCase());
|
|
10055
10330
|
}
|
|
10056
10331
|
function lazyPrompter2(open) {
|
|
10057
10332
|
let prompter = null;
|
|
@@ -10151,7 +10426,7 @@ function createIssueUnblockCommand(seams = DEFAULT_UNBLOCK_SEAMS) {
|
|
|
10151
10426
|
var unblock_default = createIssueUnblockCommand();
|
|
10152
10427
|
|
|
10153
10428
|
// src/commands/loop/list.ts
|
|
10154
|
-
var
|
|
10429
|
+
var USAGE15 = "rafa loop list";
|
|
10155
10430
|
function renderSessionList(list) {
|
|
10156
10431
|
if (list.sessions.length === 0)
|
|
10157
10432
|
return ["No running sessions."];
|
|
@@ -10161,7 +10436,7 @@ function renderSessionList(list) {
|
|
|
10161
10436
|
];
|
|
10162
10437
|
}
|
|
10163
10438
|
async function runList5(context, seams) {
|
|
10164
|
-
expectNoArgument(context.args,
|
|
10439
|
+
expectNoArgument(context.args, USAGE15);
|
|
10165
10440
|
const root = projectRoot(context);
|
|
10166
10441
|
const sessions = readRecords(root, seams).filter(isLive).map((session) => {
|
|
10167
10442
|
const checklist = readSessionChecklist(root, session);
|
|
@@ -10206,7 +10481,7 @@ function createLoopListCommand(seams = {}) {
|
|
|
10206
10481
|
var list_default6 = createLoopListCommand();
|
|
10207
10482
|
|
|
10208
10483
|
// src/commands/loop/pause.ts
|
|
10209
|
-
var
|
|
10484
|
+
var USAGE16 = "rafa loop pause [-s|--session-id=<id>]";
|
|
10210
10485
|
function renderPause(result) {
|
|
10211
10486
|
const { session } = result;
|
|
10212
10487
|
if (!result.changed)
|
|
@@ -10215,8 +10490,8 @@ function renderPause(result) {
|
|
|
10215
10490
|
return [when, " Nothing is marked. `rafa loop resume` goes on, and `rafa loop stop` ends the run."];
|
|
10216
10491
|
}
|
|
10217
10492
|
async function runPause(context, seams) {
|
|
10218
|
-
expectNoArgument(context.args,
|
|
10219
|
-
const { root, record } = pickSession(context,
|
|
10493
|
+
expectNoArgument(context.args, USAGE16);
|
|
10494
|
+
const { root, record } = pickSession(context, USAGE16, "live", seams);
|
|
10220
10495
|
if (!isLive(record)) {
|
|
10221
10496
|
throw refusal(`Session ${record.sessionId} reads ${record.state}: no run is left to pause.`);
|
|
10222
10497
|
}
|
|
@@ -10256,7 +10531,7 @@ function createLoopPauseCommand(seams = {}) {
|
|
|
10256
10531
|
var pause_default = createLoopPauseCommand();
|
|
10257
10532
|
|
|
10258
10533
|
// src/commands/loop/resume.ts
|
|
10259
|
-
var
|
|
10534
|
+
var USAGE17 = "rafa loop resume [-s|--session-id=<id>]";
|
|
10260
10535
|
function renderResume(result) {
|
|
10261
10536
|
const { session } = result;
|
|
10262
10537
|
if (!result.changed)
|
|
@@ -10264,8 +10539,8 @@ function renderResume(result) {
|
|
|
10264
10539
|
return [session.task === null ? `Resumed session ${session.sessionId}: it goes on with its next task.` : `Resumed session ${session.sessionId}: it goes on past its running task, line ${session.task.line}, ${session.task.text}`];
|
|
10265
10540
|
}
|
|
10266
10541
|
async function runResume(context, seams) {
|
|
10267
|
-
expectNoArgument(context.args,
|
|
10268
|
-
const { root, record } = pickSession(context,
|
|
10542
|
+
expectNoArgument(context.args, USAGE17);
|
|
10543
|
+
const { root, record } = pickSession(context, USAGE17, "live", seams);
|
|
10269
10544
|
if (!isLive(record)) {
|
|
10270
10545
|
throw refusal(`Session ${record.sessionId} reads ${record.state}: its run has ended, so there is nothing to resume.`, `\`rafa loop start --plan=${record.plan}\` runs its plan again as a new session, its blocked tasks first.`);
|
|
10271
10546
|
}
|
|
@@ -10400,7 +10675,7 @@ var loopStart = Object.freeze({
|
|
|
10400
10675
|
var start_default = endingWith(loopStart);
|
|
10401
10676
|
|
|
10402
10677
|
// src/commands/loop/status.ts
|
|
10403
|
-
var
|
|
10678
|
+
var USAGE18 = "rafa loop status [-s|--session-id=<id>]";
|
|
10404
10679
|
var BLOCKED_TASK_LINE = /^- \[BLOCKED\] (.+)/;
|
|
10405
10680
|
var NO_BLOCKER = "the line trails no blocker comment";
|
|
10406
10681
|
function blockerAt(checklist, lineNum) {
|
|
@@ -10436,8 +10711,8 @@ function renderStatus(status) {
|
|
|
10436
10711
|
];
|
|
10437
10712
|
}
|
|
10438
10713
|
async function runStatus(context, seams) {
|
|
10439
|
-
expectNoArgument(context.args,
|
|
10440
|
-
const { root, record } = pickSession(context,
|
|
10714
|
+
expectNoArgument(context.args, USAGE18);
|
|
10715
|
+
const { root, record } = pickSession(context, USAGE18, "live-or-newest", seams);
|
|
10441
10716
|
const checklist = readSessionChecklist(root, record);
|
|
10442
10717
|
const tasks = checklist === null ? null : countTasks(checklist.tasks);
|
|
10443
10718
|
let eta = null;
|
|
@@ -10490,7 +10765,7 @@ function createLoopStatusCommand(seams = {}) {
|
|
|
10490
10765
|
var status_default = createLoopStatusCommand();
|
|
10491
10766
|
|
|
10492
10767
|
// src/commands/loop/stop.ts
|
|
10493
|
-
var
|
|
10768
|
+
var USAGE19 = "rafa loop stop [-s|--session-id=<id>]";
|
|
10494
10769
|
function signalRun(record, interrupt) {
|
|
10495
10770
|
try {
|
|
10496
10771
|
interrupt(record.pid);
|
|
@@ -10543,8 +10818,8 @@ function renderStop(result) {
|
|
|
10543
10818
|
];
|
|
10544
10819
|
}
|
|
10545
10820
|
async function runStop(context, seams) {
|
|
10546
|
-
expectNoArgument(context.args,
|
|
10547
|
-
const { root, record } = pickSession(context,
|
|
10821
|
+
expectNoArgument(context.args, USAGE19);
|
|
10822
|
+
const { root, record } = pickSession(context, USAGE19, "live", seams);
|
|
10548
10823
|
if (!isLive(record)) {
|
|
10549
10824
|
throw refusal(`Session ${record.sessionId} reads ${record.state}: no run is left to stop.`);
|
|
10550
10825
|
}
|
|
@@ -10595,7 +10870,7 @@ function createLoopStopCommand(seams = {}) {
|
|
|
10595
10870
|
var stop_default = createLoopStopCommand();
|
|
10596
10871
|
|
|
10597
10872
|
// src/commands/module/exec.ts
|
|
10598
|
-
var
|
|
10873
|
+
var USAGE20 = "rafa module exec <module> <action> [args] [flags]";
|
|
10599
10874
|
var execCommand = {
|
|
10600
10875
|
name: "module exec",
|
|
10601
10876
|
subject: "module",
|
|
@@ -10624,13 +10899,13 @@ var execCommand = {
|
|
|
10624
10899
|
const mounts = context.registry.mounts();
|
|
10625
10900
|
const mounted = mounts.length === 0 ? "none is mounted; a module is mounted when allowList: names it and modules: gives its path source" : mounts.map((mount) => `${mount.name} (${context.registry.actionsOf(mountKey(mount.name)).map((held) => held.action).join(", ")})`).join(", ");
|
|
10626
10901
|
throw new CommandExit(1, `\u274C Expected a module and one of its actions; mounted: ${mounted}
|
|
10627
|
-
Usage: ${
|
|
10902
|
+
Usage: ${USAGE20}`);
|
|
10628
10903
|
}
|
|
10629
10904
|
};
|
|
10630
10905
|
var exec_default = Object.freeze(execCommand);
|
|
10631
10906
|
|
|
10632
10907
|
// src/commands/module/list.ts
|
|
10633
|
-
var
|
|
10908
|
+
var USAGE21 = "rafa module list";
|
|
10634
10909
|
function sourceText(source) {
|
|
10635
10910
|
const ref = source.ref === null ? "" : `@${source.ref}`;
|
|
10636
10911
|
return `${source.kind} ${source.location}${ref}`;
|
|
@@ -10651,10 +10926,10 @@ function renderModuleList(list) {
|
|
|
10651
10926
|
return ["Modules:", ...list.modules.flatMap(moduleLines)];
|
|
10652
10927
|
}
|
|
10653
10928
|
async function runList6(context, seams) {
|
|
10654
|
-
expectNoArgument(context.args,
|
|
10929
|
+
expectNoArgument(context.args, USAGE21);
|
|
10655
10930
|
const { project } = context;
|
|
10656
10931
|
if (project === null)
|
|
10657
|
-
throw new CommandExit(1, `\u274C ${
|
|
10932
|
+
throw new CommandExit(1, `\u274C ${USAGE21} runs inside a project`);
|
|
10658
10933
|
let loaded;
|
|
10659
10934
|
try {
|
|
10660
10935
|
const resolved = loadConfig({ root: project.root, home: project.home });
|
|
@@ -11120,10 +11395,10 @@ var wrapped2 = wrapPhaseZeroCommand({
|
|
|
11120
11395
|
var create_default2 = endingWith(wrapped2);
|
|
11121
11396
|
|
|
11122
11397
|
// src/commands/plan/risk.ts
|
|
11123
|
-
import { readFileSync as
|
|
11398
|
+
import { readFileSync as readFileSync17 } from "fs";
|
|
11124
11399
|
import { resolve as resolve11 } from "path";
|
|
11125
11400
|
var COMMAND2 = "rafa plan risk";
|
|
11126
|
-
var
|
|
11401
|
+
var USAGE22 = "rafa plan risk [<plan>] [--strict]";
|
|
11127
11402
|
var STRICT_HINT = `Type the plan first: ${COMMAND2} <plan> --strict`;
|
|
11128
11403
|
function spawningRunners(root) {
|
|
11129
11404
|
return { git: createGitRunner(root), gh: createGhRunner({ cwd: root }) };
|
|
@@ -11136,7 +11411,7 @@ function riskPlanPath(root, planDir, typed) {
|
|
|
11136
11411
|
throw new CommandExit(1, `\u274C Plan file not found: ${path}`);
|
|
11137
11412
|
const lookedFor = [...new Set([resolve11(root, planDir, DEFAULT_PLAN_FILE), resolve11(root, DEFAULT_PLAN_FILE)])];
|
|
11138
11413
|
throw new CommandExit(1, `\u274C No plan named, and no default plan at ${lookedFor.join(" or ")}
|
|
11139
|
-
Usage: ${
|
|
11414
|
+
Usage: ${USAGE22}`);
|
|
11140
11415
|
}
|
|
11141
11416
|
function riskLine(finding) {
|
|
11142
11417
|
const line = finding.line === undefined ? "" : `:${String(finding.line)}`;
|
|
@@ -11148,7 +11423,7 @@ function strictRefusal(report2) {
|
|
|
11148
11423
|
}
|
|
11149
11424
|
async function readRisk(path, project, config, context, seams) {
|
|
11150
11425
|
const makeRunners = seams.runners ?? spawningRunners;
|
|
11151
|
-
return assessPlanRisk({ path, text:
|
|
11426
|
+
return assessPlanRisk({ path, text: readFileSync17(path, "utf8") }, {
|
|
11152
11427
|
repoRoot: project.root,
|
|
11153
11428
|
home: project.home,
|
|
11154
11429
|
settingSources: config.settingSources,
|
|
@@ -11200,7 +11475,7 @@ function createPlanRiskCommand(seams = {}) {
|
|
|
11200
11475
|
outputs: ["text", "json"],
|
|
11201
11476
|
run: async (context) => {
|
|
11202
11477
|
const strict = readSwitch("strict", context.flags["strict"], STRICT_HINT);
|
|
11203
|
-
const typed = expectAtMostOneArgument(context.args,
|
|
11478
|
+
const typed = expectAtMostOneArgument(context.args, USAGE22);
|
|
11204
11479
|
const project = requireProject(context, COMMAND2);
|
|
11205
11480
|
const config = resolveProjectConfig(project, COMMAND2, (message) => {
|
|
11206
11481
|
context.output.warn(message);
|
|
@@ -11231,9 +11506,9 @@ function createPlanRiskCommand(seams = {}) {
|
|
|
11231
11506
|
var risk_default = createPlanRiskCommand();
|
|
11232
11507
|
|
|
11233
11508
|
// src/commands/plan/show.ts
|
|
11234
|
-
import { readFileSync as
|
|
11235
|
-
import { join as
|
|
11236
|
-
var
|
|
11509
|
+
import { readFileSync as readFileSync18 } from "fs";
|
|
11510
|
+
import { join as join23 } from "path";
|
|
11511
|
+
var USAGE23 = "rafa plan show <stub> [--tracker]";
|
|
11237
11512
|
var COMMAND3 = "rafa plan show";
|
|
11238
11513
|
function readTrackerFlag(value) {
|
|
11239
11514
|
if (value === undefined || value === false || value === "false")
|
|
@@ -11250,10 +11525,10 @@ function showPlan(plans, stub, tracker) {
|
|
|
11250
11525
|
throw new CommandExit(1, `\u274C "${stub}" is no plan stub: a stub is letters, digits, ".", "_" and "-"`);
|
|
11251
11526
|
}
|
|
11252
11527
|
const name2 = planFileName(stub, tracker);
|
|
11253
|
-
const file =
|
|
11528
|
+
const file = join23(plans.path, name2);
|
|
11254
11529
|
if (!isFile(file))
|
|
11255
|
-
throw new CommandExit(1, missingText(stub, tracker,
|
|
11256
|
-
const model = parsePlan(
|
|
11530
|
+
throw new CommandExit(1, missingText(stub, tracker, join23(plans.label, name2)));
|
|
11531
|
+
const model = parsePlan(readFileSync18(file, "utf8"));
|
|
11257
11532
|
const { header } = model;
|
|
11258
11533
|
return {
|
|
11259
11534
|
stub,
|
|
@@ -11276,7 +11551,7 @@ function taskLine(task) {
|
|
|
11276
11551
|
return ` ${checkbox(task.status)} ${task.text}`;
|
|
11277
11552
|
}
|
|
11278
11553
|
function renderShownPlan(shown, dirLabel) {
|
|
11279
|
-
const relative7 =
|
|
11554
|
+
const relative7 = join23(dirLabel, planFileName(shown.stub, shown.tracker));
|
|
11280
11555
|
const fileLabel = shown.tracker ? "Tracker" : "File";
|
|
11281
11556
|
const lines2 = [`Plan: ${shown.stub}`, `${fileLabel}: ${relative7}`];
|
|
11282
11557
|
if (shown.header.issue !== null)
|
|
@@ -11329,7 +11604,7 @@ var planShowCommand = {
|
|
|
11329
11604
|
outputs: ["text", "json"],
|
|
11330
11605
|
run: async (context) => {
|
|
11331
11606
|
const tracker = readTrackerFlag(context.flags.tracker);
|
|
11332
|
-
const stub = expectOneArgument(context.args,
|
|
11607
|
+
const stub = expectOneArgument(context.args, USAGE23);
|
|
11333
11608
|
const plans = resolvePlansDir(requireProject(context, COMMAND3), COMMAND3, (message) => {
|
|
11334
11609
|
context.output.warn(message);
|
|
11335
11610
|
});
|
|
@@ -11468,7 +11743,7 @@ Run rafa pr list to see the open pull requests.`, usage2);
|
|
|
11468
11743
|
}
|
|
11469
11744
|
|
|
11470
11745
|
// src/commands/pr/current.ts
|
|
11471
|
-
var
|
|
11746
|
+
var USAGE24 = PR_USAGE.current;
|
|
11472
11747
|
var SEPARATOR = " \u2014 ";
|
|
11473
11748
|
function trimmedOrNull(value) {
|
|
11474
11749
|
const trimmed = value.trim();
|
|
@@ -11499,9 +11774,9 @@ async function probeChecks(pulls, number) {
|
|
|
11499
11774
|
}
|
|
11500
11775
|
}
|
|
11501
11776
|
async function readCurrent(context, seams) {
|
|
11502
|
-
expectNoArguments(context.args,
|
|
11777
|
+
expectNoArguments(context.args, USAGE24);
|
|
11503
11778
|
const pr = openPrContext(context, seams);
|
|
11504
|
-
const pick = await pickPullRequest(pr, null,
|
|
11779
|
+
const pick = await pickPullRequest(pr, null, USAGE24);
|
|
11505
11780
|
const summary = pick.summary;
|
|
11506
11781
|
const probe = await probeChecks(pr.pulls, pick.number);
|
|
11507
11782
|
const reading = {
|
|
@@ -11554,7 +11829,7 @@ function createPrCurrentCommand(seams = DEFAULT_PR_SEAMS) {
|
|
|
11554
11829
|
var current_default = createPrCurrentCommand();
|
|
11555
11830
|
|
|
11556
11831
|
// src/commands/pr/list.ts
|
|
11557
|
-
var
|
|
11832
|
+
var USAGE25 = PR_USAGE.list;
|
|
11558
11833
|
var UNREADABLE2 = "?";
|
|
11559
11834
|
var PROBE_LIMIT = 6;
|
|
11560
11835
|
var TITLE_WIDTH = 60;
|
|
@@ -11655,7 +11930,7 @@ async function rowOf3(pulls, pull) {
|
|
|
11655
11930
|
};
|
|
11656
11931
|
}
|
|
11657
11932
|
async function readList(context, seams, now) {
|
|
11658
|
-
expectNoArguments(context.args,
|
|
11933
|
+
expectNoArguments(context.args, USAGE25);
|
|
11659
11934
|
const pr = openPrContext(context, seams);
|
|
11660
11935
|
const open = await onProvider("list the open pull requests", () => pr.pulls.list());
|
|
11661
11936
|
const rows = await mapWithLimit(open, PROBE_LIMIT, (pull) => rowOf3(pr.pulls, pull));
|
|
@@ -11695,8 +11970,8 @@ function createPrListCommand(seams = DEFAULT_PR_SEAMS) {
|
|
|
11695
11970
|
var list_default8 = createPrListCommand();
|
|
11696
11971
|
|
|
11697
11972
|
// src/commands/pr/merge.ts
|
|
11698
|
-
import { existsSync as existsSync9, readFileSync as
|
|
11699
|
-
import { join as
|
|
11973
|
+
import { existsSync as existsSync9, readFileSync as readFileSync20 } from "fs";
|
|
11974
|
+
import { join as join25 } from "path";
|
|
11700
11975
|
|
|
11701
11976
|
// src/board/roadmap-tick.ts
|
|
11702
11977
|
var PREFIX5 = "board roadmap";
|
|
@@ -11853,15 +12128,15 @@ import {
|
|
|
11853
12128
|
copyFileSync as copyFileSync3,
|
|
11854
12129
|
existsSync as existsSync8,
|
|
11855
12130
|
mkdirSync as mkdirSync6,
|
|
11856
|
-
readdirSync as
|
|
11857
|
-
readFileSync as
|
|
12131
|
+
readdirSync as readdirSync5,
|
|
12132
|
+
readFileSync as readFileSync19,
|
|
11858
12133
|
realpathSync as realpathSync5,
|
|
11859
12134
|
renameSync,
|
|
11860
12135
|
rmSync as rmSync2,
|
|
11861
|
-
statSync as
|
|
12136
|
+
statSync as statSync12,
|
|
11862
12137
|
symlinkSync
|
|
11863
12138
|
} from "fs";
|
|
11864
|
-
import { basename as basename7, delimiter as delimiter2, dirname as dirname4, join as
|
|
12139
|
+
import { basename as basename7, delimiter as delimiter2, dirname as dirname4, join as join24, relative as relative7, resolve as resolve12 } from "path";
|
|
11865
12140
|
var LINK_NAME = "rafa";
|
|
11866
12141
|
var FORCE_FLAG = "--force";
|
|
11867
12142
|
var EXIT_DONE = 0;
|
|
@@ -11923,19 +12198,19 @@ function runtimeRefusalLines(runtimeDir, version2) {
|
|
|
11923
12198
|
}
|
|
11924
12199
|
function listTrackers(repoRoot, planDir) {
|
|
11925
12200
|
const dir = resolve12(repoRoot, planDir);
|
|
11926
|
-
return entryNames(dir).filter((entry) => TRACKER_NAME.test(entry)).sort((a, b) => a.localeCompare(b)).map((entry) =>
|
|
12201
|
+
return entryNames(dir).filter((entry) => TRACKER_NAME.test(entry)).sort((a, b) => a.localeCompare(b)).map((entry) => join24(dir, entry)).filter((path) => statSync12(path).isFile()).map((path) => relative7(repoRoot, path));
|
|
11927
12202
|
}
|
|
11928
12203
|
function openTrackers(repoRoot, planDir) {
|
|
11929
12204
|
return listTrackers(repoRoot, planDir).flatMap((path) => {
|
|
11930
|
-
const task = findNextTask(
|
|
12205
|
+
const task = findNextTask(readFileSync19(join24(repoRoot, path), "utf8"));
|
|
11931
12206
|
return task ? [{ path, task }] : [];
|
|
11932
12207
|
});
|
|
11933
12208
|
}
|
|
11934
12209
|
function readManifestVersion2(repoRoot) {
|
|
11935
|
-
const manifest = JSON.parse(
|
|
12210
|
+
const manifest = JSON.parse(readFileSync19(join24(repoRoot, "package.json"), "utf8"));
|
|
11936
12211
|
const record = typeof manifest === "object" && manifest !== null ? manifest : {};
|
|
11937
12212
|
if (record["name"] !== name) {
|
|
11938
|
-
throw new Error(`${
|
|
12213
|
+
throw new Error(`${join24(repoRoot, "package.json")} names ${JSON.stringify(record["name"])}, not ${name}: this is no rafa checkout`);
|
|
11939
12214
|
}
|
|
11940
12215
|
const version2 = record["version"];
|
|
11941
12216
|
if (typeof version2 !== "string" || !VERSION_SHAPE.test(version2)) {
|
|
@@ -11946,10 +12221,10 @@ function readManifestVersion2(repoRoot) {
|
|
|
11946
12221
|
function copyTree(from, to) {
|
|
11947
12222
|
mkdirSync6(to, { recursive: true });
|
|
11948
12223
|
let copied = 0;
|
|
11949
|
-
const entries =
|
|
12224
|
+
const entries = readdirSync5(from, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
11950
12225
|
for (const entry of entries) {
|
|
11951
|
-
const source =
|
|
11952
|
-
const target =
|
|
12226
|
+
const source = join24(from, entry.name);
|
|
12227
|
+
const target = join24(to, entry.name);
|
|
11953
12228
|
if (entry.isDirectory()) {
|
|
11954
12229
|
copied += copyTree(source, target);
|
|
11955
12230
|
} else if (entry.isFile()) {
|
|
@@ -12044,8 +12319,8 @@ function installRuntime(seams, options = {}) {
|
|
|
12044
12319
|
}
|
|
12045
12320
|
function runInstall(seams, options) {
|
|
12046
12321
|
const { repoRoot, home, log } = seams;
|
|
12047
|
-
const runtimeRoot =
|
|
12048
|
-
const linkPath =
|
|
12322
|
+
const runtimeRoot = join24(home, RUNTIME_SUBDIR);
|
|
12323
|
+
const linkPath = join24(home, RAFA_BIN_DIR, LINK_NAME);
|
|
12049
12324
|
log(`repo root: ${repoRoot}`);
|
|
12050
12325
|
log(`runtime root: ${runtimeRoot}`);
|
|
12051
12326
|
log(`link: ${linkPath}`);
|
|
@@ -12055,8 +12330,8 @@ function runInstall(seams, options) {
|
|
|
12055
12330
|
const open = inStage("trackers", () => openTrackers(repoRoot, planDir));
|
|
12056
12331
|
if (open.length > 0)
|
|
12057
12332
|
return { kind: "refused", reason: "trackers", planDir, trackers: open };
|
|
12058
|
-
const distDir =
|
|
12059
|
-
const runtimeDir =
|
|
12333
|
+
const distDir = join24(repoRoot, "dist");
|
|
12334
|
+
const runtimeDir = join24(runtimeRoot, version2);
|
|
12060
12335
|
const installed = existsSync8(runtimeDir);
|
|
12061
12336
|
if (installed && options.force !== true) {
|
|
12062
12337
|
return { kind: "refused", reason: "runtime-exists", version: version2, runtimeDir };
|
|
@@ -12065,13 +12340,13 @@ function runInstall(seams, options) {
|
|
|
12065
12340
|
const code = inStage("build", () => seams.build(repoRoot));
|
|
12066
12341
|
if (code !== 0)
|
|
12067
12342
|
throw new StageFailure("build", `the build exited ${code}`);
|
|
12068
|
-
if (!existsSync8(
|
|
12069
|
-
throw new StageFailure("build", `the build exited 0 and left no ${
|
|
12343
|
+
if (!existsSync8(join24(distDir, RUNTIME_ENTRY))) {
|
|
12344
|
+
throw new StageFailure("build", `the build exited 0 and left no ${join24(distDir, RUNTIME_ENTRY)}`);
|
|
12070
12345
|
}
|
|
12071
12346
|
log(installed ? `copying ${distDir} over ${runtimeDir}, replacing it whole` : `copying ${distDir} into ${runtimeDir}`);
|
|
12072
12347
|
const copied = inStage("copy", () => replaceTree(distDir, runtimeDir));
|
|
12073
12348
|
log(`copied ${copied} file(s)`);
|
|
12074
|
-
const resolved = inStage("link", () => relink(linkPath,
|
|
12349
|
+
const resolved = inStage("link", () => relink(linkPath, join24(runtimeDir, RUNTIME_ENTRY)));
|
|
12075
12350
|
log(`${linkPath} resolves to ${resolved}`);
|
|
12076
12351
|
return { kind: "done", version: version2, runtimeDir, linkPath, resolved, copied };
|
|
12077
12352
|
}
|
|
@@ -12086,7 +12361,7 @@ function inStage(stage, run) {
|
|
|
12086
12361
|
}
|
|
12087
12362
|
function entryNames(dir) {
|
|
12088
12363
|
try {
|
|
12089
|
-
return
|
|
12364
|
+
return readdirSync5(dir);
|
|
12090
12365
|
} catch (err) {
|
|
12091
12366
|
if (typeof err === "object" && err !== null && "code" in err && err.code === "ENOENT")
|
|
12092
12367
|
return [];
|
|
@@ -12097,7 +12372,7 @@ function replaceFile(source, target) {
|
|
|
12097
12372
|
const temporary = temporaryName(target);
|
|
12098
12373
|
try {
|
|
12099
12374
|
copyFileSync3(source, temporary);
|
|
12100
|
-
chmodSync(temporary,
|
|
12375
|
+
chmodSync(temporary, statSync12(source).mode & 4095);
|
|
12101
12376
|
renameSync(temporary, target);
|
|
12102
12377
|
} catch (err) {
|
|
12103
12378
|
rmSync2(temporary, { force: true });
|
|
@@ -12105,7 +12380,7 @@ function replaceFile(source, target) {
|
|
|
12105
12380
|
}
|
|
12106
12381
|
}
|
|
12107
12382
|
function temporaryName(path) {
|
|
12108
|
-
return
|
|
12383
|
+
return join24(dirname4(path), `.${basename7(path)}.snapshot-${process.pid}`);
|
|
12109
12384
|
}
|
|
12110
12385
|
|
|
12111
12386
|
// src/commands/pr/merge-followups.ts
|
|
@@ -12281,8 +12556,8 @@ async function readUncheckedMerge(options) {
|
|
|
12281
12556
|
}
|
|
12282
12557
|
return Object.freeze({ workflowCount, reading, yes });
|
|
12283
12558
|
}
|
|
12284
|
-
function isYes2(
|
|
12285
|
-
return
|
|
12559
|
+
function isYes2(answer2) {
|
|
12560
|
+
return answer2 !== null && YES_ANSWERS3.includes(answer2.trim().toLowerCase());
|
|
12286
12561
|
}
|
|
12287
12562
|
async function confirmUncheckedMerge(unchecked, options) {
|
|
12288
12563
|
for (const line of unchecked.reading.warning)
|
|
@@ -12315,7 +12590,7 @@ async function postUncheckedComment(pulls, number, unchecked, warn) {
|
|
|
12315
12590
|
}
|
|
12316
12591
|
|
|
12317
12592
|
// src/commands/pr/merge.ts
|
|
12318
|
-
var
|
|
12593
|
+
var USAGE26 = PR_USAGE.merge;
|
|
12319
12594
|
var REMOTE3 = "origin";
|
|
12320
12595
|
var INDENT4 = " ";
|
|
12321
12596
|
var YES_ANSWERS4 = ["y", "yes"];
|
|
@@ -12373,8 +12648,8 @@ function requireTerminal(seams, summary) {
|
|
|
12373
12648
|
"Merge it without the question with --yes."
|
|
12374
12649
|
]);
|
|
12375
12650
|
}
|
|
12376
|
-
function isYes3(
|
|
12377
|
-
return
|
|
12651
|
+
function isYes3(answer2) {
|
|
12652
|
+
return answer2 !== null && YES_ANSWERS4.includes(answer2.trim().toLowerCase());
|
|
12378
12653
|
}
|
|
12379
12654
|
function prompterOf(seams) {
|
|
12380
12655
|
return seams.openPrompter ?? (() => createLinePrompter(process.stdin, process.stderr));
|
|
@@ -12396,13 +12671,13 @@ function remoteHoldsBranch(git, branch, warn) {
|
|
|
12396
12671
|
}
|
|
12397
12672
|
function textOf(path) {
|
|
12398
12673
|
try {
|
|
12399
|
-
return
|
|
12674
|
+
return readFileSync20(path, "utf8");
|
|
12400
12675
|
} catch {
|
|
12401
12676
|
return "";
|
|
12402
12677
|
}
|
|
12403
12678
|
}
|
|
12404
12679
|
function followUpsFor(pr, git) {
|
|
12405
|
-
const facts = readPackageFacts(textOf(
|
|
12680
|
+
const facts = readPackageFacts(textOf(join25(pr.project.root, "package.json")));
|
|
12406
12681
|
if (facts.version === null)
|
|
12407
12682
|
return [];
|
|
12408
12683
|
const tags = git(["tag", "--list", versionTag(facts.version)]);
|
|
@@ -12410,7 +12685,7 @@ function followUpsFor(pr, git) {
|
|
|
12410
12685
|
version: facts.version,
|
|
12411
12686
|
tagged: tags.ok && tags.stdout.trim() !== "",
|
|
12412
12687
|
rafaCheckout: facts.rafaCheckout,
|
|
12413
|
-
runtimeInstalled: existsSync9(
|
|
12688
|
+
runtimeInstalled: existsSync9(join25(pr.project.home, RUNTIME_SUBDIR, facts.version))
|
|
12414
12689
|
});
|
|
12415
12690
|
}
|
|
12416
12691
|
function openGh(pr, seams) {
|
|
@@ -12522,22 +12797,22 @@ async function commentIfUnchecked(context, pr, number, unchecked) {
|
|
|
12522
12797
|
return posted.url;
|
|
12523
12798
|
}
|
|
12524
12799
|
async function runMerge(context, seams) {
|
|
12525
|
-
const yes = readBooleanFlag(context.flags, "yes",
|
|
12526
|
-
const skipChecks = readBooleanFlag(context.flags, "skip-checks",
|
|
12527
|
-
const wanted = readMethodFlag(context.flags,
|
|
12528
|
-
const asked = readPullArgument(context.args,
|
|
12800
|
+
const yes = readBooleanFlag(context.flags, "yes", USAGE26);
|
|
12801
|
+
const skipChecks = readBooleanFlag(context.flags, "skip-checks", USAGE26);
|
|
12802
|
+
const wanted = readMethodFlag(context.flags, USAGE26);
|
|
12803
|
+
const asked = readPullArgument(context.args, USAGE26);
|
|
12529
12804
|
const pr = openPrContext(context, seams);
|
|
12530
12805
|
const git = (seams.git ?? createGitRunner)(pr.project.root);
|
|
12531
12806
|
const method = wanted ?? pr.mergeMethod;
|
|
12532
|
-
const pick = await pickPullRequest(pr, asked,
|
|
12807
|
+
const pick = await pickPullRequest(pr, asked, USAGE26);
|
|
12533
12808
|
const detail = await onProvider(`read pull request #${pick.number}`, () => pr.pulls.get(pick.number));
|
|
12534
12809
|
if (detail === null) {
|
|
12535
|
-
throw lineRefusal3(`No pull request #${pick.number} at ${pr.project.root}`,
|
|
12810
|
+
throw lineRefusal3(`No pull request #${pick.number} at ${pr.project.root}`, USAGE26);
|
|
12536
12811
|
}
|
|
12537
12812
|
const checks = await onProvider(`read the checks of #${pick.number}`, () => pr.pulls.checks(pick.number));
|
|
12538
12813
|
refuseFromGit(git, detail, checks, skipChecks);
|
|
12539
12814
|
const summary = summaryLine2(detail, method);
|
|
12540
|
-
const
|
|
12815
|
+
const answer2 = await askToMerge(context, pr, seams, { number: detail.number, summary, yes, skipChecks });
|
|
12541
12816
|
const answered3 = {
|
|
12542
12817
|
number: detail.number,
|
|
12543
12818
|
source: pick.source,
|
|
@@ -12552,9 +12827,9 @@ async function runMerge(context, seams) {
|
|
|
12552
12827
|
followUps: [],
|
|
12553
12828
|
roadmapTick: null,
|
|
12554
12829
|
unblocked: null,
|
|
12555
|
-
unchecked: uncheckedReport(
|
|
12830
|
+
unchecked: uncheckedReport(answer2.unchecked, null)
|
|
12556
12831
|
};
|
|
12557
|
-
if (!
|
|
12832
|
+
if (!answer2.go) {
|
|
12558
12833
|
context.output.info("Nothing was merged.");
|
|
12559
12834
|
return answered3;
|
|
12560
12835
|
}
|
|
@@ -12563,7 +12838,7 @@ async function runMerge(context, seams) {
|
|
|
12563
12838
|
throw refusal5([`\u274C ${pr.pulls.kind} would not merge #${detail.number}: ${outcome2.detail}`]);
|
|
12564
12839
|
}
|
|
12565
12840
|
context.output.info(`Merged #${detail.number} into ${detail.baseRefName} (${method}).`);
|
|
12566
|
-
const commentUrl = await commentIfUnchecked(context, pr, detail.number,
|
|
12841
|
+
const commentUrl = await commentIfUnchecked(context, pr, detail.number, answer2.unchecked);
|
|
12567
12842
|
const roadmapTick = await reportTick(context, pr, seams, detail);
|
|
12568
12843
|
const remoteBranchPresent = remoteHoldsBranch(git, detail.headRefName, (message) => {
|
|
12569
12844
|
context.output.warn(message);
|
|
@@ -12586,7 +12861,7 @@ async function runMerge(context, seams) {
|
|
|
12586
12861
|
followUps,
|
|
12587
12862
|
roadmapTick,
|
|
12588
12863
|
unblocked,
|
|
12589
|
-
unchecked: uncheckedReport(
|
|
12864
|
+
unchecked: uncheckedReport(answer2.unchecked, commentUrl)
|
|
12590
12865
|
};
|
|
12591
12866
|
}
|
|
12592
12867
|
function createPrMergeCommand(seams = DEFAULT_MERGE_SEAMS) {
|
|
@@ -13088,7 +13363,7 @@ function readLastTriage(comments) {
|
|
|
13088
13363
|
}
|
|
13089
13364
|
|
|
13090
13365
|
// src/commands/pr/show.ts
|
|
13091
|
-
var
|
|
13366
|
+
var USAGE27 = PR_USAGE.show;
|
|
13092
13367
|
var INDENT5 = " ";
|
|
13093
13368
|
var SHORT_SHA = 7;
|
|
13094
13369
|
function headLine4(detail) {
|
|
@@ -13186,12 +13461,12 @@ async function probe2(call) {
|
|
|
13186
13461
|
}
|
|
13187
13462
|
}
|
|
13188
13463
|
async function readShow(context, seams) {
|
|
13189
|
-
const asked = readPullArgument(context.args,
|
|
13464
|
+
const asked = readPullArgument(context.args, USAGE27);
|
|
13190
13465
|
const pr = openPrContext(context, seams);
|
|
13191
|
-
const pick = await pickPullRequest(pr, asked,
|
|
13466
|
+
const pick = await pickPullRequest(pr, asked, USAGE27);
|
|
13192
13467
|
const detail = await onProvider(`read pull request #${pick.number}`, () => pr.pulls.get(pick.number));
|
|
13193
13468
|
if (detail === null) {
|
|
13194
|
-
throw lineRefusal3(`No pull request #${pick.number} in the repository at ${pr.project.root}`,
|
|
13469
|
+
throw lineRefusal3(`No pull request #${pick.number} in the repository at ${pr.project.root}`, USAGE27);
|
|
13195
13470
|
}
|
|
13196
13471
|
const checks = await probe2(() => pr.pulls.checks(pick.number));
|
|
13197
13472
|
const comments = await probe2(() => pr.pulls.comments(pick.number));
|
|
@@ -14020,8 +14295,8 @@ function withTaskBudget(plan2, usd) {
|
|
|
14020
14295
|
}
|
|
14021
14296
|
|
|
14022
14297
|
// src/pr/plans/load.ts
|
|
14023
|
-
import { existsSync as existsSync10, readFileSync as
|
|
14024
|
-
import { dirname as dirname5, join as
|
|
14298
|
+
import { existsSync as existsSync10, readFileSync as readFileSync21 } from "fs";
|
|
14299
|
+
import { dirname as dirname5, join as join26 } from "path";
|
|
14025
14300
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
14026
14301
|
var MODULE_DIR2 = dirname5(fileURLToPath2(import.meta.url));
|
|
14027
14302
|
var PINNED_PLANS_DIRNAME = "plans";
|
|
@@ -14038,8 +14313,8 @@ function hasPinnedPlan(triageClass) {
|
|
|
14038
14313
|
function pinnedPlanCandidates(moduleDir, triageClass) {
|
|
14039
14314
|
const name2 = pinnedPlanFileName(triageClass);
|
|
14040
14315
|
return [
|
|
14041
|
-
|
|
14042
|
-
|
|
14316
|
+
join26(moduleDir, PINNED_PLANS_DIRNAME, name2),
|
|
14317
|
+
join26(moduleDir, name2)
|
|
14043
14318
|
];
|
|
14044
14319
|
}
|
|
14045
14320
|
function readPinnedPlan(triageClass, lookup = {}) {
|
|
@@ -14051,7 +14326,7 @@ function readPinnedPlan(triageClass, lookup = {}) {
|
|
|
14051
14326
|
if (found === undefined) {
|
|
14052
14327
|
throw new Error(`The pinned resolve plan for ${triageClass} is missing: ` + `no file at ${candidates.join(" or ")}`);
|
|
14053
14328
|
}
|
|
14054
|
-
return
|
|
14329
|
+
return readFileSync21(found, "utf8");
|
|
14055
14330
|
}
|
|
14056
14331
|
var SLOT_PATTERN = /\{[A-Z][A-Z0-9_]*\}/g;
|
|
14057
14332
|
var CONFLICT_SENTENCE_SLOT = "CONFLICT_SENTENCE";
|
|
@@ -14192,19 +14467,19 @@ function readAttemptRepeat(input) {
|
|
|
14192
14467
|
|
|
14193
14468
|
// src/commands/pr/resolve-loop.ts
|
|
14194
14469
|
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync6 } from "fs";
|
|
14195
|
-
import { join as
|
|
14196
|
-
var RESOLVE_SUBDIR =
|
|
14470
|
+
import { join as join27 } from "path";
|
|
14471
|
+
var RESOLVE_SUBDIR = join27(".rafa", "resolve");
|
|
14197
14472
|
var RUN_PREFIX = "pr-";
|
|
14198
14473
|
var ATTEMPT_PREFIX = "attempt-";
|
|
14199
14474
|
var LOOP_WORDS = Object.freeze(["loop", "start"]);
|
|
14200
14475
|
var CHILD_OUTPUT = "text";
|
|
14201
14476
|
function resolveRunDir(home, number, attempt3) {
|
|
14202
|
-
return
|
|
14477
|
+
return join27(home, RESOLVE_SUBDIR, `${RUN_PREFIX}${number}`, `${ATTEMPT_PREFIX}${attempt3}`);
|
|
14203
14478
|
}
|
|
14204
14479
|
function writeResolvePlan(write) {
|
|
14205
14480
|
const dir = resolveRunDir(write.home, write.number, write.attempt);
|
|
14206
14481
|
mkdirSync7(dir, { recursive: true });
|
|
14207
|
-
const path =
|
|
14482
|
+
const path = join27(dir, pinnedPlanFileName(write.triageClass));
|
|
14208
14483
|
writeFileSync6(path, write.plan, "utf8");
|
|
14209
14484
|
return path;
|
|
14210
14485
|
}
|
|
@@ -14563,7 +14838,7 @@ async function runAttempts(run, detail, first) {
|
|
|
14563
14838
|
}
|
|
14564
14839
|
|
|
14565
14840
|
// src/commands/pr/triage.ts
|
|
14566
|
-
var
|
|
14841
|
+
var USAGE28 = PR_USAGE.triage;
|
|
14567
14842
|
var DEFAULT_MAX_ATTEMPTS = 2;
|
|
14568
14843
|
var DETACHED_HEAD2 = "HEAD";
|
|
14569
14844
|
var RESOLVED = false;
|
|
@@ -14619,7 +14894,7 @@ async function selectTargets(pr, warn, now, resolve13) {
|
|
|
14619
14894
|
async function detailOf6(pr, number) {
|
|
14620
14895
|
const detail = await onProvider(`read pull request #${number}`, () => pr.pulls.get(number));
|
|
14621
14896
|
if (detail === null) {
|
|
14622
|
-
throw lineRefusal3(`No pull request #${number} in the repository at ${pr.project.root}`,
|
|
14897
|
+
throw lineRefusal3(`No pull request #${number} in the repository at ${pr.project.root}`, USAGE28);
|
|
14623
14898
|
}
|
|
14624
14899
|
return detail;
|
|
14625
14900
|
}
|
|
@@ -14714,14 +14989,14 @@ async function assessOne(options) {
|
|
|
14714
14989
|
function refuseResolveWithoutComment(wantsResolve, wantsComment) {
|
|
14715
14990
|
if (!wantsResolve || wantsComment)
|
|
14716
14991
|
return;
|
|
14717
|
-
throw lineRefusal3("--resolve writes the attempt count into the triage comment, and --no-comment writes none;" + " run one or the other",
|
|
14992
|
+
throw lineRefusal3("--resolve writes the attempt count into the triage comment, and --no-comment writes none;" + " run one or the other", USAGE28);
|
|
14718
14993
|
}
|
|
14719
14994
|
async function runTriage(context, seams) {
|
|
14720
|
-
const wantsComment = readBooleanFlag(context.flags, "comment",
|
|
14721
|
-
const wantsResolve = readBooleanFlag(context.flags, "resolve",
|
|
14722
|
-
const maxAttempts = readMaxAttempts(context.flags,
|
|
14995
|
+
const wantsComment = readBooleanFlag(context.flags, "comment", USAGE28, true);
|
|
14996
|
+
const wantsResolve = readBooleanFlag(context.flags, "resolve", USAGE28, false);
|
|
14997
|
+
const maxAttempts = readMaxAttempts(context.flags, USAGE28);
|
|
14723
14998
|
refuseResolveWithoutComment(wantsResolve, wantsComment);
|
|
14724
|
-
const asked = readPullArgument(context.args,
|
|
14999
|
+
const asked = readPullArgument(context.args, USAGE28);
|
|
14725
15000
|
const pr = openPrContext(context, seams);
|
|
14726
15001
|
const git = (seams.git ?? createGitRunner)(pr.project.root);
|
|
14727
15002
|
const permissions = (seams.permissions ?? ghPermissionsIn)(pr.project.root);
|
|
@@ -14854,7 +15129,7 @@ function createPrTriageCommand(seams = DEFAULT_TRIAGE_SEAMS) {
|
|
|
14854
15129
|
var triage_default = createPrTriageCommand();
|
|
14855
15130
|
|
|
14856
15131
|
// src/commands/pr/view.ts
|
|
14857
|
-
var
|
|
15132
|
+
var USAGE29 = PR_USAGE.view;
|
|
14858
15133
|
function trimmedOrNull3(value) {
|
|
14859
15134
|
const trimmed = value.trim();
|
|
14860
15135
|
return trimmed === "" ? null : trimmed;
|
|
@@ -14864,9 +15139,9 @@ function renderView(number, url) {
|
|
|
14864
15139
|
return url === null ? opened : `${opened}${SEPARATOR}${url}`;
|
|
14865
15140
|
}
|
|
14866
15141
|
async function runView2(context, seams) {
|
|
14867
|
-
const asked = readPullArgument(context.args,
|
|
15142
|
+
const asked = readPullArgument(context.args, USAGE29);
|
|
14868
15143
|
const pr = openPrContext(context, seams);
|
|
14869
|
-
const pick = await pickPullRequest(pr, asked,
|
|
15144
|
+
const pick = await pickPullRequest(pr, asked, USAGE29);
|
|
14870
15145
|
await onProvider(`open pull request #${pick.number} in the browser`, () => pr.pulls.browse(pick.number));
|
|
14871
15146
|
const url = trimmedOrNull3(pick.summary?.url ?? "");
|
|
14872
15147
|
return {
|
|
@@ -14921,7 +15196,7 @@ function createPrViewCommand(seams = DEFAULT_PR_SEAMS) {
|
|
|
14921
15196
|
var view_default = createPrViewCommand();
|
|
14922
15197
|
|
|
14923
15198
|
// src/commands/pr/wait.ts
|
|
14924
|
-
var
|
|
15199
|
+
var USAGE30 = PR_USAGE.wait;
|
|
14925
15200
|
var TIMEOUT_FLAG = "timeout";
|
|
14926
15201
|
var DEFAULT_WAIT_TIMEOUT_MIN = DEFAULT_CI_TIMEOUT_MIN;
|
|
14927
15202
|
var MS_PER_MIN = 60000;
|
|
@@ -14987,10 +15262,10 @@ function renderWait(reading) {
|
|
|
14987
15262
|
`);
|
|
14988
15263
|
}
|
|
14989
15264
|
async function runWait(context, seams) {
|
|
14990
|
-
const minutes = readTimeoutMinutes(context.flags,
|
|
14991
|
-
const asked = readPullArgument(context.args,
|
|
15265
|
+
const minutes = readTimeoutMinutes(context.flags, USAGE30);
|
|
15266
|
+
const asked = readPullArgument(context.args, USAGE30);
|
|
14992
15267
|
const pr = openPrContext(context, seams);
|
|
14993
|
-
const pick = await pickPullRequest(pr, asked,
|
|
15268
|
+
const pick = await pickPullRequest(pr, asked, USAGE30);
|
|
14994
15269
|
const timeoutMs = minutes * MS_PER_MIN;
|
|
14995
15270
|
context.output.info(`Waiting for the checks of #${pick.number}, up to ${minutes} min.`);
|
|
14996
15271
|
const waited = await waitForChecks({
|
|
@@ -15069,8 +15344,8 @@ function createPrWaitCommand(seams = DEFAULT_WAIT_SEAMS) {
|
|
|
15069
15344
|
var wait_default = createPrWaitCommand();
|
|
15070
15345
|
|
|
15071
15346
|
// src/commands/release/status.ts
|
|
15072
|
-
import { existsSync as existsSync11, readdirSync as
|
|
15073
|
-
import { join as
|
|
15347
|
+
import { existsSync as existsSync11, readdirSync as readdirSync6, readFileSync as readFileSync22 } from "fs";
|
|
15348
|
+
import { join as join28 } from "path";
|
|
15074
15349
|
var RELEASE_STATUS_USAGE = "rafa release status [--plan=<stub>]";
|
|
15075
15350
|
var UNREADABLE3 = "?";
|
|
15076
15351
|
var NOTHING = "none";
|
|
@@ -15171,13 +15446,13 @@ function untaggedVersions(released, tags) {
|
|
|
15171
15446
|
}
|
|
15172
15447
|
function textOf2(path) {
|
|
15173
15448
|
try {
|
|
15174
|
-
return
|
|
15449
|
+
return readFileSync22(path, "utf8");
|
|
15175
15450
|
} catch {
|
|
15176
15451
|
return null;
|
|
15177
15452
|
}
|
|
15178
15453
|
}
|
|
15179
15454
|
function readVersionFile(root, configured) {
|
|
15180
|
-
const resolved =
|
|
15455
|
+
const resolved = join28(root, configured);
|
|
15181
15456
|
const text = textOf2(resolved);
|
|
15182
15457
|
if (text === null) {
|
|
15183
15458
|
return { path: configured, version: null, problem: `the version file could not be read at ${resolved}` };
|
|
@@ -15194,7 +15469,7 @@ function readTags(git) {
|
|
|
15194
15469
|
return { tags, latest: tags[0] ?? null, problem: null };
|
|
15195
15470
|
}
|
|
15196
15471
|
function readUntagged(root, configured, tags) {
|
|
15197
|
-
const resolved =
|
|
15472
|
+
const resolved = join28(root, configured);
|
|
15198
15473
|
const text = textOf2(resolved);
|
|
15199
15474
|
if (text === null) {
|
|
15200
15475
|
return {
|
|
@@ -15213,11 +15488,11 @@ function readBranch2(git) {
|
|
|
15213
15488
|
return result.ok && branch !== "" && branch !== "HEAD" ? branch : null;
|
|
15214
15489
|
}
|
|
15215
15490
|
function planStubsUnder(root, planDir) {
|
|
15216
|
-
const resolved =
|
|
15491
|
+
const resolved = join28(root, planDir);
|
|
15217
15492
|
if (!existsSync11(resolved))
|
|
15218
15493
|
return [];
|
|
15219
15494
|
try {
|
|
15220
|
-
return planStubsFromFileNames(
|
|
15495
|
+
return planStubsFromFileNames(readdirSync6(resolved));
|
|
15221
15496
|
} catch {
|
|
15222
15497
|
return [];
|
|
15223
15498
|
}
|
|
@@ -15415,8 +15690,8 @@ function createReleaseStatusCommand(seams = DEFAULT_RELEASE_SEAMS) {
|
|
|
15415
15690
|
var status_default2 = createReleaseStatusCommand();
|
|
15416
15691
|
|
|
15417
15692
|
// src/commands/release/tag.ts
|
|
15418
|
-
import { readFileSync as
|
|
15419
|
-
import { join as
|
|
15693
|
+
import { readFileSync as readFileSync23 } from "fs";
|
|
15694
|
+
import { join as join29 } from "path";
|
|
15420
15695
|
var RELEASE_TAG_USAGE = "rafa release tag";
|
|
15421
15696
|
var DEFAULT_RELEASE_BRANCH = "main";
|
|
15422
15697
|
var DEFAULT_REGISTRY = "https://registry.npmjs.org";
|
|
@@ -15435,13 +15710,13 @@ function readBranch3(git) {
|
|
|
15435
15710
|
}
|
|
15436
15711
|
function textOf3(path) {
|
|
15437
15712
|
try {
|
|
15438
|
-
return
|
|
15713
|
+
return readFileSync23(path, "utf8");
|
|
15439
15714
|
} catch {
|
|
15440
15715
|
return null;
|
|
15441
15716
|
}
|
|
15442
15717
|
}
|
|
15443
15718
|
function readVersion(root, configured) {
|
|
15444
|
-
const resolved =
|
|
15719
|
+
const resolved = join29(root, configured);
|
|
15445
15720
|
const text = textOf3(resolved);
|
|
15446
15721
|
if (text === null) {
|
|
15447
15722
|
return {
|
|
@@ -15455,7 +15730,7 @@ function readVersion(root, configured) {
|
|
|
15455
15730
|
return version2 === null ? { path: configured, text, version: null, problem: `${resolved} declares no version this can read` } : { path: configured, text, version: version2, problem: null };
|
|
15456
15731
|
}
|
|
15457
15732
|
function readNewestRelease(root, configured) {
|
|
15458
|
-
const resolved =
|
|
15733
|
+
const resolved = join29(root, configured);
|
|
15459
15734
|
const text = textOf3(resolved);
|
|
15460
15735
|
if (text === null) {
|
|
15461
15736
|
return { path: configured, version: null, problem: `the changelog could not be read at ${resolved}` };
|
|
@@ -15676,14 +15951,14 @@ var roadmap_default = createRoadmapCommand();
|
|
|
15676
15951
|
|
|
15677
15952
|
// src/commands/self-update.ts
|
|
15678
15953
|
var DEFAULT_SELF_UPDATE_SEAMS = Object.freeze({ build: runBuild });
|
|
15679
|
-
var
|
|
15954
|
+
var USAGE31 = "rafa self-update [--force]";
|
|
15680
15955
|
function readForceFlag(value) {
|
|
15681
15956
|
if (value === undefined || value === false || value === "false")
|
|
15682
15957
|
return false;
|
|
15683
15958
|
if (value === true || value === "true")
|
|
15684
15959
|
return true;
|
|
15685
15960
|
throw new CommandExit(1, `\u274C --force takes no value, and read "${value}" as one
|
|
15686
|
-
Usage: ${
|
|
15961
|
+
Usage: ${USAGE31}`);
|
|
15687
15962
|
}
|
|
15688
15963
|
function projectOf11(context) {
|
|
15689
15964
|
if (context.project === null)
|
|
@@ -15691,7 +15966,7 @@ function projectOf11(context) {
|
|
|
15691
15966
|
return context.project;
|
|
15692
15967
|
}
|
|
15693
15968
|
async function runSelfUpdate(context, seams) {
|
|
15694
|
-
expectNoArgument(context.args,
|
|
15969
|
+
expectNoArgument(context.args, USAGE31);
|
|
15695
15970
|
const force = readForceFlag(context.flags["force"]);
|
|
15696
15971
|
const project = projectOf11(context);
|
|
15697
15972
|
const info = (line) => context.output.info(line);
|
|
@@ -15749,17 +16024,17 @@ function createSelfUpdateCommand(seams = DEFAULT_SELF_UPDATE_SEAMS) {
|
|
|
15749
16024
|
var self_update_default = createSelfUpdateCommand();
|
|
15750
16025
|
|
|
15751
16026
|
// src/commands/skill/backfill.ts
|
|
15752
|
-
import { statSync as
|
|
15753
|
-
import { join as
|
|
16027
|
+
import { statSync as statSync14 } from "fs";
|
|
16028
|
+
import { join as join34, resolve as resolve15 } from "path";
|
|
15754
16029
|
|
|
15755
16030
|
// src/backfill/backup.ts
|
|
15756
16031
|
import { copyFileSync as copyFileSync4, existsSync as existsSync12, mkdirSync as mkdirSync8 } from "fs";
|
|
15757
|
-
import { dirname as dirname6, isAbsolute as isAbsolute8, join as
|
|
16032
|
+
import { dirname as dirname6, isAbsolute as isAbsolute8, join as join31, relative as relative8, resolve as resolve13, sep as sep5 } from "path";
|
|
15758
16033
|
|
|
15759
16034
|
// src/backfill/proposal-file.ts
|
|
15760
|
-
import { readdirSync as
|
|
15761
|
-
import { join as
|
|
15762
|
-
var BACKFILL_PATH =
|
|
16035
|
+
import { readdirSync as readdirSync7, readFileSync as readFileSync24 } from "fs";
|
|
16036
|
+
import { join as join30 } from "path";
|
|
16037
|
+
var BACKFILL_PATH = join30(".rafa", "backfill");
|
|
15763
16038
|
var PROPOSAL_FILE_PREFIX = "proposals-";
|
|
15764
16039
|
var PROPOSAL_FILE_EXTENSION = ".yaml";
|
|
15765
16040
|
var SHA256_PATTERN = /^[0-9a-f]{64}$/;
|
|
@@ -15785,7 +16060,7 @@ var PROPOSAL_FILE_HEADER = [
|
|
|
15785
16060
|
].join(`
|
|
15786
16061
|
`);
|
|
15787
16062
|
function proposalPath(dir, batch) {
|
|
15788
|
-
return
|
|
16063
|
+
return join30(dir, `${PROPOSAL_FILE_PREFIX}${String(batch).padStart(2, "0")}${PROPOSAL_FILE_EXTENSION}`);
|
|
15789
16064
|
}
|
|
15790
16065
|
function isProposalFileName(name2) {
|
|
15791
16066
|
return name2.startsWith(PROPOSAL_FILE_PREFIX) && name2.endsWith(PROPOSAL_FILE_EXTENSION);
|
|
@@ -15916,14 +16191,14 @@ function parseProposalFile(text) {
|
|
|
15916
16191
|
function readProposalFiles(dir) {
|
|
15917
16192
|
let names;
|
|
15918
16193
|
try {
|
|
15919
|
-
names =
|
|
16194
|
+
names = readdirSync7(dir);
|
|
15920
16195
|
} catch {
|
|
15921
16196
|
return [];
|
|
15922
16197
|
}
|
|
15923
16198
|
return names.filter((name2) => isProposalFileName(name2)).sort((left, right) => left.localeCompare(right)).map((name2) => {
|
|
15924
|
-
const path =
|
|
16199
|
+
const path = join30(dir, name2);
|
|
15925
16200
|
try {
|
|
15926
|
-
return { path, result: parseProposalFile(
|
|
16201
|
+
return { path, result: parseProposalFile(readFileSync24(path, "utf8")) };
|
|
15927
16202
|
} catch (error) {
|
|
15928
16203
|
return { path, result: unreadable(`the file cannot be read (${error instanceof Error ? error.message : String(error)})`) };
|
|
15929
16204
|
}
|
|
@@ -15931,10 +16206,10 @@ function readProposalFiles(dir) {
|
|
|
15931
16206
|
}
|
|
15932
16207
|
|
|
15933
16208
|
// src/backfill/backup.ts
|
|
15934
|
-
var BACKUP_PATH =
|
|
16209
|
+
var BACKUP_PATH = join31(BACKFILL_PATH, "backup");
|
|
15935
16210
|
var BACKUP_KINDS = ["copied", "kept", "tracked", "outside", "missing"];
|
|
15936
16211
|
function backupDirectory(base) {
|
|
15937
|
-
return
|
|
16212
|
+
return join31(base, BACKUP_PATH);
|
|
15938
16213
|
}
|
|
15939
16214
|
function isUnder(root, path) {
|
|
15940
16215
|
const step = relative8(resolve13(root), resolve13(path));
|
|
@@ -15943,7 +16218,7 @@ function isUnder(root, path) {
|
|
|
15943
16218
|
function backupPathFor(path, root, backupDir) {
|
|
15944
16219
|
if (!isUnder(root, path))
|
|
15945
16220
|
return null;
|
|
15946
|
-
return
|
|
16221
|
+
return join31(backupDir, relative8(resolve13(root), resolve13(path)));
|
|
15947
16222
|
}
|
|
15948
16223
|
function backupFile(path, options) {
|
|
15949
16224
|
if (options.repoRoot !== null && isUnder(options.repoRoot, path)) {
|
|
@@ -15979,348 +16254,8 @@ function countBackups(results) {
|
|
|
15979
16254
|
}
|
|
15980
16255
|
|
|
15981
16256
|
// src/backfill/derive.ts
|
|
15982
|
-
import { readFileSync as
|
|
16257
|
+
import { readFileSync as readFileSync25, writeFileSync as writeFileSync7 } from "fs";
|
|
15983
16258
|
import { basename as basename8 } from "path";
|
|
15984
|
-
|
|
15985
|
-
// src/demote/classify.ts
|
|
15986
|
-
var LEARNED_DIRECTORY = "learned";
|
|
15987
|
-
var ORIGIN_FIELD = "origin";
|
|
15988
|
-
var DEMOTION_VERDICTS = [
|
|
15989
|
-
"observation",
|
|
15990
|
-
"procedure",
|
|
15991
|
-
"unclassified"
|
|
15992
|
-
];
|
|
15993
|
-
var RULE_VERDICTS = Object.freeze({
|
|
15994
|
-
"no-frontmatter": "unclassified",
|
|
15995
|
-
"learned-without-origin": "unclassified",
|
|
15996
|
-
"no-section-pair": "unclassified",
|
|
15997
|
-
"repeated-section": "procedure",
|
|
15998
|
-
"numbered-procedure": "procedure",
|
|
15999
|
-
"referenced-script": "procedure",
|
|
16000
|
-
"observation-shape": "observation"
|
|
16001
|
-
});
|
|
16002
|
-
var PROCEDURE_STEP_MINIMUM = 3;
|
|
16003
|
-
var PROBLEM_HEADING = /^(?:the\s+)?problem\b/i;
|
|
16004
|
-
var SOLUTION_HEADING = /^(?:the\s+)?solution\b/i;
|
|
16005
|
-
var WHEN_TO_USE_HEADING = /^when\s+to\s+use\b/i;
|
|
16006
|
-
var EXTRACTED_LINE = /^\s*\*\*Extracted:\*\*\s*(\S+)/m;
|
|
16007
|
-
var SCRIPT_EXTENSIONS = [
|
|
16008
|
-
".sh",
|
|
16009
|
-
".bash",
|
|
16010
|
-
".zsh",
|
|
16011
|
-
".py",
|
|
16012
|
-
".rb",
|
|
16013
|
-
".pl",
|
|
16014
|
-
".js",
|
|
16015
|
-
".mjs",
|
|
16016
|
-
".cjs",
|
|
16017
|
-
".ts"
|
|
16018
|
-
];
|
|
16019
|
-
var FENCE_LINE = /^ {0,3}(?:```|~~~)/;
|
|
16020
|
-
var HEADING_LINE = /^ {0,3}(#{1,6})\s+(.*)$/;
|
|
16021
|
-
var NUMBERED_ITEM = /^ {0,3}\d+[.)]\s+\S/;
|
|
16022
|
-
var CONTINUATION = /^ {2,}\S/;
|
|
16023
|
-
var DEMOTED_SOURCE = "demoted";
|
|
16024
|
-
var DEMOTED_CONFIDENCE = 0.5;
|
|
16025
|
-
var DEMOTED_KIND = "gotcha";
|
|
16026
|
-
var DEMOTED_SIGNAL = "silent";
|
|
16027
|
-
var DEMOTED_USAGE_COUNT = 1;
|
|
16028
|
-
var EVIDENCE_PATH_KEY = "path";
|
|
16029
|
-
var EVIDENCE_EXTRACTED_KEY = "extracted";
|
|
16030
|
-
var DEFAULT_DOMAIN = "general-best-practices";
|
|
16031
|
-
var DOMAIN_MARKERS = [
|
|
16032
|
-
["security", /\b(?:security|secret|credential|token|auth|csrf|xss|injection)\b/i],
|
|
16033
|
-
["testing", /\b(?:test|tests|testing|spec|assertion|assert|mock|stub|fixture|coverage)\b/i],
|
|
16034
|
-
["git", /\b(?:git|commit|rebase|worktree|branch|merge|checkout)\b/i],
|
|
16035
|
-
["debugging", /\b(?:debug|debugging|traceback|reproduce|bisect)\b/i],
|
|
16036
|
-
["code-style", /\b(?:lint|eslint|format|formatter|prettier|naming)\b/i],
|
|
16037
|
-
["workflow", /\b(?:workflow|pipeline|release|deploy|build|ci|loop|dispatch)\b/i]
|
|
16038
|
-
];
|
|
16039
|
-
var ERROR_WORDS = /\b(?:error|exception|traceback|panic|fatal|refused|denied|not found|no such|cannot|could not|failed|failure|unexpected|undefined)\b/i;
|
|
16040
|
-
var SENTENCE_ABBREVIATIONS = ["e.g", "i.e", "vs", "cf", "etc"];
|
|
16041
|
-
function isFilled(value) {
|
|
16042
|
-
return typeof value === "string" && value.trim() !== "";
|
|
16043
|
-
}
|
|
16044
|
-
function bodyLines2(body) {
|
|
16045
|
-
return body.split(`
|
|
16046
|
-
`).map((line) => line.replace(/\r$/, ""));
|
|
16047
|
-
}
|
|
16048
|
-
function bodySections(body) {
|
|
16049
|
-
const lines2 = bodyLines2(body);
|
|
16050
|
-
const headings = [];
|
|
16051
|
-
let fenced = false;
|
|
16052
|
-
lines2.forEach((line, index) => {
|
|
16053
|
-
if (FENCE_LINE.test(line)) {
|
|
16054
|
-
fenced = !fenced;
|
|
16055
|
-
return;
|
|
16056
|
-
}
|
|
16057
|
-
if (fenced)
|
|
16058
|
-
return;
|
|
16059
|
-
const match = HEADING_LINE.exec(line);
|
|
16060
|
-
if (match === null)
|
|
16061
|
-
return;
|
|
16062
|
-
const [, hashes = "", title = ""] = match;
|
|
16063
|
-
headings.push({
|
|
16064
|
-
level: hashes.length,
|
|
16065
|
-
title: title.replace(/\s+#+\s*$/, "").trim(),
|
|
16066
|
-
index
|
|
16067
|
-
});
|
|
16068
|
-
});
|
|
16069
|
-
return headings.map((heading, position) => {
|
|
16070
|
-
const next = headings.slice(position + 1).find((other) => other.level <= heading.level);
|
|
16071
|
-
const end = next === undefined ? lines2.length : next.index;
|
|
16072
|
-
return {
|
|
16073
|
-
level: heading.level,
|
|
16074
|
-
title: heading.title,
|
|
16075
|
-
line: heading.index + 1,
|
|
16076
|
-
text: lines2.slice(heading.index + 1, end).join(`
|
|
16077
|
-
`).trim()
|
|
16078
|
-
};
|
|
16079
|
-
});
|
|
16080
|
-
}
|
|
16081
|
-
function numberedRuns(body) {
|
|
16082
|
-
const runs = [];
|
|
16083
|
-
let fenced = false;
|
|
16084
|
-
let steps = 0;
|
|
16085
|
-
let line = 0;
|
|
16086
|
-
const close = () => {
|
|
16087
|
-
if (steps > 0)
|
|
16088
|
-
runs.push({ steps, line });
|
|
16089
|
-
steps = 0;
|
|
16090
|
-
};
|
|
16091
|
-
bodyLines2(body).forEach((text, index) => {
|
|
16092
|
-
if (FENCE_LINE.test(text)) {
|
|
16093
|
-
fenced = !fenced;
|
|
16094
|
-
return;
|
|
16095
|
-
}
|
|
16096
|
-
if (fenced || text.trim() === "")
|
|
16097
|
-
return;
|
|
16098
|
-
if (NUMBERED_ITEM.test(text)) {
|
|
16099
|
-
if (steps === 0)
|
|
16100
|
-
line = index + 1;
|
|
16101
|
-
steps += 1;
|
|
16102
|
-
return;
|
|
16103
|
-
}
|
|
16104
|
-
if (CONTINUATION.test(text))
|
|
16105
|
-
return;
|
|
16106
|
-
close();
|
|
16107
|
-
});
|
|
16108
|
-
close();
|
|
16109
|
-
return runs;
|
|
16110
|
-
}
|
|
16111
|
-
function isScriptPath(token) {
|
|
16112
|
-
if (token.startsWith("/"))
|
|
16113
|
-
return false;
|
|
16114
|
-
const last = token.split("/").at(-1) ?? "";
|
|
16115
|
-
return SCRIPT_EXTENSIONS.some((extension) => last.endsWith(extension));
|
|
16116
|
-
}
|
|
16117
|
-
function referencedScript(body, entries = []) {
|
|
16118
|
-
const owned = new Set(entries.map((entry) => entry.replace(/^\.\//, "")));
|
|
16119
|
-
for (const reference of collectReferences(body)) {
|
|
16120
|
-
if (reference.kind !== "path")
|
|
16121
|
-
continue;
|
|
16122
|
-
const token = reference.text.replace(/^\.\//, "");
|
|
16123
|
-
const [first = ""] = token.split("/");
|
|
16124
|
-
if (owned.has(first) && isScriptPath(token))
|
|
16125
|
-
return reference;
|
|
16126
|
-
}
|
|
16127
|
-
return null;
|
|
16128
|
-
}
|
|
16129
|
-
function isLearnedFile(path) {
|
|
16130
|
-
const [first] = path.split(/[\\/]/);
|
|
16131
|
-
return first === LEARNED_DIRECTORY;
|
|
16132
|
-
}
|
|
16133
|
-
function decide2(rule, reason) {
|
|
16134
|
-
return { verdict: RULE_VERDICTS[rule], rule, reason };
|
|
16135
|
-
}
|
|
16136
|
-
function pairReason(problems, solutions) {
|
|
16137
|
-
if (problems === 0 && solutions === 0) {
|
|
16138
|
-
return "the body carries no Problem section and no Solution section";
|
|
16139
|
-
}
|
|
16140
|
-
return problems === 0 ? "the body carries a Solution section and no Problem section, so there is no pair" : "the body carries a Problem section and no Solution section, so there is no pair";
|
|
16141
|
-
}
|
|
16142
|
-
function repeatReason(problems, solutions) {
|
|
16143
|
-
const counted3 = problems > 1 ? `${problems} Problem sections` : `${solutions} Solution sections`;
|
|
16144
|
-
return `the body carries ${counted3}, and an observation carries exactly one of each`;
|
|
16145
|
-
}
|
|
16146
|
-
function classifySkill(source) {
|
|
16147
|
-
const document = readFrontmatterDocument(source.text);
|
|
16148
|
-
if (document === null) {
|
|
16149
|
-
return decide2("no-frontmatter", "the file opens with no --- block holding a YAML mapping");
|
|
16150
|
-
}
|
|
16151
|
-
if (isLearnedFile(source.path) && !isFilled(document.data[ORIGIN_FIELD])) {
|
|
16152
|
-
return decide2("learned-without-origin", `a ${LEARNED_DIRECTORY}/ file whose frontmatter carries no ${ORIGIN_FIELD}`);
|
|
16153
|
-
}
|
|
16154
|
-
const sections = bodySections(document.body);
|
|
16155
|
-
const problems = sections.filter((section) => PROBLEM_HEADING.test(section.title));
|
|
16156
|
-
const solutions = sections.filter((section) => SOLUTION_HEADING.test(section.title));
|
|
16157
|
-
if (problems.length === 0 || solutions.length === 0) {
|
|
16158
|
-
return decide2("no-section-pair", pairReason(problems.length, solutions.length));
|
|
16159
|
-
}
|
|
16160
|
-
if (problems.length > 1 || solutions.length > 1) {
|
|
16161
|
-
return decide2("repeated-section", repeatReason(problems.length, solutions.length));
|
|
16162
|
-
}
|
|
16163
|
-
const run = numberedRuns(document.body).find((each) => each.steps >= PROCEDURE_STEP_MINIMUM);
|
|
16164
|
-
if (run !== undefined) {
|
|
16165
|
-
return decide2("numbered-procedure", `a numbered procedure of ${run.steps} consecutive steps at line ${run.line}`);
|
|
16166
|
-
}
|
|
16167
|
-
const script = referencedScript(document.body, source.entries ?? []);
|
|
16168
|
-
if (script !== null) {
|
|
16169
|
-
return decide2("referenced-script", `the body names the script ${script.text} at line ${script.line}`);
|
|
16170
|
-
}
|
|
16171
|
-
return decide2("observation-shape", "one Problem section and one Solution section, no numbered procedure of " + `${PROCEDURE_STEP_MINIMUM} or more consecutive steps, and no referenced script`);
|
|
16172
|
-
}
|
|
16173
|
-
function firstSection(sections, heading) {
|
|
16174
|
-
return sections.find((section) => heading.test(section.title));
|
|
16175
|
-
}
|
|
16176
|
-
function withoutFences(text) {
|
|
16177
|
-
const kept = [];
|
|
16178
|
-
let fenced = false;
|
|
16179
|
-
for (const line of bodyLines2(text)) {
|
|
16180
|
-
if (FENCE_LINE.test(line)) {
|
|
16181
|
-
fenced = !fenced;
|
|
16182
|
-
continue;
|
|
16183
|
-
}
|
|
16184
|
-
if (!fenced)
|
|
16185
|
-
kept.push(line);
|
|
16186
|
-
}
|
|
16187
|
-
return kept;
|
|
16188
|
-
}
|
|
16189
|
-
function stripMarkers(line) {
|
|
16190
|
-
return line.replace(/^\s*(?:[-*+]|\d+[.)]|>)\s+/, "").replace(/\*\*|__|\*|`/g, "").trim();
|
|
16191
|
-
}
|
|
16192
|
-
function isAbbreviation(text, index) {
|
|
16193
|
-
const before = text.slice(0, index);
|
|
16194
|
-
return SENTENCE_ABBREVIATIONS.some((word) => before.toLowerCase().endsWith(word));
|
|
16195
|
-
}
|
|
16196
|
-
function firstSentence(text) {
|
|
16197
|
-
const lines2 = withoutFences(text);
|
|
16198
|
-
const start2 = lines2.findIndex((line) => line.trim() !== "");
|
|
16199
|
-
if (start2 === -1)
|
|
16200
|
-
return "";
|
|
16201
|
-
const collected = [lines2[start2] ?? ""];
|
|
16202
|
-
for (const line of lines2.slice(start2 + 1)) {
|
|
16203
|
-
if (line.trim() === "" || /^\s*(?:[-*+]|\d+[.)]|#)/.test(line))
|
|
16204
|
-
break;
|
|
16205
|
-
collected.push(line);
|
|
16206
|
-
}
|
|
16207
|
-
const joined2 = stripMarkers(collected.join(" ")).replace(/\s+/g, " ");
|
|
16208
|
-
for (let index = 0;index < joined2.length; index += 1) {
|
|
16209
|
-
if (!".!?".includes(joined2[index] ?? ""))
|
|
16210
|
-
continue;
|
|
16211
|
-
if (isAbbreviation(joined2, index))
|
|
16212
|
-
continue;
|
|
16213
|
-
const next = joined2[index + 1];
|
|
16214
|
-
if (next === undefined)
|
|
16215
|
-
return joined2.slice(0, index + 1).trim();
|
|
16216
|
-
if (next === " ")
|
|
16217
|
-
return joined2.slice(0, index + 1).trim();
|
|
16218
|
-
}
|
|
16219
|
-
return joined2.trim();
|
|
16220
|
-
}
|
|
16221
|
-
function demotedTrigger(sections, data) {
|
|
16222
|
-
const whenToUse = firstSection(sections, WHEN_TO_USE_HEADING);
|
|
16223
|
-
const fromSection = whenToUse === undefined ? "" : firstSentence(whenToUse.text);
|
|
16224
|
-
if (fromSection !== "")
|
|
16225
|
-
return fromSection;
|
|
16226
|
-
const description = data["description"];
|
|
16227
|
-
if (isFilled(description))
|
|
16228
|
-
return description.trim();
|
|
16229
|
-
const problem2 = firstSection(sections, PROBLEM_HEADING);
|
|
16230
|
-
return problem2 === undefined ? "" : firstSentence(problem2.text);
|
|
16231
|
-
}
|
|
16232
|
-
function extractedDate(body) {
|
|
16233
|
-
const match = EXTRACTED_LINE.exec(body);
|
|
16234
|
-
return match?.[1] ?? null;
|
|
16235
|
-
}
|
|
16236
|
-
function errorString(body) {
|
|
16237
|
-
let fenced = false;
|
|
16238
|
-
for (const line of bodyLines2(body)) {
|
|
16239
|
-
if (FENCE_LINE.test(line)) {
|
|
16240
|
-
fenced = !fenced;
|
|
16241
|
-
continue;
|
|
16242
|
-
}
|
|
16243
|
-
if (fenced) {
|
|
16244
|
-
if (ERROR_WORDS.test(line))
|
|
16245
|
-
return line.trim();
|
|
16246
|
-
continue;
|
|
16247
|
-
}
|
|
16248
|
-
for (const span of line.matchAll(/`([^`\n]+)`/g)) {
|
|
16249
|
-
const inner = span[1] ?? "";
|
|
16250
|
-
if (ERROR_WORDS.test(inner))
|
|
16251
|
-
return inner.trim();
|
|
16252
|
-
}
|
|
16253
|
-
}
|
|
16254
|
-
return null;
|
|
16255
|
-
}
|
|
16256
|
-
function inferDomain(name2, body) {
|
|
16257
|
-
for (const [domain, pattern] of DOMAIN_MARKERS) {
|
|
16258
|
-
if (pattern.test(name2))
|
|
16259
|
-
return domain;
|
|
16260
|
-
}
|
|
16261
|
-
for (const [domain, pattern] of DOMAIN_MARKERS) {
|
|
16262
|
-
if (pattern.test(body))
|
|
16263
|
-
return domain;
|
|
16264
|
-
}
|
|
16265
|
-
return DEFAULT_DOMAIN;
|
|
16266
|
-
}
|
|
16267
|
-
function slugifyId(value) {
|
|
16268
|
-
return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
16269
|
-
}
|
|
16270
|
-
function uniqueInstinctId(base, taken) {
|
|
16271
|
-
const used = new Set(taken);
|
|
16272
|
-
if (!used.has(base))
|
|
16273
|
-
return base;
|
|
16274
|
-
let suffix = 2;
|
|
16275
|
-
while (used.has(`${base}-${suffix}`))
|
|
16276
|
-
suffix += 1;
|
|
16277
|
-
return `${base}-${suffix}`;
|
|
16278
|
-
}
|
|
16279
|
-
function sourceName(source, data) {
|
|
16280
|
-
const declared = data["name"];
|
|
16281
|
-
if (isFilled(declared))
|
|
16282
|
-
return slugifyId(declared);
|
|
16283
|
-
const segments = source.path.split(/[\\/]/).filter((segment) => segment !== "");
|
|
16284
|
-
const last = segments.at(-1) ?? "";
|
|
16285
|
-
const stem = last.toUpperCase() === "SKILL.MD" ? segments.at(-2) ?? "" : last.replace(/\.md$/i, "");
|
|
16286
|
-
return slugifyId(stem);
|
|
16287
|
-
}
|
|
16288
|
-
function convertToInstinct(source, options) {
|
|
16289
|
-
const document = readFrontmatterDocument(source.text);
|
|
16290
|
-
const data = document?.data ?? {};
|
|
16291
|
-
const body = document?.body ?? source.text;
|
|
16292
|
-
const sections = bodySections(body);
|
|
16293
|
-
const action = firstSection(sections, SOLUTION_HEADING)?.text ?? "";
|
|
16294
|
-
const named3 = errorString(body);
|
|
16295
|
-
const name2 = sourceName(source, data);
|
|
16296
|
-
const draft = {
|
|
16297
|
-
id: uniqueInstinctId(name2, options.takenIds ?? []),
|
|
16298
|
-
trigger: demotedTrigger(sections, data),
|
|
16299
|
-
kind: DEMOTED_KIND,
|
|
16300
|
-
domain: inferDomain(name2, body),
|
|
16301
|
-
confidence: DEMOTED_CONFIDENCE,
|
|
16302
|
-
usageCount: DEMOTED_USAGE_COUNT,
|
|
16303
|
-
artifact: null,
|
|
16304
|
-
signal: named3 === null ? DEMOTED_SIGNAL : "loud",
|
|
16305
|
-
scope: options.scope,
|
|
16306
|
-
projectId: options.projectId ?? null,
|
|
16307
|
-
source: DEMOTED_SOURCE,
|
|
16308
|
-
evidence: [{
|
|
16309
|
-
[EVIDENCE_PATH_KEY]: source.path,
|
|
16310
|
-
[EVIDENCE_EXTRACTED_KEY]: extractedDate(body) ?? options.mtime
|
|
16311
|
-
}],
|
|
16312
|
-
createdAt: options.now,
|
|
16313
|
-
updatedAt: options.now,
|
|
16314
|
-
action,
|
|
16315
|
-
cause: firstSection(sections, PROBLEM_HEADING)?.text ?? "",
|
|
16316
|
-
actionHash: actionHash(action)
|
|
16317
|
-
};
|
|
16318
|
-
const text = writeInstinct(draft);
|
|
16319
|
-
const parsed = parseInstinct(text);
|
|
16320
|
-
return parsed.instinct === null ? { instinct: null, text: null, issues: parsed.issues } : { instinct: parsed.instinct, text, issues: parsed.issues };
|
|
16321
|
-
}
|
|
16322
|
-
|
|
16323
|
-
// src/backfill/derive.ts
|
|
16324
16259
|
var DERIVED_FIELDS = ["stack", "paths", "when_to_use"];
|
|
16325
16260
|
function renderWhenToUse(trigger, prevents) {
|
|
16326
16261
|
return `${sentenceEnded(trigger)} Prevents: ${prevents}`;
|
|
@@ -16445,7 +16380,7 @@ function planFile(entry, options) {
|
|
|
16445
16380
|
}
|
|
16446
16381
|
let original;
|
|
16447
16382
|
try {
|
|
16448
|
-
original =
|
|
16383
|
+
original = readFileSync25(entry.path, "utf8");
|
|
16449
16384
|
} catch (error) {
|
|
16450
16385
|
return inert(entry, "skipped", `the file cannot be read (${error instanceof Error ? error.message : String(error)})`);
|
|
16451
16386
|
}
|
|
@@ -16489,7 +16424,7 @@ function planDerivation(root, options) {
|
|
|
16489
16424
|
function applyFile(action, options) {
|
|
16490
16425
|
if (action.text === null || action.original === null)
|
|
16491
16426
|
return action;
|
|
16492
|
-
const current =
|
|
16427
|
+
const current = readFileSync25(action.path, "utf8");
|
|
16493
16428
|
if (current !== action.original) {
|
|
16494
16429
|
return {
|
|
16495
16430
|
...action,
|
|
@@ -16520,7 +16455,7 @@ function applyDerivation(plan2, options) {
|
|
|
16520
16455
|
}
|
|
16521
16456
|
|
|
16522
16457
|
// src/backfill/proposal-batch.ts
|
|
16523
|
-
import { readFileSync as
|
|
16458
|
+
import { readFileSync as readFileSync26 } from "fs";
|
|
16524
16459
|
import { relative as relative9 } from "path";
|
|
16525
16460
|
|
|
16526
16461
|
// src/demote/report.ts
|
|
@@ -16819,7 +16754,7 @@ function readCandidate(root, entry) {
|
|
|
16819
16754
|
return null;
|
|
16820
16755
|
let text;
|
|
16821
16756
|
try {
|
|
16822
|
-
text =
|
|
16757
|
+
text = readFileSync26(entry.path, "utf8");
|
|
16823
16758
|
} catch {
|
|
16824
16759
|
return null;
|
|
16825
16760
|
}
|
|
@@ -16925,8 +16860,8 @@ function parseSessionAnswer(stdout) {
|
|
|
16925
16860
|
}
|
|
16926
16861
|
|
|
16927
16862
|
// src/backfill/propose.ts
|
|
16928
|
-
import { mkdirSync as mkdirSync9, readFileSync as
|
|
16929
|
-
import { join as
|
|
16863
|
+
import { mkdirSync as mkdirSync9, readFileSync as readFileSync27, writeFileSync as writeFileSync8 } from "fs";
|
|
16864
|
+
import { join as join32, resolve as resolve14 } from "path";
|
|
16930
16865
|
var PROPOSAL_ACTION_KINDS = [
|
|
16931
16866
|
"applied",
|
|
16932
16867
|
"unchanged",
|
|
@@ -16947,47 +16882,47 @@ function unanswered(candidate, note) {
|
|
|
16947
16882
|
note
|
|
16948
16883
|
};
|
|
16949
16884
|
}
|
|
16950
|
-
function answerProblem(needs,
|
|
16885
|
+
function answerProblem(needs, answer2) {
|
|
16951
16886
|
if (needs.includes("prevents")) {
|
|
16952
|
-
if (
|
|
16887
|
+
if (answer2.prevents === null)
|
|
16953
16888
|
return "the answer carries no prevents";
|
|
16954
|
-
if (
|
|
16889
|
+
if (answer2.signal === null)
|
|
16955
16890
|
return "the answer carries prevents with no signal";
|
|
16956
|
-
if (!isSkillSignal(
|
|
16957
|
-
return `the answer signal ${
|
|
16891
|
+
if (!isSkillSignal(answer2.signal)) {
|
|
16892
|
+
return `the answer signal ${answer2.signal} is neither ${SKILL_SIGNALS.join(" nor ")}`;
|
|
16958
16893
|
}
|
|
16959
16894
|
}
|
|
16960
|
-
if (needs.includes("trigger") &&
|
|
16895
|
+
if (needs.includes("trigger") && answer2.trigger === null) {
|
|
16961
16896
|
return "the answer carries no trigger sentence";
|
|
16962
16897
|
}
|
|
16963
16898
|
if (needs.includes("description")) {
|
|
16964
|
-
if (
|
|
16899
|
+
if (answer2.description === null)
|
|
16965
16900
|
return "the answer carries no description";
|
|
16966
|
-
if (countCharacters(
|
|
16967
|
-
return `the answer description is ${countCharacters(
|
|
16901
|
+
if (countCharacters(answer2.description) >= DESCRIPTION_LIMIT) {
|
|
16902
|
+
return `the answer description is ${countCharacters(answer2.description)} characters, at or over the ${DESCRIPTION_LIMIT} cap`;
|
|
16968
16903
|
}
|
|
16969
16904
|
}
|
|
16970
16905
|
return null;
|
|
16971
16906
|
}
|
|
16972
|
-
function proposalRow(candidate,
|
|
16973
|
-
if (
|
|
16907
|
+
function proposalRow(candidate, answer2) {
|
|
16908
|
+
if (answer2 === undefined) {
|
|
16974
16909
|
return unanswered(candidate, "the session answered nothing about this file");
|
|
16975
16910
|
}
|
|
16976
|
-
const problem2 = answerProblem(candidate.needs,
|
|
16911
|
+
const problem2 = answerProblem(candidate.needs, answer2);
|
|
16977
16912
|
if (problem2 !== null)
|
|
16978
16913
|
return unanswered(candidate, problem2);
|
|
16979
16914
|
const wants = (need) => candidate.needs.includes(need);
|
|
16980
|
-
const signal =
|
|
16915
|
+
const signal = answer2.signal;
|
|
16981
16916
|
return {
|
|
16982
16917
|
path: candidate.relative,
|
|
16983
16918
|
name: candidate.name,
|
|
16984
16919
|
hash: candidate.hash,
|
|
16985
16920
|
needs: candidate.needs,
|
|
16986
16921
|
status: ANSWERED_ROW,
|
|
16987
|
-
prevents: wants("prevents") ?
|
|
16922
|
+
prevents: wants("prevents") ? answer2.prevents : null,
|
|
16988
16923
|
signal: wants("prevents") && signal !== null && isSkillSignal(signal) ? signal : null,
|
|
16989
|
-
trigger: wants("trigger") ?
|
|
16990
|
-
description: wants("description") ?
|
|
16924
|
+
trigger: wants("trigger") ? answer2.trigger : null,
|
|
16925
|
+
description: wants("description") ? answer2.description : null,
|
|
16991
16926
|
note: null
|
|
16992
16927
|
};
|
|
16993
16928
|
}
|
|
@@ -17075,7 +17010,7 @@ function writeRow(path, row2, original, options) {
|
|
|
17075
17010
|
};
|
|
17076
17011
|
}
|
|
17077
17012
|
function applyRow(root, row2, options) {
|
|
17078
|
-
const path =
|
|
17013
|
+
const path = join32(root, ...row2.path.split("/"));
|
|
17079
17014
|
if (row2.status === UNANSWERED_ROW) {
|
|
17080
17015
|
return inert2(path, row2, "unanswered", row2.note ?? "the row carries no answer");
|
|
17081
17016
|
}
|
|
@@ -17084,7 +17019,7 @@ function applyRow(root, row2, options) {
|
|
|
17084
17019
|
}
|
|
17085
17020
|
let original;
|
|
17086
17021
|
try {
|
|
17087
|
-
original =
|
|
17022
|
+
original = readFileSync27(path, "utf8");
|
|
17088
17023
|
} catch {
|
|
17089
17024
|
return inert2(path, row2, "refused", "the file the row names is gone");
|
|
17090
17025
|
}
|
|
@@ -17112,7 +17047,7 @@ function applyProposals(files, root, options) {
|
|
|
17112
17047
|
for (const file of files) {
|
|
17113
17048
|
const refusal7 = fileRefusal(file, root);
|
|
17114
17049
|
for (const row2 of file.rows) {
|
|
17115
|
-
const action = refusal7 === null ? applyRow(root, row2, options) : inert2(
|
|
17050
|
+
const action = refusal7 === null ? applyRow(root, row2, options) : inert2(join32(root, ...row2.path.split("/")), row2, "refused", refusal7);
|
|
17116
17051
|
actions.push(action);
|
|
17117
17052
|
if (row2.trigger !== null && action.kind !== "refused" && action.kind !== "unanswered") {
|
|
17118
17053
|
triggers[row2.name] = row2.trigger;
|
|
@@ -17123,13 +17058,13 @@ function applyProposals(files, root, options) {
|
|
|
17123
17058
|
}
|
|
17124
17059
|
|
|
17125
17060
|
// src/demote/select.ts
|
|
17126
|
-
import { readdirSync as
|
|
17127
|
-
import { basename as basename9, dirname as dirname7, join as
|
|
17061
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync28, realpathSync as realpathSync6, statSync as statSync13 } from "fs";
|
|
17062
|
+
import { basename as basename9, dirname as dirname7, join as join33 } from "path";
|
|
17128
17063
|
var SKILLS_DIRECTORY = "skills";
|
|
17129
17064
|
var CLAUDE_DIRECTORY = ".claude";
|
|
17130
17065
|
var AUTO_EXTRACTED_ORIGIN = "auto-extracted";
|
|
17131
|
-
var DEMOTED_PATH =
|
|
17132
|
-
var INSTINCTS_PATH =
|
|
17066
|
+
var DEMOTED_PATH = join33(".rafa", "demoted");
|
|
17067
|
+
var INSTINCTS_PATH = join33(".rafa", "instincts");
|
|
17133
17068
|
var REPORT_FILE = "report.md";
|
|
17134
17069
|
function realOrSelf(path) {
|
|
17135
17070
|
try {
|
|
@@ -17152,19 +17087,19 @@ function resolveDemotionScope(dir, home) {
|
|
|
17152
17087
|
if (basename9(claude) !== CLAUDE_DIRECTORY)
|
|
17153
17088
|
return null;
|
|
17154
17089
|
const base = dirname7(claude);
|
|
17155
|
-
const demotedDir =
|
|
17090
|
+
const demotedDir = join33(base, DEMOTED_PATH);
|
|
17156
17091
|
return {
|
|
17157
17092
|
scope: samePath(base, home) ? "user" : "project",
|
|
17158
17093
|
dir,
|
|
17159
17094
|
base,
|
|
17160
17095
|
demotedDir,
|
|
17161
|
-
instinctsDir:
|
|
17162
|
-
reportPath:
|
|
17096
|
+
instinctsDir: join33(base, INSTINCTS_PATH),
|
|
17097
|
+
reportPath: join33(demotedDir, REPORT_FILE)
|
|
17163
17098
|
};
|
|
17164
17099
|
}
|
|
17165
17100
|
function entryKind(path) {
|
|
17166
17101
|
try {
|
|
17167
|
-
const stats =
|
|
17102
|
+
const stats = statSync13(path);
|
|
17168
17103
|
if (stats.isFile())
|
|
17169
17104
|
return "file";
|
|
17170
17105
|
if (stats.isDirectory())
|
|
@@ -17176,7 +17111,7 @@ function entryKind(path) {
|
|
|
17176
17111
|
}
|
|
17177
17112
|
function visibleNames(dir) {
|
|
17178
17113
|
try {
|
|
17179
|
-
return
|
|
17114
|
+
return readdirSync8(dir).filter((name2) => !name2.startsWith(".")).sort((left, right) => left.localeCompare(right));
|
|
17180
17115
|
} catch {
|
|
17181
17116
|
return [];
|
|
17182
17117
|
}
|
|
@@ -17185,8 +17120,8 @@ function readSelected(absolute, path, entries) {
|
|
|
17185
17120
|
let text;
|
|
17186
17121
|
let mtime;
|
|
17187
17122
|
try {
|
|
17188
|
-
text =
|
|
17189
|
-
mtime =
|
|
17123
|
+
text = readFileSync28(absolute, "utf8");
|
|
17124
|
+
mtime = statSync13(absolute).mtime.toISOString();
|
|
17190
17125
|
} catch {
|
|
17191
17126
|
return null;
|
|
17192
17127
|
}
|
|
@@ -17201,14 +17136,14 @@ function selectsLearned(text, scope) {
|
|
|
17201
17136
|
return origin === AUTO_EXTRACTED_ORIGIN;
|
|
17202
17137
|
}
|
|
17203
17138
|
function selectLearned(scope) {
|
|
17204
|
-
const dir =
|
|
17139
|
+
const dir = join33(scope.dir, LEARNED_DIRECTORY);
|
|
17205
17140
|
if (entryKind(dir) !== "directory")
|
|
17206
17141
|
return [];
|
|
17207
17142
|
const selected = [];
|
|
17208
17143
|
for (const name2 of visibleNames(dir)) {
|
|
17209
17144
|
if (!name2.endsWith(MARKDOWN_EXTENSION) || name2 === MARKDOWN_EXTENSION)
|
|
17210
17145
|
continue;
|
|
17211
|
-
const absolute =
|
|
17146
|
+
const absolute = join33(dir, name2);
|
|
17212
17147
|
if (entryKind(absolute) !== "file")
|
|
17213
17148
|
continue;
|
|
17214
17149
|
const file = readSelected(absolute, `${LEARNED_DIRECTORY}/${name2}`, undefined);
|
|
@@ -17222,10 +17157,10 @@ function selectSkillFiles(scope) {
|
|
|
17222
17157
|
for (const name2 of visibleNames(scope.dir)) {
|
|
17223
17158
|
if (name2 === LEARNED_DIRECTORY)
|
|
17224
17159
|
continue;
|
|
17225
|
-
const skillDir =
|
|
17160
|
+
const skillDir = join33(scope.dir, name2);
|
|
17226
17161
|
if (entryKind(skillDir) !== "directory")
|
|
17227
17162
|
continue;
|
|
17228
|
-
const absolute =
|
|
17163
|
+
const absolute = join33(skillDir, SKILL_FILE);
|
|
17229
17164
|
if (entryKind(absolute) !== "file")
|
|
17230
17165
|
continue;
|
|
17231
17166
|
const file = readSelected(absolute, `${name2}/${SKILL_FILE}`, visibleNames(skillDir));
|
|
@@ -17286,7 +17221,7 @@ Usage: ${BACKFILL_USAGE}`);
|
|
|
17286
17221
|
}
|
|
17287
17222
|
function isDirectory3(path) {
|
|
17288
17223
|
try {
|
|
17289
|
-
return
|
|
17224
|
+
return statSync14(path).isDirectory();
|
|
17290
17225
|
} catch {
|
|
17291
17226
|
return false;
|
|
17292
17227
|
}
|
|
@@ -17410,7 +17345,7 @@ function reviewedProposals(dir) {
|
|
|
17410
17345
|
return read2.flatMap((entry) => entry.result.file === null ? [] : [entry.result.file]);
|
|
17411
17346
|
}
|
|
17412
17347
|
function rowPaths(files, root) {
|
|
17413
|
-
return files.flatMap((file) => file.status !== REVIEWED_FILE ? [] : file.rows.filter((row2) => row2.status === ANSWERED_ROW).map((row2) =>
|
|
17348
|
+
return files.flatMap((file) => file.status !== REVIEWED_FILE ? [] : file.rows.filter((row2) => row2.status === ANSWERED_ROW).map((row2) => join34(root, ...row2.path.split("/"))));
|
|
17414
17349
|
}
|
|
17415
17350
|
function runApply(context, scope, backfillDir, projectRoot3) {
|
|
17416
17351
|
const options = checkOptions(context, projectRoot3);
|
|
@@ -17456,7 +17391,7 @@ async function runBackfill(context, seams) {
|
|
|
17456
17391
|
const dir = readBackfillDirectory(context.args, seams.cwd);
|
|
17457
17392
|
const projectRoot3 = readConsumerRoot(context.flags["project"], seams.cwd);
|
|
17458
17393
|
const scope = backfillScopeOf(dir, projectOf12(context).home);
|
|
17459
|
-
const backfillDir =
|
|
17394
|
+
const backfillDir = join34(scope.base, BACKFILL_PATH);
|
|
17460
17395
|
if (mode === "propose") {
|
|
17461
17396
|
await runPropose(context, scope, backfillDir, seams);
|
|
17462
17397
|
return;
|
|
@@ -17570,13 +17505,13 @@ function createSkillCheckCommand(seams = DEFAULT_CHECK_SEAMS) {
|
|
|
17570
17505
|
var check_default3 = createSkillCheckCommand();
|
|
17571
17506
|
|
|
17572
17507
|
// src/commands/skill/demote.ts
|
|
17573
|
-
import { existsSync as existsSync14, mkdirSync as mkdirSync11, readFileSync as
|
|
17508
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync11, readFileSync as readFileSync30, statSync as statSync16, writeFileSync as writeFileSync10 } from "fs";
|
|
17574
17509
|
import { dirname as dirname9, resolve as resolve16 } from "path";
|
|
17575
17510
|
|
|
17576
17511
|
// src/demote/apply.ts
|
|
17577
|
-
import { copyFileSync as copyFileSync5, existsSync as existsSync13, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync2, readdirSync as
|
|
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";
|
|
17578
17513
|
import { tmpdir as tmpdir2 } from "os";
|
|
17579
|
-
import { dirname as dirname8, join as
|
|
17514
|
+
import { dirname as dirname8, join as join35 } from "path";
|
|
17580
17515
|
var DEMOTION_ACTION_KINDS = [
|
|
17581
17516
|
"demoted",
|
|
17582
17517
|
"kept",
|
|
@@ -17597,18 +17532,18 @@ function learnedSkillName(path) {
|
|
|
17597
17532
|
return base.slice(0, -MARKDOWN_EXTENSION.length);
|
|
17598
17533
|
}
|
|
17599
17534
|
function sourcePath(scope, path) {
|
|
17600
|
-
return
|
|
17535
|
+
return join35(scope.dir, ...path.split("/"));
|
|
17601
17536
|
}
|
|
17602
17537
|
function demotedPath(scope, path) {
|
|
17603
|
-
return
|
|
17538
|
+
return join35(scope.demotedDir, ...path.split("/"));
|
|
17604
17539
|
}
|
|
17605
17540
|
function promotedPath(scope, path) {
|
|
17606
|
-
return
|
|
17541
|
+
return join35(scope.dir, learnedSkillName(path), SKILL_FILE);
|
|
17607
17542
|
}
|
|
17608
17543
|
function takenInstinctIds(dir) {
|
|
17609
17544
|
let names;
|
|
17610
17545
|
try {
|
|
17611
|
-
names =
|
|
17546
|
+
names = readdirSync9(dir);
|
|
17612
17547
|
} catch {
|
|
17613
17548
|
return [];
|
|
17614
17549
|
}
|
|
@@ -17616,7 +17551,7 @@ function takenInstinctIds(dir) {
|
|
|
17616
17551
|
}
|
|
17617
17552
|
function readText4(path) {
|
|
17618
17553
|
try {
|
|
17619
|
-
return
|
|
17554
|
+
return statSync15(path).isFile() ? readFileSync29(path, "utf8") : null;
|
|
17620
17555
|
} catch {
|
|
17621
17556
|
return null;
|
|
17622
17557
|
}
|
|
@@ -17658,7 +17593,7 @@ function planKept(scope, row2, file) {
|
|
|
17658
17593
|
};
|
|
17659
17594
|
}
|
|
17660
17595
|
function checkCandidate(dir, id, text, pathDirs) {
|
|
17661
|
-
const path =
|
|
17596
|
+
const path = join35(dir, `${id}${MARKDOWN_EXTENSION}`);
|
|
17662
17597
|
writeFileSync9(path, text, "utf8");
|
|
17663
17598
|
const report3 = checkFile(path, "instinct", { projectRoot: null, pathDirs });
|
|
17664
17599
|
return failureLines2(report3.issues);
|
|
@@ -17679,7 +17614,7 @@ function planDemoted(scope, row2, file, context) {
|
|
|
17679
17614
|
if (failures.length > 0) {
|
|
17680
17615
|
return inert3(row2.path, "observation", "refused", `the record ${id} fails the checker \u2014 ${failures.join("; ")}`);
|
|
17681
17616
|
}
|
|
17682
|
-
const destination =
|
|
17617
|
+
const destination = join35(scope.instinctsDir, `${id}${MARKDOWN_EXTENSION}`);
|
|
17683
17618
|
const kept = demotedPath(scope, row2.path);
|
|
17684
17619
|
if (existsSync13(destination))
|
|
17685
17620
|
return inert3(row2.path, "observation", "refused", `${destination} is already there`);
|
|
@@ -17715,7 +17650,7 @@ function planRow(scope, row2, context) {
|
|
|
17715
17650
|
entries: undefined,
|
|
17716
17651
|
absolute,
|
|
17717
17652
|
hash,
|
|
17718
|
-
mtime:
|
|
17653
|
+
mtime: statSync15(absolute).mtime.toISOString()
|
|
17719
17654
|
};
|
|
17720
17655
|
return verdict === "procedure" ? planKept(scope, row2, file) : planDemoted(scope, row2, file, context);
|
|
17721
17656
|
}
|
|
@@ -17726,7 +17661,7 @@ function countActions(actions) {
|
|
|
17726
17661
|
return counts;
|
|
17727
17662
|
}
|
|
17728
17663
|
function planDemotion(report3, scope, seams = DEFAULT_APPLY_SEAMS) {
|
|
17729
|
-
const temp = mkdtempSync2(
|
|
17664
|
+
const temp = mkdtempSync2(join35(tmpdir2(), "rafa-demote-"));
|
|
17730
17665
|
const taken = [...takenInstinctIds(scope.instinctsDir)];
|
|
17731
17666
|
try {
|
|
17732
17667
|
const actions = report3.rows.map((row2) => planRow(scope, row2, { temp, taken, seams }));
|
|
@@ -17817,7 +17752,7 @@ Usage: ${DEMOTE_USAGE}`);
|
|
|
17817
17752
|
}
|
|
17818
17753
|
function isDirectory4(path) {
|
|
17819
17754
|
try {
|
|
17820
|
-
return
|
|
17755
|
+
return statSync16(path).isDirectory();
|
|
17821
17756
|
} catch {
|
|
17822
17757
|
return false;
|
|
17823
17758
|
}
|
|
@@ -17847,7 +17782,7 @@ function verdictLine(report3) {
|
|
|
17847
17782
|
function previousReport(path, context) {
|
|
17848
17783
|
if (!existsSync14(path))
|
|
17849
17784
|
return null;
|
|
17850
|
-
const parsed = parseDemotionReport(
|
|
17785
|
+
const parsed = parseDemotionReport(readFileSync30(path, "utf8"));
|
|
17851
17786
|
if (parsed.report !== null)
|
|
17852
17787
|
return parsed.report;
|
|
17853
17788
|
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(", ")}`);
|
|
@@ -17883,7 +17818,7 @@ function reviewedReport(scope) {
|
|
|
17883
17818
|
if (!existsSync14(scope.reportPath)) {
|
|
17884
17819
|
throw new CommandExit(1, `\u274C No report at ${scope.reportPath}; run "rafa skill demote ${scope.dir}" first, then review it`);
|
|
17885
17820
|
}
|
|
17886
|
-
const parsed = parseDemotionReport(
|
|
17821
|
+
const parsed = parseDemotionReport(readFileSync30(scope.reportPath, "utf8"));
|
|
17887
17822
|
if (parsed.report === null) {
|
|
17888
17823
|
const lines2 = parsed.issues.map((issue2) => ` line ${String(issue2.line)} ${issue2.code}: ${issue2.message}`);
|
|
17889
17824
|
throw new CommandExit(1, [`\u274C ${scope.reportPath} does not parse:`, ...lines2].join(`
|
|
@@ -17990,7 +17925,7 @@ var demote_default = createSkillDemoteCommand();
|
|
|
17990
17925
|
// src/commands/skill/show.ts
|
|
17991
17926
|
var DEFAULT_SKILL_SHOW_SEAMS = DEFAULT_SKILL_LIST_SEAMS;
|
|
17992
17927
|
var COMMAND_NAME5 = "rafa skill show";
|
|
17993
|
-
var
|
|
17928
|
+
var USAGE32 = "rafa skill show <name> [--full]";
|
|
17994
17929
|
function unknownSkillMessage(name2, inventory) {
|
|
17995
17930
|
const agent = findShown(inventory.records, "agent", name2);
|
|
17996
17931
|
const hint = agent === null ? [] : [`An agent is named "${name2}" (${agent.source}): rafa agent show ${name2}`];
|
|
@@ -17998,7 +17933,7 @@ function unknownSkillMessage(name2, inventory) {
|
|
|
17998
17933
|
`\u274C No skill is named "${name2}".`,
|
|
17999
17934
|
...hint,
|
|
18000
17935
|
"Run `rafa skill list` to see every skill and where it comes from.",
|
|
18001
|
-
`Usage: ${
|
|
17936
|
+
`Usage: ${USAGE32}`
|
|
18002
17937
|
].join(`
|
|
18003
17938
|
`);
|
|
18004
17939
|
}
|
|
@@ -18014,8 +17949,8 @@ function projectOf14(context) {
|
|
|
18014
17949
|
return context.project;
|
|
18015
17950
|
}
|
|
18016
17951
|
async function runShow3(context, seams) {
|
|
18017
|
-
const full = readSwitch("full", context.flags["full"], `Type the name ahead of it: ${
|
|
18018
|
-
const name2 = expectOneArgument(context.args,
|
|
17952
|
+
const full = readSwitch("full", context.flags["full"], `Type the name ahead of it: ${USAGE32}`);
|
|
17953
|
+
const name2 = expectOneArgument(context.args, USAGE32);
|
|
18019
17954
|
const project = projectOf14(context);
|
|
18020
17955
|
const { inventory, settingSources } = await projectInventory(project, context, seams, COMMAND_NAME5);
|
|
18021
17956
|
const warnings = warningLines(inventory);
|
|
@@ -18432,7 +18367,7 @@ var CORE_SUBJECTS = Object.freeze([
|
|
|
18432
18367
|
{ name: "module", summary: "list the configured modules; run an action a module provides" },
|
|
18433
18368
|
{ name: "agent", summary: "copy an agent definition into the project; list what a session sees" },
|
|
18434
18369
|
{ name: "skill", summary: "check a skills directory; list each tier; demote and backfill it" },
|
|
18435
|
-
{ name: "instinct", summary: "check an instincts directory; list and
|
|
18370
|
+
{ name: "instinct", summary: "check an instincts directory; list, show, flag and promote its records" },
|
|
18436
18371
|
{ name: "release", summary: "read the release state of the project; tag the release branch's HEAD" }
|
|
18437
18372
|
]);
|
|
18438
18373
|
var CORE_COMMANDS = Object.freeze([
|
|
@@ -18480,6 +18415,8 @@ var CORE_COMMANDS = Object.freeze([
|
|
|
18480
18415
|
check_default,
|
|
18481
18416
|
list_default4,
|
|
18482
18417
|
show_default2,
|
|
18418
|
+
flag_default,
|
|
18419
|
+
promote_default,
|
|
18483
18420
|
status_default2,
|
|
18484
18421
|
tag_default,
|
|
18485
18422
|
status_default3,
|