@open-tomato/rafa 0.34.0 → 0.35.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 +32 -18
- package/dist/bundled/agents/doc-updater.md +1 -1
- package/dist/bundled/operators/.claude-plugin/plugin.json +5 -0
- package/dist/bundled/operators/agents/rafa-stretch-analyst.md +53 -0
- package/dist/bundled/operators/agents/rafa-stretch-engineer.md +41 -15
- package/dist/bundled/operators/skills/rafa-stretch-pit-stop/SKILL.md +2 -2
- package/dist/cli.js +11813 -10419
- package/dist/describe-59899b0p.js +11 -0
- package/dist/effort/store/index.js +33 -36
- package/dist/index-21jcfatr.js +16 -0
- package/dist/{index-vp0xghk2.js → index-2tjmxwvp.js} +519 -114
- package/dist/{index-v8d7c6sw.js → index-41vzahew.js} +69 -33
- package/dist/{index-bvfbfa63.js → index-ckqfhynj.js} +824 -547
- package/dist/{index-4b3m7s0z.js → index-dvrq9nfb.js} +4646 -3954
- package/dist/{index-d6d0942q.js → index-hgcvjke7.js} +17 -17
- package/dist/{index-b8t7q5hc.js → index-se13pvag.js} +2879 -2260
- package/dist/index.js +147 -154
- package/dist/learning/index.js +20 -20
- package/dist/plan/index.js +42 -45
- package/package.json +4 -2
- package/dist/describe-5hqfwbjc.js +0 -14
- package/dist/index-3mzw3kzh.js +0 -129
- package/dist/index-fzhd3d4y.js +0 -446
- package/dist/index-k6sd4ym5.js +0 -243
- package/dist/index-wp8c28fd.js +0 -18
|
@@ -1,45 +1,447 @@
|
|
|
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
|
-
|
|
3
|
+
CONFIDENCE_MIN2,
|
|
4
|
+
CONFIDENCE_MAX2
|
|
5
|
+
} from "./index-21jcfatr.js";
|
|
6
|
+
|
|
7
|
+
// src/pr/types.ts
|
|
8
|
+
var MERGE_METHODS = Object.freeze([
|
|
9
|
+
"squash",
|
|
10
|
+
"merge",
|
|
11
|
+
"rebase"
|
|
12
|
+
]);
|
|
13
|
+
function isMergeMethod(value) {
|
|
14
|
+
return typeof value === "string" && MERGE_METHODS.includes(value);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// src/schema/tiers.ts
|
|
18
|
+
import { existsSync, realpathSync } from "fs";
|
|
19
|
+
import { dirname, join } from "path";
|
|
20
|
+
var SKILL_TIERS = ["project", "rafa", "user"];
|
|
21
|
+
var INSTINCT_SCOPES = ["project", "user"];
|
|
22
|
+
var CLAUDE_SKILLS_PATH = join(".claude", "skills");
|
|
23
|
+
var RAFA_INSTINCTS_PATH = join(".rafa", "instincts");
|
|
24
|
+
var BUNDLED_SKILLS_DIR = join("bundled", "skills");
|
|
25
|
+
var BUNDLED_BIN_DIR = join("bundled", "bin");
|
|
26
|
+
function isSkillTier(value) {
|
|
27
|
+
return SKILL_TIERS.includes(value);
|
|
28
|
+
}
|
|
29
|
+
function realEntry(entry) {
|
|
30
|
+
try {
|
|
31
|
+
return realpathSync(entry);
|
|
32
|
+
} catch {
|
|
33
|
+
return entry;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function bundledSkillsDirectory(entry) {
|
|
37
|
+
return join(dirname(realEntry(entry ?? Bun.main)), BUNDLED_SKILLS_DIR);
|
|
38
|
+
}
|
|
39
|
+
function bundledBinDirectory(entry) {
|
|
40
|
+
return join(dirname(realEntry(entry ?? Bun.main)), BUNDLED_BIN_DIR);
|
|
41
|
+
}
|
|
42
|
+
function skillTierDirectory(tier, seams) {
|
|
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
|
+
}
|
|
43
445
|
|
|
44
446
|
// src/config-items.ts
|
|
45
447
|
var itemText = text("a non-empty string");
|
|
@@ -48,13 +450,13 @@ function readKeyedItem(shape, raw, at) {
|
|
|
48
450
|
if (!isMapping(raw))
|
|
49
451
|
return refused(at, raw, `a mapping naming one of: ${choices}`);
|
|
50
452
|
const entries = Object.entries(raw);
|
|
51
|
-
const kinds = shape.kinds.filter((
|
|
453
|
+
const kinds = shape.kinds.filter((kind) => entries.some(([name]) => name === kind));
|
|
52
454
|
const [kind] = kinds;
|
|
53
455
|
if (kind === undefined)
|
|
54
456
|
return refusedWith([`${at.label} names none of: ${choices}`]);
|
|
55
457
|
if (kinds.length > 1) {
|
|
56
|
-
const
|
|
57
|
-
return refusedWith([`${at.label} names ${
|
|
458
|
+
const named = kinds.join(" and ");
|
|
459
|
+
return refusedWith([`${at.label} names ${named}, expected exactly one of: ${choices}`]);
|
|
58
460
|
}
|
|
59
461
|
const optionalKeys = shape.optionalFor(kind);
|
|
60
462
|
const problems = [];
|
|
@@ -79,11 +481,11 @@ function readKeyedItem(shape, raw, at) {
|
|
|
79
481
|
}
|
|
80
482
|
return problems.length > 0 || named === undefined ? { value: undefined, problems, extras } : { value: { kind, named, optional }, problems, extras };
|
|
81
483
|
}
|
|
82
|
-
var
|
|
83
|
-
var REQUIRED_ITEM_KEYS = [...
|
|
484
|
+
var PREREQUISITE_KINDS2 = ["tool", "env", "service", "lsp"];
|
|
485
|
+
var REQUIRED_ITEM_KEYS = [...PREREQUISITE_KINDS2, "probe"];
|
|
84
486
|
var OPTIONAL_ITEM_KEYS = [...REQUIRED_ITEM_KEYS, "reason"];
|
|
85
487
|
var requiredPrerequisite = (raw, at) => {
|
|
86
|
-
const shape = { kinds:
|
|
488
|
+
const shape = { kinds: PREREQUISITE_KINDS2, optionalFor: () => ["probe"] };
|
|
87
489
|
return mapReading(readKeyedItem(shape, raw, at), (item) => Object.freeze({
|
|
88
490
|
kind: item.kind,
|
|
89
491
|
name: item.named,
|
|
@@ -91,7 +493,7 @@ var requiredPrerequisite = (raw, at) => {
|
|
|
91
493
|
}));
|
|
92
494
|
};
|
|
93
495
|
var optionalPrerequisite = (raw, at) => {
|
|
94
|
-
const shape = { kinds:
|
|
496
|
+
const shape = { kinds: PREREQUISITE_KINDS2, optionalFor: () => ["probe", "reason"] };
|
|
95
497
|
return mapReading(readKeyedItem(shape, raw, at), (item) => Object.freeze({
|
|
96
498
|
kind: item.kind,
|
|
97
499
|
name: item.named,
|
|
@@ -99,11 +501,11 @@ var optionalPrerequisite = (raw, at) => {
|
|
|
99
501
|
reason: item.optional.get("reason") ?? null
|
|
100
502
|
}));
|
|
101
503
|
};
|
|
102
|
-
var
|
|
103
|
-
var MODULE_SOURCE_KEYS = [...
|
|
504
|
+
var MODULE_SOURCE_KINDS2 = ["npm", "github", "path"];
|
|
505
|
+
var MODULE_SOURCE_KEYS = [...MODULE_SOURCE_KINDS2, "ref"];
|
|
104
506
|
var moduleSource = (raw, at) => {
|
|
105
507
|
const shape = {
|
|
106
|
-
kinds:
|
|
508
|
+
kinds: MODULE_SOURCE_KINDS2,
|
|
107
509
|
optionalFor: (kind) => kind === "github" ? ["ref"] : []
|
|
108
510
|
};
|
|
109
511
|
return mapReading(readKeyedItem(shape, raw, at), (item) => Object.freeze({
|
|
@@ -114,7 +516,7 @@ var moduleSource = (raw, at) => {
|
|
|
114
516
|
};
|
|
115
517
|
|
|
116
518
|
// src/config-schema.ts
|
|
117
|
-
import { join } from "path";
|
|
519
|
+
import { join as join2 } from "path";
|
|
118
520
|
|
|
119
521
|
// src/config-readers.ts
|
|
120
522
|
import { isAbsolute, normalize } from "path";
|
|
@@ -236,7 +638,7 @@ var PR_DEFAULTS = Object.freeze({
|
|
|
236
638
|
prVersionCollision: "report"
|
|
237
639
|
});
|
|
238
640
|
var RELEASE_DEFAULTS = Object.freeze({
|
|
239
|
-
releaseEnabled:
|
|
641
|
+
releaseEnabled: RELEASE_AUTO2,
|
|
240
642
|
releaseVersionFile: "package.json",
|
|
241
643
|
releaseChangelog: "CHANGELOG.md",
|
|
242
644
|
releaseHeading: "## {version} \u2014 {date}, {title}",
|
|
@@ -250,7 +652,7 @@ var DANGEROUS_RELEASE_DEFAULTS = Object.freeze({
|
|
|
250
652
|
dangerousAcceptVersionCollision: false
|
|
251
653
|
});
|
|
252
654
|
var PR_SETTINGS = {
|
|
253
|
-
prProvider: { key: "pr.provider", read: oneOf(
|
|
655
|
+
prProvider: { key: "pr.provider", read: oneOf(PR_PROVIDERS2), cli: false },
|
|
254
656
|
prMergeMethod: { key: "pr.mergeMethod", read: mergeMethod, cli: false },
|
|
255
657
|
prBase: { key: "pr.base", read: text("a branch name"), cli: false },
|
|
256
658
|
prResolveBudget: { key: "pr.resolveBudget", read: usdAmount, cli: false },
|
|
@@ -313,7 +715,8 @@ var TESTS_DEFAULTS = Object.freeze({
|
|
|
313
715
|
"**/*.integration.test.ts",
|
|
314
716
|
"**/*-spawned*.test.ts",
|
|
315
717
|
"**/*-cli.test.ts"
|
|
316
|
-
])
|
|
718
|
+
]),
|
|
719
|
+
testsAlwaysRun: Object.freeze(["src/**/*.sweep.test.ts"])
|
|
317
720
|
});
|
|
318
721
|
var TESTS_SETTINGS = {
|
|
319
722
|
testsFullSuiteTriggers: {
|
|
@@ -321,7 +724,8 @@ var TESTS_SETTINGS = {
|
|
|
321
724
|
read: globList,
|
|
322
725
|
cli: false
|
|
323
726
|
},
|
|
324
|
-
testsIntegration: { key: "tests.integration", read: globList, cli: false }
|
|
727
|
+
testsIntegration: { key: "tests.integration", read: globList, cli: false },
|
|
728
|
+
testsAlwaysRun: { key: "tests.alwaysRun", read: globList, cli: false }
|
|
325
729
|
};
|
|
326
730
|
|
|
327
731
|
// src/config-schema-triage.ts
|
|
@@ -435,10 +839,10 @@ function sameItemGroups(holders, read) {
|
|
|
435
839
|
const groups = [];
|
|
436
840
|
for (const row of holders) {
|
|
437
841
|
const bytes = read(row.path);
|
|
438
|
-
const
|
|
439
|
-
const group =
|
|
842
|
+
const text = bytes === null ? null : comparableText(bytes);
|
|
843
|
+
const group = text === null ? undefined : groups.find((candidate) => candidate.text === text);
|
|
440
844
|
if (group === undefined)
|
|
441
|
-
groups.push({ text
|
|
845
|
+
groups.push({ text, rows: [row] });
|
|
442
846
|
else
|
|
443
847
|
group.rows.push(row);
|
|
444
848
|
}
|
|
@@ -532,16 +936,16 @@ var DEFAULT_ROUTES = Object.freeze([
|
|
|
532
936
|
var DEFAULT_ROUTING = new Map(DEFAULT_ROUTES);
|
|
533
937
|
|
|
534
938
|
// src/config-schema.ts
|
|
535
|
-
var
|
|
536
|
-
var
|
|
939
|
+
var CONFIG_FILE2 = join2(".rafa", "config.yaml");
|
|
940
|
+
var CONFIG_DEFAULTS2 = Object.freeze({
|
|
537
941
|
version: 1,
|
|
538
942
|
store: "sqlite",
|
|
539
943
|
effortBusyTimeoutMs: 5000,
|
|
540
944
|
effortSync: "local",
|
|
541
945
|
...HUB_DEFAULTS,
|
|
542
946
|
inject: "stage",
|
|
543
|
-
planDir:
|
|
544
|
-
specsDir:
|
|
947
|
+
planDir: join2(".rafa", "plans"),
|
|
948
|
+
specsDir: join2(".rafa", "specs"),
|
|
545
949
|
trackerDefault: "github",
|
|
546
950
|
trackerFallback: Object.freeze(["local"]),
|
|
547
951
|
learningAdapter: "local",
|
|
@@ -557,7 +961,7 @@ var CONFIG_DEFAULTS = Object.freeze({
|
|
|
557
961
|
modules: Object.freeze([]),
|
|
558
962
|
allowList: Object.freeze([]),
|
|
559
963
|
settingSources: Object.freeze(["project", "local"]),
|
|
560
|
-
loopWorktreeDir:
|
|
964
|
+
loopWorktreeDir: join2(".rafa", "worktrees"),
|
|
561
965
|
...WRAP_UP_DEFAULTS,
|
|
562
966
|
...PR_DEFAULTS,
|
|
563
967
|
boardTrustedAuthors: Object.freeze([]),
|
|
@@ -583,12 +987,12 @@ var CONFIG_DEFAULTS = Object.freeze({
|
|
|
583
987
|
...TESTS_DEFAULTS
|
|
584
988
|
});
|
|
585
989
|
var SETTINGS = {
|
|
586
|
-
version: { key: "version", read: oneOf(
|
|
587
|
-
store: { key: "store", read: oneOf(
|
|
990
|
+
version: { key: "version", read: oneOf(CONFIG_VERSIONS2), cli: false },
|
|
991
|
+
store: { key: "store", read: oneOf(STORE_BACKENDS2), cli: true },
|
|
588
992
|
effortBusyTimeoutMs: { key: "effort.busyTimeoutMs", read: busyTimeoutMs, cli: false },
|
|
589
|
-
effortSync: { key: "effort.sync", read: oneOf(
|
|
993
|
+
effortSync: { key: "effort.sync", read: oneOf(SYNC_STRATEGIES2), cli: false },
|
|
590
994
|
...HUB_SETTINGS,
|
|
591
|
-
inject: { key: "plan.inject", read: oneOf(
|
|
995
|
+
inject: { key: "plan.inject", read: oneOf(INJECT_MODES2), cli: true },
|
|
592
996
|
planDir: { key: "plan.dir", read: directory, cli: true },
|
|
593
997
|
specsDir: { key: "specs.dir", read: directory, cli: true },
|
|
594
998
|
trackerDefault: { key: "tracker.default", read: trackerKind, cli: true },
|
|
@@ -605,7 +1009,7 @@ var SETTINGS = {
|
|
|
605
1009
|
learningBlessMinConfidence: { key: "learning.bless.minConfidence", read: confidence, cli: false },
|
|
606
1010
|
learningPromoteAfter: { key: "learning.promote.after", read: recurrenceCount, cli: false },
|
|
607
1011
|
learningPromoteMinConfidence: { key: "learning.promote.minConfidence", read: confidence, cli: false },
|
|
608
|
-
outputMode: { key: "output.mode", read: oneOf(
|
|
1012
|
+
outputMode: { key: "output.mode", read: oneOf(OUTPUT_MODES2), cli: true },
|
|
609
1013
|
prerequisitesRequired: {
|
|
610
1014
|
key: "prerequisites.required",
|
|
611
1015
|
read: listOf(requiredPrerequisite, "prerequisite items"),
|
|
@@ -634,7 +1038,7 @@ var SETTINGS = {
|
|
|
634
1038
|
},
|
|
635
1039
|
settingSources: {
|
|
636
1040
|
key: "loop.settingSources",
|
|
637
|
-
read: subsetOf(
|
|
1041
|
+
read: subsetOf(CLAUDE_SETTING_SOURCES2),
|
|
638
1042
|
cli: true
|
|
639
1043
|
},
|
|
640
1044
|
loopWorktreeDir: { key: "loop.worktreeDir", read: directory, cli: false },
|
|
@@ -647,7 +1051,7 @@ var SETTINGS = {
|
|
|
647
1051
|
},
|
|
648
1052
|
boardRelationships: {
|
|
649
1053
|
key: "board.relationships",
|
|
650
|
-
read: oneOf(
|
|
1054
|
+
read: oneOf(BOARD_RELATIONSHIP_MODES2),
|
|
651
1055
|
cli: false
|
|
652
1056
|
},
|
|
653
1057
|
roadmapIssue: { key: "roadmap.issue", read: issueNumber, cli: false },
|
|
@@ -730,8 +1134,8 @@ function knownKeysAbove(key) {
|
|
|
730
1134
|
}
|
|
731
1135
|
|
|
732
1136
|
// src/config.ts
|
|
733
|
-
import { join as
|
|
734
|
-
class
|
|
1137
|
+
import { join as join3 } from "path";
|
|
1138
|
+
class ConfigError2 extends Error {
|
|
735
1139
|
problems;
|
|
736
1140
|
constructor(problems, options) {
|
|
737
1141
|
super(`rafa config: ${problems.join("; ")}`, options);
|
|
@@ -814,7 +1218,8 @@ function readLayer(rawOf, atOf) {
|
|
|
814
1218
|
taskSkills: read("taskSkills"),
|
|
815
1219
|
taskLessons: read("taskLessons"),
|
|
816
1220
|
testsFullSuiteTriggers: read("testsFullSuiteTriggers"),
|
|
817
|
-
testsIntegration: read("testsIntegration")
|
|
1221
|
+
testsIntegration: read("testsIntegration"),
|
|
1222
|
+
testsAlwaysRun: read("testsAlwaysRun")
|
|
818
1223
|
};
|
|
819
1224
|
return { layer, problems, extras };
|
|
820
1225
|
}
|
|
@@ -855,28 +1260,28 @@ function sortKeys(document, path) {
|
|
|
855
1260
|
return { named, extras, problems };
|
|
856
1261
|
}
|
|
857
1262
|
var TAB_INDENTED_LINE = /^[ \t]*\t[ \t]*[^\s#]/;
|
|
858
|
-
function tabIndentProblems(
|
|
859
|
-
return
|
|
1263
|
+
function tabIndentProblems(text, path) {
|
|
1264
|
+
return text.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`] : []);
|
|
860
1265
|
}
|
|
861
|
-
function parseYaml(
|
|
862
|
-
const tabProblems = tabIndentProblems(
|
|
1266
|
+
function parseYaml(text, path) {
|
|
1267
|
+
const tabProblems = tabIndentProblems(text, path);
|
|
863
1268
|
if (tabProblems.length > 0)
|
|
864
|
-
throw new
|
|
1269
|
+
throw new ConfigError2(tabProblems);
|
|
865
1270
|
try {
|
|
866
|
-
return Bun.YAML.parse(
|
|
1271
|
+
return Bun.YAML.parse(text);
|
|
867
1272
|
} catch (error) {
|
|
868
1273
|
const problem = `${path}: not valid YAML (${messageOf(error)})`;
|
|
869
|
-
throw new
|
|
1274
|
+
throw new ConfigError2([problem], { cause: error });
|
|
870
1275
|
}
|
|
871
1276
|
}
|
|
872
|
-
function
|
|
873
|
-
return
|
|
1277
|
+
function configFilePath2(root) {
|
|
1278
|
+
return join3(root, CONFIG_FILE2);
|
|
874
1279
|
}
|
|
875
|
-
function
|
|
876
|
-
const document = parseYaml(
|
|
1280
|
+
function parseConfigText2(text, path) {
|
|
1281
|
+
const document = parseYaml(text, path) ?? {};
|
|
877
1282
|
if (!isMapping(document)) {
|
|
878
1283
|
const found = describeValue(document);
|
|
879
|
-
throw new
|
|
1284
|
+
throw new ConfigError2([
|
|
880
1285
|
`${path}: expected a mapping at the top level, found ${found}`
|
|
881
1286
|
]);
|
|
882
1287
|
}
|
|
@@ -887,7 +1292,7 @@ function parseConfigText(text2, path) {
|
|
|
887
1292
|
}));
|
|
888
1293
|
const all = [...sorted.problems, ...read.problems];
|
|
889
1294
|
if (all.length > 0)
|
|
890
|
-
throw new
|
|
1295
|
+
throw new ConfigError2(all);
|
|
891
1296
|
return { path, values: read.layer, extras: [...sorted.extras, ...read.extras] };
|
|
892
1297
|
}
|
|
893
1298
|
var MAP_SETTINGS = new Set([
|
|
@@ -918,13 +1323,13 @@ function unknownKeyWarning(key, path) {
|
|
|
918
1323
|
const where = under === "" ? "" : ` under ${under}`;
|
|
919
1324
|
return `rafa config: unknown key ${quoted} in ${path} has no effect ` + `in this version (known keys${where}: ${names.join(", ")})`;
|
|
920
1325
|
}
|
|
921
|
-
function
|
|
1326
|
+
function resolveConfig2(layers = {}) {
|
|
922
1327
|
const file = layers.file ?? null;
|
|
923
1328
|
const user = layers.user ?? null;
|
|
924
1329
|
const overrides = layers.cli ?? {};
|
|
925
1330
|
const { layer: cli, problems } = readLayer((setting) => isCommandLineSetting(setting) ? overrides[setting] : undefined, (setting) => ({ label: `command line: ${setting}`, key: setting }));
|
|
926
1331
|
if (problems.length > 0)
|
|
927
|
-
throw new
|
|
1332
|
+
throw new ConfigError2(problems);
|
|
928
1333
|
const rank = (setting) => {
|
|
929
1334
|
const fromCli = cli[setting];
|
|
930
1335
|
if (fromCli !== undefined)
|
|
@@ -932,7 +1337,7 @@ function resolveConfig(layers = {}) {
|
|
|
932
1337
|
const fromFile = file?.values[setting];
|
|
933
1338
|
const fromUser = user?.values[setting];
|
|
934
1339
|
if (MAP_SETTINGS.has(setting)) {
|
|
935
|
-
const merged = mergeMaps(
|
|
1340
|
+
const merged = mergeMaps(CONFIG_DEFAULTS2[setting], fromUser, fromFile);
|
|
936
1341
|
const source = fromFile !== undefined ? "file" : fromUser !== undefined ? "user" : "default";
|
|
937
1342
|
return { value: merged, source };
|
|
938
1343
|
}
|
|
@@ -940,7 +1345,7 @@ function resolveConfig(layers = {}) {
|
|
|
940
1345
|
return { value: fromFile, source: "file" };
|
|
941
1346
|
if (fromUser !== undefined)
|
|
942
1347
|
return { value: fromUser, source: "user" };
|
|
943
|
-
return { value:
|
|
1348
|
+
return { value: CONFIG_DEFAULTS2[setting], source: "default" };
|
|
944
1349
|
};
|
|
945
1350
|
const ranked = SETTING_NAMES.map((setting) => [setting, rank(setting)]);
|
|
946
1351
|
const effortSync = rank("effortSync");
|
|
@@ -951,7 +1356,7 @@ function resolveConfig(layers = {}) {
|
|
|
951
1356
|
paths: { file: file?.path ?? null, user: user?.path ?? null }
|
|
952
1357
|
});
|
|
953
1358
|
if (hubProblems.length > 0)
|
|
954
|
-
throw new
|
|
1359
|
+
throw new ConfigError2(hubProblems);
|
|
955
1360
|
const rafaLoaded = ranked.find(([setting]) => setting === "tiersRafa")?.[1].value !== "off";
|
|
956
1361
|
const warnings = [user, file].flatMap((layer) => layer === null ? [] : [
|
|
957
1362
|
...layer.extras.map((extra) => unknownKeyWarning(extra.key, layer.path)),
|
|
@@ -969,7 +1374,7 @@ function resolveConfig(layers = {}) {
|
|
|
969
1374
|
}
|
|
970
1375
|
|
|
971
1376
|
// src/plan/blocks.ts
|
|
972
|
-
var
|
|
1377
|
+
var RAFA_BLOCK_KINDS2 = [
|
|
973
1378
|
"plan",
|
|
974
1379
|
"context",
|
|
975
1380
|
"stage-context",
|
|
@@ -978,8 +1383,8 @@ var RAFA_BLOCK_KINDS = [
|
|
|
978
1383
|
var RAFA_PREFIX = "rafa:";
|
|
979
1384
|
var FENCE_RUN = /^( {0,3})(`{3,}|~{3,})/;
|
|
980
1385
|
var CLOSING_FENCE = /^ {0,3}(`{3,}|~{3,})[ \t]*$/;
|
|
981
|
-
function
|
|
982
|
-
return
|
|
1386
|
+
function isRafaBlockKind2(kind) {
|
|
1387
|
+
return RAFA_BLOCK_KINDS2.includes(kind);
|
|
983
1388
|
}
|
|
984
1389
|
function linesOf(markdown) {
|
|
985
1390
|
const lines = markdown.split(`
|
|
@@ -1023,7 +1428,7 @@ function dedent(line, indent) {
|
|
|
1023
1428
|
cut += 1;
|
|
1024
1429
|
return line.slice(cut);
|
|
1025
1430
|
}
|
|
1026
|
-
function
|
|
1431
|
+
function readRafaBlocks2(markdown) {
|
|
1027
1432
|
const lines = linesOf(markdown);
|
|
1028
1433
|
const blocks = [];
|
|
1029
1434
|
let index = 0;
|
|
@@ -1047,9 +1452,9 @@ function readRafaBlocks(markdown) {
|
|
|
1047
1452
|
}
|
|
1048
1453
|
|
|
1049
1454
|
// src/report/parse.ts
|
|
1050
|
-
var
|
|
1051
|
-
var
|
|
1052
|
-
var
|
|
1455
|
+
var REPORT_STATUSES2 = ["done", "blocked"];
|
|
1456
|
+
var FINDING_KINDS2 = ["gotcha", "pattern", "location", "skill-suggestion"];
|
|
1457
|
+
var FINDING_SIGNALS2 = ["loud", "silent"];
|
|
1053
1458
|
var FINDING_DOMAINS = [
|
|
1054
1459
|
"code-style",
|
|
1055
1460
|
"testing",
|
|
@@ -1105,11 +1510,11 @@ function describeValue2(value) {
|
|
|
1105
1510
|
function messageOf2(error) {
|
|
1106
1511
|
return error instanceof Error ? error.message : String(error);
|
|
1107
1512
|
}
|
|
1108
|
-
function reportIssue(reason, field,
|
|
1109
|
-
return { reason, field, text
|
|
1513
|
+
function reportIssue(reason, field, text) {
|
|
1514
|
+
return { reason, field, text };
|
|
1110
1515
|
}
|
|
1111
|
-
function absent(reason, block,
|
|
1112
|
-
return { present: false, reason, block, text
|
|
1516
|
+
function absent(reason, block, text) {
|
|
1517
|
+
return { present: false, reason, block, text };
|
|
1113
1518
|
}
|
|
1114
1519
|
function scopeOf(mapping, keys, prefix, issues) {
|
|
1115
1520
|
const fields = new Map;
|
|
@@ -1181,8 +1586,8 @@ function listField(scope, key, readEntry) {
|
|
|
1181
1586
|
function entryScope(item, field, keys, issues) {
|
|
1182
1587
|
if (isMapping2(item))
|
|
1183
1588
|
return scopeOf(item, keys, `${field}.`, issues);
|
|
1184
|
-
const
|
|
1185
|
-
issues.push(reportIssue("unusable-field", field,
|
|
1589
|
+
const text = `${field} is ${describeValue2(item)}, not a mapping of ${keys.join(", ")}; dropped`;
|
|
1590
|
+
issues.push(reportIssue("unusable-field", field, text));
|
|
1186
1591
|
return null;
|
|
1187
1592
|
}
|
|
1188
1593
|
function readSkill(item, field, issues) {
|
|
@@ -1198,12 +1603,12 @@ function readFinding(item, field, issues) {
|
|
|
1198
1603
|
return null;
|
|
1199
1604
|
return {
|
|
1200
1605
|
trigger: stringField(scope, "trigger", REQUIRED),
|
|
1201
|
-
kind: choiceField(scope, "kind",
|
|
1606
|
+
kind: choiceField(scope, "kind", FINDING_KINDS2, REQUIRED),
|
|
1202
1607
|
what: stringField(scope, "what", REQUIRED),
|
|
1203
1608
|
cause: stringField(scope, "cause", OPTIONAL),
|
|
1204
1609
|
resolution: stringField(scope, "resolution", OPTIONAL),
|
|
1205
1610
|
artifact: stringField(scope, "artifact", OPTIONAL),
|
|
1206
|
-
signal: choiceField(scope, "signal",
|
|
1611
|
+
signal: choiceField(scope, "signal", FINDING_SIGNALS2, REQUIRED),
|
|
1207
1612
|
domain: choiceField(scope, "domain", FINDING_DOMAINS, OPTIONAL),
|
|
1208
1613
|
extras: scope.extras
|
|
1209
1614
|
};
|
|
@@ -1243,7 +1648,7 @@ function readChange(item, field, issues) {
|
|
|
1243
1648
|
function readReport(document, issues) {
|
|
1244
1649
|
const scope = scopeOf(document, REPORT_KEYS, "", issues);
|
|
1245
1650
|
return {
|
|
1246
|
-
status: choiceField(scope, "status",
|
|
1651
|
+
status: choiceField(scope, "status", REPORT_STATUSES2, REQUIRED),
|
|
1247
1652
|
feedback: stringField(scope, "feedback", OPTIONAL),
|
|
1248
1653
|
findings: listField(scope, "findings", readFinding),
|
|
1249
1654
|
skillsUsed: listField(scope, "skills_used", readSkill),
|
|
@@ -1253,8 +1658,8 @@ function readReport(document, issues) {
|
|
|
1253
1658
|
extras: scope.extras
|
|
1254
1659
|
};
|
|
1255
1660
|
}
|
|
1256
|
-
function
|
|
1257
|
-
const reports =
|
|
1661
|
+
function parseReport2(output) {
|
|
1662
|
+
const reports = readRafaBlocks2(output).filter((block) => block.kind === REPORT_KIND);
|
|
1258
1663
|
const block = reports.at(-1);
|
|
1259
1664
|
if (block === undefined) {
|
|
1260
1665
|
return absent("no-block", null, "the session output holds no rafa:report block");
|
|
@@ -1267,12 +1672,12 @@ function parseReport(output) {
|
|
|
1267
1672
|
try {
|
|
1268
1673
|
document = Bun.YAML.parse(block.body);
|
|
1269
1674
|
} catch (error) {
|
|
1270
|
-
const
|
|
1271
|
-
return absent("malformed-block", block,
|
|
1675
|
+
const text = `rafa:report block at line ${line} is not valid YAML (${messageOf2(error)})`;
|
|
1676
|
+
return absent("malformed-block", block, text);
|
|
1272
1677
|
}
|
|
1273
1678
|
if (!isMapping2(document)) {
|
|
1274
|
-
const
|
|
1275
|
-
return absent("malformed-block", block,
|
|
1679
|
+
const text = `rafa:report block at line ${line} holds ${describeValue2(document)}, ` + "not a mapping of report fields";
|
|
1680
|
+
return absent("malformed-block", block, text);
|
|
1276
1681
|
}
|
|
1277
1682
|
const issues = [];
|
|
1278
1683
|
const report = readReport(document, issues);
|
|
@@ -1400,4 +1805,4 @@ function activeOutputMode() {
|
|
|
1400
1805
|
return activeMode;
|
|
1401
1806
|
}
|
|
1402
1807
|
|
|
1403
|
-
export { hubContextOf,
|
|
1808
|
+
export { MERGE_METHODS, isMergeMethod, SKILL_TIERS, RAFA_INSTINCTS_PATH, BUNDLED_SKILLS_DIR, isSkillTier, realEntry, bundledBinDirectory, skillTierDirectory, resolveSkillTiers, resolveInstinctScopes, tierExists, TEST_SCOPES, isAgentName, BUDGET_FLAG, parseBudgetUsd, readTestScope, parseTaskDeclaration, stripTaskDeclaration, resolveDeclarationFlags, isMapping, describeValue, messageOf, CONFIG_VERSIONS2, STORE_BACKENDS2, SYNC_STRATEGIES2, BOARD_RELATIONSHIP_MODES2, INJECT_MODES2, OUTPUT_MODES2, CLAUDE_SETTING_SOURCES2, PR_PROVIDERS2, RELEASE_AUTO2, SKILL_RESOLVERS, CLAIMS_STALE_DISABLED, BUSY_TIMEOUT_MIN_MS, BUSY_TIMEOUT_MAX_MS, isBusyTimeoutMs, claimDurationHours, isGitHubLogin, listOf, hubContextOf, PREREQUISITE_KINDS2, requiredPrerequisite, optionalPrerequisite, MODULE_SOURCE_KINDS2, pinKey, pinLine, collisionMessage, readItemBytes, resolveTiers, findTierItem, DEFAULT_ROUTES, DEFAULT_ROUTING, CONFIG_FILE2, CONFIG_DEFAULTS2, SETTINGS, ConfigError2, configFilePath2, parseConfigText2, resolveConfig2, isStampableStub, planStubFromPrompt, stampPrompt, planStubFromPath, createTextOutput, activeOutput, activeOutputMode, RAFA_BLOCK_KINDS2, isRafaBlockKind2, readRafaBlocks2, REPORT_STATUSES2, FINDING_KINDS2, FINDING_SIGNALS2, FINDING_DOMAINS, CHANGE_LEVELS, parseReport2 };
|