@open-tomato/rafa 0.35.0 → 0.36.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/dist/bundled/operators/agents/rafa-stretch-engineer.md +4 -4
- package/dist/bundled/operators/agents/rafa-stretch-watchtower.md +9 -9
- package/dist/cli.js +12102 -10915
- package/dist/describe-5hqfwbjc.js +14 -0
- package/dist/effort/store/index.js +36 -33
- package/dist/{index-dvrq9nfb.js → index-2n2nedrk.js} +4988 -4683
- package/dist/index-3mzw3kzh.js +129 -0
- package/dist/{index-41vzahew.js → index-7bb0fdb7.js} +33 -31
- package/dist/{index-hgcvjke7.js → index-d6d0942q.js} +17 -17
- package/dist/{index-se13pvag.js → index-ddzzmcaz.js} +2856 -2243
- package/dist/index-fzhd3d4y.js +446 -0
- package/dist/{index-2tjmxwvp.js → index-jfas157k.js} +111 -513
- package/dist/index-k6sd4ym5.js +243 -0
- package/dist/{index-ckqfhynj.js → index-qvbeqrx3.js} +417 -494
- package/dist/index-wp8c28fd.js +18 -0
- package/dist/index.js +152 -147
- package/dist/learning/index.js +20 -20
- package/dist/plan/index.js +45 -42
- package/package.json +1 -1
- package/dist/describe-59899b0p.js +0 -11
- package/dist/index-21jcfatr.js +0 -16
|
@@ -1,447 +1,45 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (tier === "user")
|
|
44
|
-
return join(seams.home, CLAUDE_SKILLS_PATH);
|
|
45
|
-
if (tier === "rafa")
|
|
46
|
-
return bundledSkillsDirectory(seams.entry);
|
|
47
|
-
return seams.projectRoot === null ? null : join(seams.projectRoot, CLAUDE_SKILLS_PATH);
|
|
48
|
-
}
|
|
49
|
-
function resolveSkillTiers(seams) {
|
|
50
|
-
const located = [];
|
|
51
|
-
for (const tier of SKILL_TIERS) {
|
|
52
|
-
const dir = skillTierDirectory(tier, seams);
|
|
53
|
-
if (dir !== null)
|
|
54
|
-
located.push({ tier, dir });
|
|
55
|
-
}
|
|
56
|
-
return located;
|
|
57
|
-
}
|
|
58
|
-
function instinctScopeDirectory(scope, seams) {
|
|
59
|
-
if (scope === "user")
|
|
60
|
-
return join(seams.home, RAFA_INSTINCTS_PATH);
|
|
61
|
-
return seams.projectRoot === null ? null : join(seams.projectRoot, RAFA_INSTINCTS_PATH);
|
|
62
|
-
}
|
|
63
|
-
function resolveInstinctScopes(seams) {
|
|
64
|
-
const located = [];
|
|
65
|
-
for (const scope of INSTINCT_SCOPES) {
|
|
66
|
-
const dir = instinctScopeDirectory(scope, seams);
|
|
67
|
-
if (dir !== null)
|
|
68
|
-
located.push({ scope, dir });
|
|
69
|
-
}
|
|
70
|
-
return located;
|
|
71
|
-
}
|
|
72
|
-
function tierExists(dir) {
|
|
73
|
-
return existsSync(dir);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// src/utils/declaration.ts
|
|
77
|
-
var DECLARATION_KEYS = [
|
|
78
|
-
"agent",
|
|
79
|
-
"model",
|
|
80
|
-
"effort",
|
|
81
|
-
"budget",
|
|
82
|
-
"tools",
|
|
83
|
-
"skills",
|
|
84
|
-
"tests"
|
|
85
|
-
];
|
|
86
|
-
var GRANULAR_KEYS = ["model", "effort", "tools"];
|
|
87
|
-
var AGENT_OWNED_KEYS = ["model", "tools"];
|
|
88
|
-
var MODEL_ALIASES = ["opus", "sonnet", "haiku", "fable"];
|
|
89
|
-
var EFFORT_LEVELS = [
|
|
90
|
-
"low",
|
|
91
|
-
"medium",
|
|
92
|
-
"high",
|
|
93
|
-
"xhigh",
|
|
94
|
-
"max"
|
|
95
|
-
];
|
|
96
|
-
var TEST_SCOPES = ["affected", "module", "full"];
|
|
97
|
-
var DEFAULT_TEST_SCOPE = "affected";
|
|
98
|
-
var DECLARATION_BLOCK = /\{([^{}]*)\}$/;
|
|
99
|
-
var ENTRY_TOKEN = /^([A-Za-z_][A-Za-z0-9_-]*)=(.*)$/;
|
|
100
|
-
var FULL_MODEL_NAME = /^claude-[a-z0-9][a-z0-9.-]*$/;
|
|
101
|
-
var AGENT_NAME = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
102
|
-
function isAgentName(value) {
|
|
103
|
-
return AGENT_NAME.test(value);
|
|
104
|
-
}
|
|
105
|
-
var TOOL_NAME = /^[A-Za-z][A-Za-z0-9_-]*$/;
|
|
106
|
-
var SKILL_NAME = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
107
|
-
var BUDGET_FLAG = "--max-budget-usd";
|
|
108
|
-
var BUDGET_VALUE = /^(?:0|[1-9]\d{0,5})(?:\.\d{1,6})?$/;
|
|
109
|
-
function parseBudgetUsd(value) {
|
|
110
|
-
if (!BUDGET_VALUE.test(value))
|
|
111
|
-
return null;
|
|
112
|
-
const usd = Number(value);
|
|
113
|
-
return usd > 0 ? usd : null;
|
|
114
|
-
}
|
|
115
|
-
function isEffortLevel(value) {
|
|
116
|
-
return EFFORT_LEVELS.includes(value);
|
|
117
|
-
}
|
|
118
|
-
function isTestScope(value) {
|
|
119
|
-
return TEST_SCOPES.includes(value);
|
|
120
|
-
}
|
|
121
|
-
function readTestScope(declaration) {
|
|
122
|
-
return declaration?.tests ?? DEFAULT_TEST_SCOPE;
|
|
123
|
-
}
|
|
124
|
-
function isModelValue(value) {
|
|
125
|
-
if (MODEL_ALIASES.includes(value))
|
|
126
|
-
return true;
|
|
127
|
-
return FULL_MODEL_NAME.test(value);
|
|
128
|
-
}
|
|
129
|
-
function parseToolList(value) {
|
|
130
|
-
const parts = value.split(",");
|
|
131
|
-
if (parts.length === 0)
|
|
132
|
-
return null;
|
|
133
|
-
const tools = [];
|
|
134
|
-
for (const part of parts) {
|
|
135
|
-
if (!TOOL_NAME.test(part))
|
|
136
|
-
return null;
|
|
137
|
-
if (!tools.includes(part))
|
|
138
|
-
tools.push(part);
|
|
139
|
-
}
|
|
140
|
-
return tools;
|
|
141
|
-
}
|
|
142
|
-
function parseSkillList(value) {
|
|
143
|
-
const parts = value.split(",");
|
|
144
|
-
if (parts.length === 0)
|
|
145
|
-
return null;
|
|
146
|
-
const skills = [];
|
|
147
|
-
for (const part of parts) {
|
|
148
|
-
if (!SKILL_NAME.test(part))
|
|
149
|
-
return null;
|
|
150
|
-
if (!skills.includes(part))
|
|
151
|
-
skills.push(part);
|
|
152
|
-
}
|
|
153
|
-
return skills;
|
|
154
|
-
}
|
|
155
|
-
function unusableValue(key, token) {
|
|
156
|
-
return { reason: "unusable-value", key, text: token };
|
|
157
|
-
}
|
|
158
|
-
function isDeclarationKey(key) {
|
|
159
|
-
return DECLARATION_KEYS.includes(key);
|
|
160
|
-
}
|
|
161
|
-
function tokenise(body) {
|
|
162
|
-
const trimmed = body.trim();
|
|
163
|
-
if (trimmed.length === 0)
|
|
164
|
-
return [];
|
|
165
|
-
return trimmed.split(/\s+/);
|
|
166
|
-
}
|
|
167
|
-
function readBlock(raw, body) {
|
|
168
|
-
const entries = [];
|
|
169
|
-
const extras = [];
|
|
170
|
-
const issues = [];
|
|
171
|
-
const seen = new Set;
|
|
172
|
-
let agent = null;
|
|
173
|
-
let model = null;
|
|
174
|
-
let effort = null;
|
|
175
|
-
let budget = null;
|
|
176
|
-
let tools = null;
|
|
177
|
-
let skills = null;
|
|
178
|
-
let tests = null;
|
|
179
|
-
for (const token of tokenise(body)) {
|
|
180
|
-
const match = token.match(ENTRY_TOKEN);
|
|
181
|
-
const key = match?.[1];
|
|
182
|
-
const value = match?.[2];
|
|
183
|
-
if (key === undefined || value === undefined) {
|
|
184
|
-
issues.push({ reason: "stray-token", key: "", text: token });
|
|
185
|
-
continue;
|
|
186
|
-
}
|
|
187
|
-
const entry = { key, value };
|
|
188
|
-
entries.push(entry);
|
|
189
|
-
if (!isDeclarationKey(key)) {
|
|
190
|
-
extras.push(entry);
|
|
191
|
-
continue;
|
|
192
|
-
}
|
|
193
|
-
if (seen.has(key)) {
|
|
194
|
-
issues.push({ reason: "duplicate-key", key, text: token });
|
|
195
|
-
continue;
|
|
196
|
-
}
|
|
197
|
-
seen.add(key);
|
|
198
|
-
if (key === "agent") {
|
|
199
|
-
if (AGENT_NAME.test(value))
|
|
200
|
-
agent = value;
|
|
201
|
-
else
|
|
202
|
-
issues.push(unusableValue(key, token));
|
|
203
|
-
continue;
|
|
204
|
-
}
|
|
205
|
-
if (key === "model") {
|
|
206
|
-
if (isModelValue(value))
|
|
207
|
-
model = value;
|
|
208
|
-
else
|
|
209
|
-
issues.push(unusableValue(key, token));
|
|
210
|
-
continue;
|
|
211
|
-
}
|
|
212
|
-
if (key === "effort") {
|
|
213
|
-
if (isEffortLevel(value))
|
|
214
|
-
effort = value;
|
|
215
|
-
else
|
|
216
|
-
issues.push(unusableValue(key, token));
|
|
217
|
-
continue;
|
|
218
|
-
}
|
|
219
|
-
if (key === "budget") {
|
|
220
|
-
const usd = parseBudgetUsd(value);
|
|
221
|
-
if (usd === null)
|
|
222
|
-
issues.push(unusableValue(key, token));
|
|
223
|
-
else
|
|
224
|
-
budget = usd;
|
|
225
|
-
continue;
|
|
226
|
-
}
|
|
227
|
-
if (key === "tools") {
|
|
228
|
-
const parsed = parseToolList(value);
|
|
229
|
-
if (parsed === null)
|
|
230
|
-
issues.push(unusableValue(key, token));
|
|
231
|
-
else
|
|
232
|
-
tools = parsed;
|
|
233
|
-
continue;
|
|
234
|
-
}
|
|
235
|
-
if (key === "tests") {
|
|
236
|
-
if (isTestScope(value))
|
|
237
|
-
tests = value;
|
|
238
|
-
else
|
|
239
|
-
issues.push(unusableValue(key, token));
|
|
240
|
-
continue;
|
|
241
|
-
}
|
|
242
|
-
const named = parseSkillList(value);
|
|
243
|
-
if (named === null)
|
|
244
|
-
issues.push(unusableValue(key, token));
|
|
245
|
-
else
|
|
246
|
-
skills = named;
|
|
247
|
-
}
|
|
248
|
-
if (seen.size === 0)
|
|
249
|
-
return null;
|
|
250
|
-
return {
|
|
251
|
-
raw,
|
|
252
|
-
entries,
|
|
253
|
-
extras,
|
|
254
|
-
issues,
|
|
255
|
-
agent,
|
|
256
|
-
model,
|
|
257
|
-
effort,
|
|
258
|
-
budget,
|
|
259
|
-
tools,
|
|
260
|
-
skills,
|
|
261
|
-
tests
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
function parseTaskDeclaration(taskText) {
|
|
265
|
-
const trimmed = taskText.trimEnd();
|
|
266
|
-
const match = trimmed.match(DECLARATION_BLOCK);
|
|
267
|
-
const raw = match?.[0];
|
|
268
|
-
const body = match?.[1];
|
|
269
|
-
if (raw === undefined || body === undefined) {
|
|
270
|
-
return { text: taskText, declaration: null };
|
|
271
|
-
}
|
|
272
|
-
const before = trimmed.slice(0, trimmed.length - raw.length).trimEnd();
|
|
273
|
-
if (before.length === 0)
|
|
274
|
-
return { text: taskText, declaration: null };
|
|
275
|
-
const declaration = readBlock(raw, body);
|
|
276
|
-
if (declaration === null)
|
|
277
|
-
return { text: taskText, declaration: null };
|
|
278
|
-
return { text: before, declaration };
|
|
279
|
-
}
|
|
280
|
-
function stripTaskDeclaration(taskText) {
|
|
281
|
-
return parseTaskDeclaration(taskText).text;
|
|
282
|
-
}
|
|
283
|
-
function budgetArgs(budget) {
|
|
284
|
-
return budget === null ? [] : [BUDGET_FLAG, String(budget)];
|
|
285
|
-
}
|
|
286
|
-
function resolveDeclarationFlags(declaration, agentDeclaresEffort) {
|
|
287
|
-
if (declaration === null)
|
|
288
|
-
return { args: [], suppressed: [] };
|
|
289
|
-
const { agent, effort } = declaration;
|
|
290
|
-
const isPresent = (key) => declaration[key] !== null;
|
|
291
|
-
const budget = budgetArgs(declaration.budget);
|
|
292
|
-
if (agent !== null) {
|
|
293
|
-
if (effort === null || agentDeclaresEffort(agent)) {
|
|
294
|
-
return { args: ["--agent", agent, ...budget], suppressed: GRANULAR_KEYS.filter(isPresent) };
|
|
295
|
-
}
|
|
296
|
-
return {
|
|
297
|
-
args: ["--agent", agent, "--effort", effort, ...budget],
|
|
298
|
-
suppressed: AGENT_OWNED_KEYS.filter(isPresent)
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
const args = [];
|
|
302
|
-
if (declaration.model !== null)
|
|
303
|
-
args.push("--model", declaration.model);
|
|
304
|
-
if (declaration.effort !== null)
|
|
305
|
-
args.push("--effort", declaration.effort);
|
|
306
|
-
args.push(...budget);
|
|
307
|
-
if (declaration.tools !== null) {
|
|
308
|
-
args.push("--tools", declaration.tools.join(","));
|
|
309
|
-
}
|
|
310
|
-
return { args, suppressed: [] };
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
// src/config-sections.ts
|
|
314
|
-
function isMapping(value) {
|
|
315
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
316
|
-
}
|
|
317
|
-
function describeValue(value) {
|
|
318
|
-
if (typeof value === "string")
|
|
319
|
-
return JSON.stringify(value);
|
|
320
|
-
if (value === null)
|
|
321
|
-
return "null";
|
|
322
|
-
if (Array.isArray(value))
|
|
323
|
-
return "a list";
|
|
324
|
-
if (typeof value === "object")
|
|
325
|
-
return "a mapping";
|
|
326
|
-
return String(value);
|
|
327
|
-
}
|
|
328
|
-
function messageOf(error) {
|
|
329
|
-
return error instanceof Error ? error.message : String(error);
|
|
330
|
-
}
|
|
331
|
-
var CONFIG_VERSIONS2 = [1];
|
|
332
|
-
var STORE_BACKENDS2 = ["sqlite", "ndjson"];
|
|
333
|
-
var SYNC_STRATEGIES2 = ["local", "file", "git", "service", "p2p"];
|
|
334
|
-
var BOARD_RELATIONSHIP_MODES2 = ["labels", "native"];
|
|
335
|
-
var INJECT_MODES2 = ["full", "stage", "task"];
|
|
336
|
-
var OUTPUT_MODES2 = ["text", "json", "events"];
|
|
337
|
-
var CLAUDE_SETTING_SOURCES2 = ["user", "project", "local"];
|
|
338
|
-
var PR_PROVIDERS2 = ["gh", "none"];
|
|
339
|
-
var RELEASE_AUTO2 = "auto";
|
|
340
|
-
var TIER_SWITCHES = ["on", "off"];
|
|
341
|
-
var SKILL_RESOLVERS = ["planner", "tag", "none"];
|
|
342
|
-
var LESSON_SWITCHES = ["on", "off"];
|
|
343
|
-
var CLAIMS_STALE_DISABLED = "disabled";
|
|
344
|
-
var CLAIMS_AHEAD = ["off", "allow"];
|
|
345
|
-
function accepted(value) {
|
|
346
|
-
return { value, problems: [], extras: [] };
|
|
347
|
-
}
|
|
348
|
-
function refused(at, raw, expected) {
|
|
349
|
-
const problem = `${at.label} is ${describeValue(raw)}, expected ${expected}`;
|
|
350
|
-
return { value: undefined, problems: [problem], extras: [] };
|
|
351
|
-
}
|
|
352
|
-
function refusedWith(problems) {
|
|
353
|
-
return { value: undefined, problems, extras: [] };
|
|
354
|
-
}
|
|
355
|
-
function mapReading(reading, map) {
|
|
356
|
-
return reading.value === undefined ? { ...reading, value: undefined } : { ...reading, value: map(reading.value) };
|
|
357
|
-
}
|
|
358
|
-
function below(at, step) {
|
|
359
|
-
return { label: `${at.label}${step}`, key: `${at.key}${step}` };
|
|
360
|
-
}
|
|
361
|
-
function oneOf(values) {
|
|
362
|
-
const expected = `one of: ${values.join(", ")}`;
|
|
363
|
-
return (raw, at) => {
|
|
364
|
-
const hit = values.find((value) => value === raw);
|
|
365
|
-
return hit === undefined ? refused(at, raw, expected) : accepted(hit);
|
|
366
|
-
};
|
|
367
|
-
}
|
|
368
|
-
function text(expected) {
|
|
369
|
-
return (raw, at) => typeof raw === "string" && raw.trim() !== "" ? accepted(raw) : refused(at, raw, expected);
|
|
370
|
-
}
|
|
371
|
-
var flag = (raw, at) => typeof raw === "boolean" ? accepted(raw) : refused(at, raw, "true or false");
|
|
372
|
-
var mergeMethod = oneOf(MERGE_METHODS);
|
|
373
|
-
var usdAmount = (raw, at) => {
|
|
374
|
-
const usd = typeof raw === "number" ? parseBudgetUsd(String(raw)) : null;
|
|
375
|
-
return usd === null ? refused(at, raw, "a number of US dollars above zero, at most six digits either side of the point") : accepted(usd);
|
|
376
|
-
};
|
|
377
|
-
var issueNumber = (raw, at) => typeof raw === "number" && Number.isSafeInteger(raw) && raw > 0 ? accepted(raw) : refused(at, raw, "an issue number, a whole number above zero");
|
|
378
|
-
var dayCount = (raw, at) => typeof raw === "number" && Number.isSafeInteger(raw) && raw > 0 ? accepted(raw) : refused(at, raw, "a number of days, a whole number above zero");
|
|
379
|
-
var BUSY_TIMEOUT_MIN_MS = 1;
|
|
380
|
-
var BUSY_TIMEOUT_MAX_MS = 60000;
|
|
381
|
-
function isBusyTimeoutMs(raw) {
|
|
382
|
-
return typeof raw === "number" && Number.isSafeInteger(raw) && raw >= BUSY_TIMEOUT_MIN_MS && raw <= BUSY_TIMEOUT_MAX_MS;
|
|
383
|
-
}
|
|
384
|
-
var busyTimeoutMs = (raw, at) => isBusyTimeoutMs(raw) ? accepted(raw) : refused(at, raw, `a lock wait in milliseconds, a whole number from ${String(BUSY_TIMEOUT_MIN_MS)} to ${String(BUSY_TIMEOUT_MAX_MS)}`);
|
|
385
|
-
var confidence = (raw, at) => typeof raw === "number" && Number.isFinite(raw) && toHundredths(raw) >= toHundredths(CONFIDENCE_MIN2) && toHundredths(raw) <= toHundredths(CONFIDENCE_MAX2) ? accepted(raw) : refused(at, raw, `a confidence from ${String(CONFIDENCE_MIN2)} to ${String(CONFIDENCE_MAX2)}`);
|
|
386
|
-
function toHundredths(value) {
|
|
387
|
-
return Math.round(value * 100);
|
|
388
|
-
}
|
|
389
|
-
var recurrenceCount = (raw, at) => typeof raw === "number" && Number.isSafeInteger(raw) && raw >= 1 ? accepted(raw) : refused(at, raw, "a count, a whole number of 1 or more");
|
|
390
|
-
var releaseEnabled = (raw, at) => typeof raw === "boolean" || raw === RELEASE_AUTO2 ? accepted(raw) : refused(at, raw, `true, false or ${RELEASE_AUTO2}`);
|
|
391
|
-
var tierSwitch = oneOf(TIER_SWITCHES);
|
|
392
|
-
var tierPin = (raw, at) => {
|
|
393
|
-
if (raw === false)
|
|
394
|
-
return accepted(false);
|
|
395
|
-
const tier = SKILL_TIERS.find((name) => name === raw);
|
|
396
|
-
return tier === undefined ? refused(at, raw, `false or one of: ${SKILL_TIERS.join(", ")}`) : accepted(tier);
|
|
397
|
-
};
|
|
398
|
-
var routeTarget = (raw, at) => raw === false || typeof raw === "string" && raw.trim() !== "" ? accepted(raw) : refused(at, raw, "false or an agent name");
|
|
399
|
-
var skillResolverName = oneOf(SKILL_RESOLVERS);
|
|
400
|
-
var lessonSwitch = oneOf(LESSON_SWITCHES);
|
|
401
|
-
var CLAIM_DURATION = /^(\d+)([hd])$/;
|
|
402
|
-
var HOURS_PER_DAY = 24;
|
|
403
|
-
function claimDurationHours(raw) {
|
|
404
|
-
const match = typeof raw === "string" ? CLAIM_DURATION.exec(raw) : null;
|
|
405
|
-
if (match === null)
|
|
406
|
-
return null;
|
|
407
|
-
const hours = Number(match[1]) * (match[2] === "d" ? HOURS_PER_DAY : 1);
|
|
408
|
-
return Number.isSafeInteger(hours) && hours > 0 ? hours : null;
|
|
409
|
-
}
|
|
410
|
-
var claimsStaleAfter = (raw, at) => raw === CLAIMS_STALE_DISABLED || claimDurationHours(raw) !== null ? accepted(raw) : refused(at, raw, `a duration of whole hours or days above zero, such as 36h or 3d, or ${CLAIMS_STALE_DISABLED}`);
|
|
411
|
-
var claimsAhead = oneOf(CLAIMS_AHEAD);
|
|
412
|
-
var GITHUB_LOGIN = /^[A-Za-z0-9][A-Za-z0-9-]*(?:\[bot\])?$/;
|
|
413
|
-
function isGitHubLogin(value) {
|
|
414
|
-
return typeof value === "string" && GITHUB_LOGIN.test(value);
|
|
415
|
-
}
|
|
416
|
-
var githubLogin = (raw, at) => isGitHubLogin(raw) ? accepted(raw) : refused(at, raw, "a GitHub login");
|
|
417
|
-
function listOf(item, expected) {
|
|
418
|
-
return (raw, at) => {
|
|
419
|
-
if (!Array.isArray(raw))
|
|
420
|
-
return refused(at, raw, `a list of ${expected}`);
|
|
421
|
-
const readings = raw.map((entry, index) => item(entry, below(at, `[${index}]`)));
|
|
422
|
-
const problems = readings.flatMap((reading) => reading.problems);
|
|
423
|
-
const extras = readings.flatMap((reading) => reading.extras);
|
|
424
|
-
if (problems.length > 0)
|
|
425
|
-
return { value: undefined, problems, extras };
|
|
426
|
-
const values = readings.flatMap((reading) => reading.value === undefined ? [] : [reading.value]);
|
|
427
|
-
return { value: Object.freeze(values), problems, extras };
|
|
428
|
-
};
|
|
429
|
-
}
|
|
430
|
-
function subsetOf(values) {
|
|
431
|
-
const expected = `a comma-separated subset of: ${values.join(", ")}`;
|
|
432
|
-
return (raw, at) => {
|
|
433
|
-
if (typeof raw !== "string")
|
|
434
|
-
return refused(at, raw, expected);
|
|
435
|
-
const named = [];
|
|
436
|
-
for (const entry of raw.split(",")) {
|
|
437
|
-
const hit = values.find((value) => value === entry.trim());
|
|
438
|
-
if (hit === undefined || named.includes(hit))
|
|
439
|
-
return refused(at, raw, expected);
|
|
440
|
-
named.push(hit);
|
|
441
|
-
}
|
|
442
|
-
return accepted(Object.freeze(named));
|
|
443
|
-
};
|
|
444
|
-
}
|
|
3
|
+
BOARD_RELATIONSHIP_MODES,
|
|
4
|
+
CLAUDE_SETTING_SOURCES,
|
|
5
|
+
CONFIG_VERSIONS,
|
|
6
|
+
INJECT_MODES,
|
|
7
|
+
OUTPUT_MODES,
|
|
8
|
+
PR_PROVIDERS,
|
|
9
|
+
RELEASE_AUTO,
|
|
10
|
+
SKILL_TIERS,
|
|
11
|
+
STORE_BACKENDS,
|
|
12
|
+
SYNC_STRATEGIES,
|
|
13
|
+
below,
|
|
14
|
+
busyTimeoutMs,
|
|
15
|
+
claimsAhead,
|
|
16
|
+
claimsStaleAfter,
|
|
17
|
+
confidence,
|
|
18
|
+
dayCount,
|
|
19
|
+
describeValue,
|
|
20
|
+
flag,
|
|
21
|
+
githubLogin,
|
|
22
|
+
isMapping,
|
|
23
|
+
isSkillTier,
|
|
24
|
+
issueNumber,
|
|
25
|
+
lessonSwitch,
|
|
26
|
+
listOf,
|
|
27
|
+
mapReading,
|
|
28
|
+
mergeMethod,
|
|
29
|
+
messageOf,
|
|
30
|
+
oneOf,
|
|
31
|
+
recurrenceCount,
|
|
32
|
+
refused,
|
|
33
|
+
refusedWith,
|
|
34
|
+
releaseEnabled,
|
|
35
|
+
routeTarget,
|
|
36
|
+
skillResolverName,
|
|
37
|
+
subsetOf,
|
|
38
|
+
text,
|
|
39
|
+
tierPin,
|
|
40
|
+
tierSwitch,
|
|
41
|
+
usdAmount
|
|
42
|
+
} from "./index-fzhd3d4y.js";
|
|
445
43
|
|
|
446
44
|
// src/config-items.ts
|
|
447
45
|
var itemText = text("a non-empty string");
|
|
@@ -450,13 +48,13 @@ function readKeyedItem(shape, raw, at) {
|
|
|
450
48
|
if (!isMapping(raw))
|
|
451
49
|
return refused(at, raw, `a mapping naming one of: ${choices}`);
|
|
452
50
|
const entries = Object.entries(raw);
|
|
453
|
-
const kinds = shape.kinds.filter((
|
|
51
|
+
const kinds = shape.kinds.filter((kind2) => entries.some(([name]) => name === kind2));
|
|
454
52
|
const [kind] = kinds;
|
|
455
53
|
if (kind === undefined)
|
|
456
54
|
return refusedWith([`${at.label} names none of: ${choices}`]);
|
|
457
55
|
if (kinds.length > 1) {
|
|
458
|
-
const
|
|
459
|
-
return refusedWith([`${at.label} names ${
|
|
56
|
+
const named2 = kinds.join(" and ");
|
|
57
|
+
return refusedWith([`${at.label} names ${named2}, expected exactly one of: ${choices}`]);
|
|
460
58
|
}
|
|
461
59
|
const optionalKeys = shape.optionalFor(kind);
|
|
462
60
|
const problems = [];
|
|
@@ -481,11 +79,11 @@ function readKeyedItem(shape, raw, at) {
|
|
|
481
79
|
}
|
|
482
80
|
return problems.length > 0 || named === undefined ? { value: undefined, problems, extras } : { value: { kind, named, optional }, problems, extras };
|
|
483
81
|
}
|
|
484
|
-
var
|
|
485
|
-
var REQUIRED_ITEM_KEYS = [...
|
|
82
|
+
var PREREQUISITE_KINDS = ["tool", "env", "service", "lsp"];
|
|
83
|
+
var REQUIRED_ITEM_KEYS = [...PREREQUISITE_KINDS, "probe"];
|
|
486
84
|
var OPTIONAL_ITEM_KEYS = [...REQUIRED_ITEM_KEYS, "reason"];
|
|
487
85
|
var requiredPrerequisite = (raw, at) => {
|
|
488
|
-
const shape = { kinds:
|
|
86
|
+
const shape = { kinds: PREREQUISITE_KINDS, optionalFor: () => ["probe"] };
|
|
489
87
|
return mapReading(readKeyedItem(shape, raw, at), (item) => Object.freeze({
|
|
490
88
|
kind: item.kind,
|
|
491
89
|
name: item.named,
|
|
@@ -493,7 +91,7 @@ var requiredPrerequisite = (raw, at) => {
|
|
|
493
91
|
}));
|
|
494
92
|
};
|
|
495
93
|
var optionalPrerequisite = (raw, at) => {
|
|
496
|
-
const shape = { kinds:
|
|
94
|
+
const shape = { kinds: PREREQUISITE_KINDS, optionalFor: () => ["probe", "reason"] };
|
|
497
95
|
return mapReading(readKeyedItem(shape, raw, at), (item) => Object.freeze({
|
|
498
96
|
kind: item.kind,
|
|
499
97
|
name: item.named,
|
|
@@ -501,11 +99,11 @@ var optionalPrerequisite = (raw, at) => {
|
|
|
501
99
|
reason: item.optional.get("reason") ?? null
|
|
502
100
|
}));
|
|
503
101
|
};
|
|
504
|
-
var
|
|
505
|
-
var MODULE_SOURCE_KEYS = [...
|
|
102
|
+
var MODULE_SOURCE_KINDS = ["npm", "github", "path"];
|
|
103
|
+
var MODULE_SOURCE_KEYS = [...MODULE_SOURCE_KINDS, "ref"];
|
|
506
104
|
var moduleSource = (raw, at) => {
|
|
507
105
|
const shape = {
|
|
508
|
-
kinds:
|
|
106
|
+
kinds: MODULE_SOURCE_KINDS,
|
|
509
107
|
optionalFor: (kind) => kind === "github" ? ["ref"] : []
|
|
510
108
|
};
|
|
511
109
|
return mapReading(readKeyedItem(shape, raw, at), (item) => Object.freeze({
|
|
@@ -516,7 +114,7 @@ var moduleSource = (raw, at) => {
|
|
|
516
114
|
};
|
|
517
115
|
|
|
518
116
|
// src/config-schema.ts
|
|
519
|
-
import { join
|
|
117
|
+
import { join } from "path";
|
|
520
118
|
|
|
521
119
|
// src/config-readers.ts
|
|
522
120
|
import { isAbsolute, normalize } from "path";
|
|
@@ -638,7 +236,7 @@ var PR_DEFAULTS = Object.freeze({
|
|
|
638
236
|
prVersionCollision: "report"
|
|
639
237
|
});
|
|
640
238
|
var RELEASE_DEFAULTS = Object.freeze({
|
|
641
|
-
releaseEnabled:
|
|
239
|
+
releaseEnabled: RELEASE_AUTO,
|
|
642
240
|
releaseVersionFile: "package.json",
|
|
643
241
|
releaseChangelog: "CHANGELOG.md",
|
|
644
242
|
releaseHeading: "## {version} \u2014 {date}, {title}",
|
|
@@ -652,7 +250,7 @@ var DANGEROUS_RELEASE_DEFAULTS = Object.freeze({
|
|
|
652
250
|
dangerousAcceptVersionCollision: false
|
|
653
251
|
});
|
|
654
252
|
var PR_SETTINGS = {
|
|
655
|
-
prProvider: { key: "pr.provider", read: oneOf(
|
|
253
|
+
prProvider: { key: "pr.provider", read: oneOf(PR_PROVIDERS), cli: false },
|
|
656
254
|
prMergeMethod: { key: "pr.mergeMethod", read: mergeMethod, cli: false },
|
|
657
255
|
prBase: { key: "pr.base", read: text("a branch name"), cli: false },
|
|
658
256
|
prResolveBudget: { key: "pr.resolveBudget", read: usdAmount, cli: false },
|
|
@@ -839,10 +437,10 @@ function sameItemGroups(holders, read) {
|
|
|
839
437
|
const groups = [];
|
|
840
438
|
for (const row of holders) {
|
|
841
439
|
const bytes = read(row.path);
|
|
842
|
-
const
|
|
843
|
-
const group =
|
|
440
|
+
const text2 = bytes === null ? null : comparableText(bytes);
|
|
441
|
+
const group = text2 === null ? undefined : groups.find((candidate) => candidate.text === text2);
|
|
844
442
|
if (group === undefined)
|
|
845
|
-
groups.push({ text, rows: [row] });
|
|
443
|
+
groups.push({ text: text2, rows: [row] });
|
|
846
444
|
else
|
|
847
445
|
group.rows.push(row);
|
|
848
446
|
}
|
|
@@ -936,16 +534,16 @@ var DEFAULT_ROUTES = Object.freeze([
|
|
|
936
534
|
var DEFAULT_ROUTING = new Map(DEFAULT_ROUTES);
|
|
937
535
|
|
|
938
536
|
// src/config-schema.ts
|
|
939
|
-
var
|
|
940
|
-
var
|
|
537
|
+
var CONFIG_FILE = join(".rafa", "config.yaml");
|
|
538
|
+
var CONFIG_DEFAULTS = Object.freeze({
|
|
941
539
|
version: 1,
|
|
942
540
|
store: "sqlite",
|
|
943
541
|
effortBusyTimeoutMs: 5000,
|
|
944
542
|
effortSync: "local",
|
|
945
543
|
...HUB_DEFAULTS,
|
|
946
544
|
inject: "stage",
|
|
947
|
-
planDir:
|
|
948
|
-
specsDir:
|
|
545
|
+
planDir: join(".rafa", "plans"),
|
|
546
|
+
specsDir: join(".rafa", "specs"),
|
|
949
547
|
trackerDefault: "github",
|
|
950
548
|
trackerFallback: Object.freeze(["local"]),
|
|
951
549
|
learningAdapter: "local",
|
|
@@ -961,7 +559,7 @@ var CONFIG_DEFAULTS2 = Object.freeze({
|
|
|
961
559
|
modules: Object.freeze([]),
|
|
962
560
|
allowList: Object.freeze([]),
|
|
963
561
|
settingSources: Object.freeze(["project", "local"]),
|
|
964
|
-
loopWorktreeDir:
|
|
562
|
+
loopWorktreeDir: join(".rafa", "worktrees"),
|
|
965
563
|
...WRAP_UP_DEFAULTS,
|
|
966
564
|
...PR_DEFAULTS,
|
|
967
565
|
boardTrustedAuthors: Object.freeze([]),
|
|
@@ -987,12 +585,12 @@ var CONFIG_DEFAULTS2 = Object.freeze({
|
|
|
987
585
|
...TESTS_DEFAULTS
|
|
988
586
|
});
|
|
989
587
|
var SETTINGS = {
|
|
990
|
-
version: { key: "version", read: oneOf(
|
|
991
|
-
store: { key: "store", read: oneOf(
|
|
588
|
+
version: { key: "version", read: oneOf(CONFIG_VERSIONS), cli: false },
|
|
589
|
+
store: { key: "store", read: oneOf(STORE_BACKENDS), cli: true },
|
|
992
590
|
effortBusyTimeoutMs: { key: "effort.busyTimeoutMs", read: busyTimeoutMs, cli: false },
|
|
993
|
-
effortSync: { key: "effort.sync", read: oneOf(
|
|
591
|
+
effortSync: { key: "effort.sync", read: oneOf(SYNC_STRATEGIES), cli: false },
|
|
994
592
|
...HUB_SETTINGS,
|
|
995
|
-
inject: { key: "plan.inject", read: oneOf(
|
|
593
|
+
inject: { key: "plan.inject", read: oneOf(INJECT_MODES), cli: true },
|
|
996
594
|
planDir: { key: "plan.dir", read: directory, cli: true },
|
|
997
595
|
specsDir: { key: "specs.dir", read: directory, cli: true },
|
|
998
596
|
trackerDefault: { key: "tracker.default", read: trackerKind, cli: true },
|
|
@@ -1009,7 +607,7 @@ var SETTINGS = {
|
|
|
1009
607
|
learningBlessMinConfidence: { key: "learning.bless.minConfidence", read: confidence, cli: false },
|
|
1010
608
|
learningPromoteAfter: { key: "learning.promote.after", read: recurrenceCount, cli: false },
|
|
1011
609
|
learningPromoteMinConfidence: { key: "learning.promote.minConfidence", read: confidence, cli: false },
|
|
1012
|
-
outputMode: { key: "output.mode", read: oneOf(
|
|
610
|
+
outputMode: { key: "output.mode", read: oneOf(OUTPUT_MODES), cli: true },
|
|
1013
611
|
prerequisitesRequired: {
|
|
1014
612
|
key: "prerequisites.required",
|
|
1015
613
|
read: listOf(requiredPrerequisite, "prerequisite items"),
|
|
@@ -1038,7 +636,7 @@ var SETTINGS = {
|
|
|
1038
636
|
},
|
|
1039
637
|
settingSources: {
|
|
1040
638
|
key: "loop.settingSources",
|
|
1041
|
-
read: subsetOf(
|
|
639
|
+
read: subsetOf(CLAUDE_SETTING_SOURCES),
|
|
1042
640
|
cli: true
|
|
1043
641
|
},
|
|
1044
642
|
loopWorktreeDir: { key: "loop.worktreeDir", read: directory, cli: false },
|
|
@@ -1051,7 +649,7 @@ var SETTINGS = {
|
|
|
1051
649
|
},
|
|
1052
650
|
boardRelationships: {
|
|
1053
651
|
key: "board.relationships",
|
|
1054
|
-
read: oneOf(
|
|
652
|
+
read: oneOf(BOARD_RELATIONSHIP_MODES),
|
|
1055
653
|
cli: false
|
|
1056
654
|
},
|
|
1057
655
|
roadmapIssue: { key: "roadmap.issue", read: issueNumber, cli: false },
|
|
@@ -1134,8 +732,8 @@ function knownKeysAbove(key) {
|
|
|
1134
732
|
}
|
|
1135
733
|
|
|
1136
734
|
// src/config.ts
|
|
1137
|
-
import { join as
|
|
1138
|
-
class
|
|
735
|
+
import { join as join2 } from "path";
|
|
736
|
+
class ConfigError extends Error {
|
|
1139
737
|
problems;
|
|
1140
738
|
constructor(problems, options) {
|
|
1141
739
|
super(`rafa config: ${problems.join("; ")}`, options);
|
|
@@ -1260,28 +858,28 @@ function sortKeys(document, path) {
|
|
|
1260
858
|
return { named, extras, problems };
|
|
1261
859
|
}
|
|
1262
860
|
var TAB_INDENTED_LINE = /^[ \t]*\t[ \t]*[^\s#]/;
|
|
1263
|
-
function tabIndentProblems(
|
|
1264
|
-
return
|
|
861
|
+
function tabIndentProblems(text2, path) {
|
|
862
|
+
return text2.split(/\r?\n/).flatMap((line, index) => TAB_INDENTED_LINE.test(line) ? [`${path}: line ${index + 1} is indented with a tab; YAML indents with spaces only`] : []);
|
|
1265
863
|
}
|
|
1266
|
-
function parseYaml(
|
|
1267
|
-
const tabProblems = tabIndentProblems(
|
|
864
|
+
function parseYaml(text2, path) {
|
|
865
|
+
const tabProblems = tabIndentProblems(text2, path);
|
|
1268
866
|
if (tabProblems.length > 0)
|
|
1269
|
-
throw new
|
|
867
|
+
throw new ConfigError(tabProblems);
|
|
1270
868
|
try {
|
|
1271
|
-
return Bun.YAML.parse(
|
|
869
|
+
return Bun.YAML.parse(text2);
|
|
1272
870
|
} catch (error) {
|
|
1273
871
|
const problem = `${path}: not valid YAML (${messageOf(error)})`;
|
|
1274
|
-
throw new
|
|
872
|
+
throw new ConfigError([problem], { cause: error });
|
|
1275
873
|
}
|
|
1276
874
|
}
|
|
1277
|
-
function
|
|
1278
|
-
return
|
|
875
|
+
function configFilePath(root) {
|
|
876
|
+
return join2(root, CONFIG_FILE);
|
|
1279
877
|
}
|
|
1280
|
-
function
|
|
1281
|
-
const document = parseYaml(
|
|
878
|
+
function parseConfigText(text2, path) {
|
|
879
|
+
const document = parseYaml(text2, path) ?? {};
|
|
1282
880
|
if (!isMapping(document)) {
|
|
1283
881
|
const found = describeValue(document);
|
|
1284
|
-
throw new
|
|
882
|
+
throw new ConfigError([
|
|
1285
883
|
`${path}: expected a mapping at the top level, found ${found}`
|
|
1286
884
|
]);
|
|
1287
885
|
}
|
|
@@ -1292,7 +890,7 @@ function parseConfigText2(text, path) {
|
|
|
1292
890
|
}));
|
|
1293
891
|
const all = [...sorted.problems, ...read.problems];
|
|
1294
892
|
if (all.length > 0)
|
|
1295
|
-
throw new
|
|
893
|
+
throw new ConfigError(all);
|
|
1296
894
|
return { path, values: read.layer, extras: [...sorted.extras, ...read.extras] };
|
|
1297
895
|
}
|
|
1298
896
|
var MAP_SETTINGS = new Set([
|
|
@@ -1323,13 +921,13 @@ function unknownKeyWarning(key, path) {
|
|
|
1323
921
|
const where = under === "" ? "" : ` under ${under}`;
|
|
1324
922
|
return `rafa config: unknown key ${quoted} in ${path} has no effect ` + `in this version (known keys${where}: ${names.join(", ")})`;
|
|
1325
923
|
}
|
|
1326
|
-
function
|
|
924
|
+
function resolveConfig(layers = {}) {
|
|
1327
925
|
const file = layers.file ?? null;
|
|
1328
926
|
const user = layers.user ?? null;
|
|
1329
927
|
const overrides = layers.cli ?? {};
|
|
1330
928
|
const { layer: cli, problems } = readLayer((setting) => isCommandLineSetting(setting) ? overrides[setting] : undefined, (setting) => ({ label: `command line: ${setting}`, key: setting }));
|
|
1331
929
|
if (problems.length > 0)
|
|
1332
|
-
throw new
|
|
930
|
+
throw new ConfigError(problems);
|
|
1333
931
|
const rank = (setting) => {
|
|
1334
932
|
const fromCli = cli[setting];
|
|
1335
933
|
if (fromCli !== undefined)
|
|
@@ -1337,7 +935,7 @@ function resolveConfig2(layers = {}) {
|
|
|
1337
935
|
const fromFile = file?.values[setting];
|
|
1338
936
|
const fromUser = user?.values[setting];
|
|
1339
937
|
if (MAP_SETTINGS.has(setting)) {
|
|
1340
|
-
const merged = mergeMaps(
|
|
938
|
+
const merged = mergeMaps(CONFIG_DEFAULTS[setting], fromUser, fromFile);
|
|
1341
939
|
const source = fromFile !== undefined ? "file" : fromUser !== undefined ? "user" : "default";
|
|
1342
940
|
return { value: merged, source };
|
|
1343
941
|
}
|
|
@@ -1345,7 +943,7 @@ function resolveConfig2(layers = {}) {
|
|
|
1345
943
|
return { value: fromFile, source: "file" };
|
|
1346
944
|
if (fromUser !== undefined)
|
|
1347
945
|
return { value: fromUser, source: "user" };
|
|
1348
|
-
return { value:
|
|
946
|
+
return { value: CONFIG_DEFAULTS[setting], source: "default" };
|
|
1349
947
|
};
|
|
1350
948
|
const ranked = SETTING_NAMES.map((setting) => [setting, rank(setting)]);
|
|
1351
949
|
const effortSync = rank("effortSync");
|
|
@@ -1356,7 +954,7 @@ function resolveConfig2(layers = {}) {
|
|
|
1356
954
|
paths: { file: file?.path ?? null, user: user?.path ?? null }
|
|
1357
955
|
});
|
|
1358
956
|
if (hubProblems.length > 0)
|
|
1359
|
-
throw new
|
|
957
|
+
throw new ConfigError(hubProblems);
|
|
1360
958
|
const rafaLoaded = ranked.find(([setting]) => setting === "tiersRafa")?.[1].value !== "off";
|
|
1361
959
|
const warnings = [user, file].flatMap((layer) => layer === null ? [] : [
|
|
1362
960
|
...layer.extras.map((extra) => unknownKeyWarning(extra.key, layer.path)),
|
|
@@ -1374,7 +972,7 @@ function resolveConfig2(layers = {}) {
|
|
|
1374
972
|
}
|
|
1375
973
|
|
|
1376
974
|
// src/plan/blocks.ts
|
|
1377
|
-
var
|
|
975
|
+
var RAFA_BLOCK_KINDS = [
|
|
1378
976
|
"plan",
|
|
1379
977
|
"context",
|
|
1380
978
|
"stage-context",
|
|
@@ -1383,8 +981,8 @@ var RAFA_BLOCK_KINDS2 = [
|
|
|
1383
981
|
var RAFA_PREFIX = "rafa:";
|
|
1384
982
|
var FENCE_RUN = /^( {0,3})(`{3,}|~{3,})/;
|
|
1385
983
|
var CLOSING_FENCE = /^ {0,3}(`{3,}|~{3,})[ \t]*$/;
|
|
1386
|
-
function
|
|
1387
|
-
return
|
|
984
|
+
function isRafaBlockKind(kind) {
|
|
985
|
+
return RAFA_BLOCK_KINDS.includes(kind);
|
|
1388
986
|
}
|
|
1389
987
|
function linesOf(markdown) {
|
|
1390
988
|
const lines = markdown.split(`
|
|
@@ -1428,7 +1026,7 @@ function dedent(line, indent) {
|
|
|
1428
1026
|
cut += 1;
|
|
1429
1027
|
return line.slice(cut);
|
|
1430
1028
|
}
|
|
1431
|
-
function
|
|
1029
|
+
function readRafaBlocks(markdown) {
|
|
1432
1030
|
const lines = linesOf(markdown);
|
|
1433
1031
|
const blocks = [];
|
|
1434
1032
|
let index = 0;
|
|
@@ -1452,9 +1050,9 @@ function readRafaBlocks2(markdown) {
|
|
|
1452
1050
|
}
|
|
1453
1051
|
|
|
1454
1052
|
// src/report/parse.ts
|
|
1455
|
-
var
|
|
1456
|
-
var
|
|
1457
|
-
var
|
|
1053
|
+
var REPORT_STATUSES = ["done", "blocked"];
|
|
1054
|
+
var FINDING_KINDS = ["gotcha", "pattern", "location", "skill-suggestion"];
|
|
1055
|
+
var FINDING_SIGNALS = ["loud", "silent"];
|
|
1458
1056
|
var FINDING_DOMAINS = [
|
|
1459
1057
|
"code-style",
|
|
1460
1058
|
"testing",
|
|
@@ -1510,11 +1108,11 @@ function describeValue2(value) {
|
|
|
1510
1108
|
function messageOf2(error) {
|
|
1511
1109
|
return error instanceof Error ? error.message : String(error);
|
|
1512
1110
|
}
|
|
1513
|
-
function reportIssue(reason, field,
|
|
1514
|
-
return { reason, field, text };
|
|
1111
|
+
function reportIssue(reason, field, text2) {
|
|
1112
|
+
return { reason, field, text: text2 };
|
|
1515
1113
|
}
|
|
1516
|
-
function absent(reason, block,
|
|
1517
|
-
return { present: false, reason, block, text };
|
|
1114
|
+
function absent(reason, block, text2) {
|
|
1115
|
+
return { present: false, reason, block, text: text2 };
|
|
1518
1116
|
}
|
|
1519
1117
|
function scopeOf(mapping, keys, prefix, issues) {
|
|
1520
1118
|
const fields = new Map;
|
|
@@ -1586,8 +1184,8 @@ function listField(scope, key, readEntry) {
|
|
|
1586
1184
|
function entryScope(item, field, keys, issues) {
|
|
1587
1185
|
if (isMapping2(item))
|
|
1588
1186
|
return scopeOf(item, keys, `${field}.`, issues);
|
|
1589
|
-
const
|
|
1590
|
-
issues.push(reportIssue("unusable-field", field,
|
|
1187
|
+
const text2 = `${field} is ${describeValue2(item)}, not a mapping of ${keys.join(", ")}; dropped`;
|
|
1188
|
+
issues.push(reportIssue("unusable-field", field, text2));
|
|
1591
1189
|
return null;
|
|
1592
1190
|
}
|
|
1593
1191
|
function readSkill(item, field, issues) {
|
|
@@ -1603,12 +1201,12 @@ function readFinding(item, field, issues) {
|
|
|
1603
1201
|
return null;
|
|
1604
1202
|
return {
|
|
1605
1203
|
trigger: stringField(scope, "trigger", REQUIRED),
|
|
1606
|
-
kind: choiceField(scope, "kind",
|
|
1204
|
+
kind: choiceField(scope, "kind", FINDING_KINDS, REQUIRED),
|
|
1607
1205
|
what: stringField(scope, "what", REQUIRED),
|
|
1608
1206
|
cause: stringField(scope, "cause", OPTIONAL),
|
|
1609
1207
|
resolution: stringField(scope, "resolution", OPTIONAL),
|
|
1610
1208
|
artifact: stringField(scope, "artifact", OPTIONAL),
|
|
1611
|
-
signal: choiceField(scope, "signal",
|
|
1209
|
+
signal: choiceField(scope, "signal", FINDING_SIGNALS, REQUIRED),
|
|
1612
1210
|
domain: choiceField(scope, "domain", FINDING_DOMAINS, OPTIONAL),
|
|
1613
1211
|
extras: scope.extras
|
|
1614
1212
|
};
|
|
@@ -1648,7 +1246,7 @@ function readChange(item, field, issues) {
|
|
|
1648
1246
|
function readReport(document, issues) {
|
|
1649
1247
|
const scope = scopeOf(document, REPORT_KEYS, "", issues);
|
|
1650
1248
|
return {
|
|
1651
|
-
status: choiceField(scope, "status",
|
|
1249
|
+
status: choiceField(scope, "status", REPORT_STATUSES, REQUIRED),
|
|
1652
1250
|
feedback: stringField(scope, "feedback", OPTIONAL),
|
|
1653
1251
|
findings: listField(scope, "findings", readFinding),
|
|
1654
1252
|
skillsUsed: listField(scope, "skills_used", readSkill),
|
|
@@ -1658,8 +1256,8 @@ function readReport(document, issues) {
|
|
|
1658
1256
|
extras: scope.extras
|
|
1659
1257
|
};
|
|
1660
1258
|
}
|
|
1661
|
-
function
|
|
1662
|
-
const reports =
|
|
1259
|
+
function parseReport(output) {
|
|
1260
|
+
const reports = readRafaBlocks(output).filter((block2) => block2.kind === REPORT_KIND);
|
|
1663
1261
|
const block = reports.at(-1);
|
|
1664
1262
|
if (block === undefined) {
|
|
1665
1263
|
return absent("no-block", null, "the session output holds no rafa:report block");
|
|
@@ -1672,12 +1270,12 @@ function parseReport2(output) {
|
|
|
1672
1270
|
try {
|
|
1673
1271
|
document = Bun.YAML.parse(block.body);
|
|
1674
1272
|
} catch (error) {
|
|
1675
|
-
const
|
|
1676
|
-
return absent("malformed-block", block,
|
|
1273
|
+
const text2 = `rafa:report block at line ${line} is not valid YAML (${messageOf2(error)})`;
|
|
1274
|
+
return absent("malformed-block", block, text2);
|
|
1677
1275
|
}
|
|
1678
1276
|
if (!isMapping2(document)) {
|
|
1679
|
-
const
|
|
1680
|
-
return absent("malformed-block", block,
|
|
1277
|
+
const text2 = `rafa:report block at line ${line} holds ${describeValue2(document)}, ` + "not a mapping of report fields";
|
|
1278
|
+
return absent("malformed-block", block, text2);
|
|
1681
1279
|
}
|
|
1682
1280
|
const issues = [];
|
|
1683
1281
|
const report = readReport(document, issues);
|
|
@@ -1805,4 +1403,4 @@ function activeOutputMode() {
|
|
|
1805
1403
|
return activeMode;
|
|
1806
1404
|
}
|
|
1807
1405
|
|
|
1808
|
-
export {
|
|
1406
|
+
export { hubContextOf, PREREQUISITE_KINDS, requiredPrerequisite, optionalPrerequisite, MODULE_SOURCE_KINDS, pinKey, pinLine, collisionMessage, readItemBytes, resolveTiers, findTierItem, DEFAULT_ROUTES, DEFAULT_ROUTING, CONFIG_FILE, CONFIG_DEFAULTS, SETTINGS, ConfigError, configFilePath, parseConfigText, resolveConfig, isStampableStub, planStubFromPrompt, stampPrompt, planStubFromPath, createTextOutput, activeOutput, activeOutputMode, RAFA_BLOCK_KINDS, isRafaBlockKind, readRafaBlocks, REPORT_STATUSES, FINDING_KINDS, FINDING_SIGNALS, FINDING_DOMAINS, CHANGE_LEVELS, parseReport };
|