@open-tomato/rafa 0.45.0 → 0.46.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 +255 -23
- package/dist/PROMPT.md +18 -1
- package/dist/adapters/logger/settings.d.ts +132 -0
- package/dist/bugs/closest.d.ts +19 -0
- package/dist/bugs/fenced.d.ts +8 -0
- package/dist/bugs/places.d.ts +20 -0
- package/dist/bugs/record.d.ts +145 -0
- package/dist/bugs/title.d.ts +83 -0
- package/dist/bundled/agents/doc-updater.md +17 -3
- package/dist/bundled/agents/loop-implementer.md +14 -2
- package/dist/bundled/operators/skills/rafa-stretch-pit-stop/SKILL.md +10 -3
- package/dist/bundled/operators/skills/rafa-stretch-sweep/SKILL.md +5 -0
- package/dist/bundled/skills/dev-planner/SKILL.md +101 -18
- package/dist/cli.js +74726 -62960
- package/dist/config/entry.d.ts +119 -0
- package/dist/config/index.d.ts +36 -0
- package/dist/config/index.js +51 -0
- package/dist/config/shape.d.ts +232 -0
- package/dist/config-registry.d.ts +127 -0
- package/dist/config-schema-board-project.d.ts +157 -0
- package/dist/config-schema-bugs.d.ts +71 -0
- package/dist/config-schema-errors.d.ts +54 -0
- package/dist/config-schema-features.d.ts +64 -0
- package/dist/config-schema-hub.d.ts +150 -0
- package/dist/config-schema-issues.d.ts +95 -0
- package/dist/config-schema-logger.d.ts +91 -0
- package/dist/config-schema-loop-continue.d.ts +122 -0
- package/dist/config-schema-loop-retries.d.ts +94 -0
- package/dist/config-schema-release.d.ts +307 -0
- package/dist/config-schema-tests.d.ts +170 -0
- package/dist/config-schema-triage.d.ts +142 -0
- package/dist/config-schema-wrap-up.d.ts +96 -0
- package/dist/core/command/command.d.ts +228 -0
- package/dist/core/command/confirm.d.ts +67 -0
- package/dist/core/command/index.d.ts +112 -0
- package/dist/core/command/lazy.d.ts +54 -0
- package/dist/core/command/registry-types.d.ts +96 -0
- package/dist/core/command/running.d.ts +96 -0
- package/dist/core/command/spends.d.ts +39 -0
- package/dist/core/command/types.d.ts +92 -0
- package/dist/core/command/version.d.ts +4 -0
- package/dist/core/config/branch-template.d.ts +20 -0
- package/dist/core/config/config-items.d.ts +86 -0
- package/dist/core/config/config-load.d.ts +47 -0
- package/dist/core/config/config-origins.d.ts +57 -0
- package/dist/core/config/config-readers.d.ts +167 -0
- package/dist/core/config/config-schema.d.ts +207 -0
- package/dist/core/config/config-sections.d.ts +493 -0
- package/dist/core/config/config.d.ts +320 -0
- package/dist/core/config/core-section.d.ts +39 -0
- package/dist/core/config/dangerous.d.ts +58 -0
- package/dist/core/config/default-routing.d.ts +16 -0
- package/dist/core/config/index.d.ts +141 -0
- package/dist/core/config/scope.d.ts +42 -0
- package/dist/core/config/section.d.ts +206 -0
- package/dist/core/config/sections.d.ts +45 -0
- package/dist/core/config/standard-schema.d.ts +27 -0
- package/dist/core/git/commit.d.ts +232 -0
- package/dist/core/git/gh-runner.d.ts +24 -0
- package/dist/core/git/git.d.ts +22 -0
- package/dist/core/git/index.d.ts +85 -0
- package/dist/core/loop/claude.d.ts +388 -0
- package/dist/core/loop/hop-record.d.ts +52 -0
- package/dist/core/loop/index.d.ts +179 -0
- package/dist/core/loop/session-env.d.ts +20 -0
- package/dist/core/loop/session-record-parse.d.ts +63 -0
- package/dist/core/loop/sessions.d.ts +408 -0
- package/dist/core/loop/suite-failure.d.ts +25 -0
- package/dist/core/output/active.d.ts +100 -0
- package/dist/core/output/stream.d.ts +20 -0
- package/dist/core/output/text.d.ts +55 -0
- package/dist/core/plan/block-reader.d.ts +46 -0
- package/dist/core/plan/blocks.d.ts +139 -0
- package/dist/core/plan/declaration.d.ts +366 -0
- package/dist/core/plan/plan-stamp.d.ts +75 -0
- package/dist/core/runtime/identity.d.ts +21 -0
- package/dist/core/runtime/index.d.ts +46 -0
- package/dist/effort/store/bring-forward.d.ts +131 -0
- package/dist/effort/store/check-rows.d.ts +31 -0
- package/dist/effort/store/commit-stats.d.ts +42 -0
- package/dist/effort/store/copy.d.ts +35 -0
- package/dist/effort/store/development-build.d.ts +105 -0
- package/dist/effort/store/effort-levels.d.ts +13 -0
- package/dist/effort/store/findings.d.ts +214 -0
- package/dist/effort/store/fix-schema.d.ts +184 -0
- package/dist/effort/store/index.js +10 -7
- package/dist/effort/store/location.d.ts +44 -0
- package/dist/effort/store/merge-commit-gaps.d.ts +68 -0
- package/dist/effort/store/merge-conflicts.d.ts +91 -0
- package/dist/effort/store/merge-rules.d.ts +82 -0
- package/dist/effort/store/merge-store.d.ts +211 -0
- package/dist/effort/store/merge-union.d.ts +92 -0
- package/dist/effort/store/migrate.d.ts +146 -0
- package/dist/effort/store/migrations.d.ts +92 -0
- package/dist/effort/store/ndjson-files.d.ts +114 -0
- package/dist/effort/store/origins.d.ts +116 -0
- package/dist/effort/store/plan-stubs.d.ts +79 -0
- package/dist/effort/store/rebuild-aside.d.ts +172 -0
- package/dist/effort/store/schema-plan.d.ts +102 -0
- package/dist/effort/store/session-row-types.d.ts +64 -0
- package/dist/effort/store/settings.d.ts +13 -0
- package/dist/effort/store/sqlite.d.ts +340 -0
- package/dist/effort/store/store-generation.d.ts +17 -0
- package/dist/effort/store/store-identity.d.ts +220 -0
- package/dist/effort/store/store-meta.d.ts +305 -0
- package/dist/effort/store/store-replaced.d.ts +72 -0
- package/dist/effort/store/types.d.ts +223 -0
- package/dist/errors/codes.d.ts +56 -0
- package/dist/errors/rafa-codes.d.ts +36 -0
- package/dist/index-2a7nb3an.js +125 -0
- package/dist/{index-r28fzsvc.js → index-39kbcw68.js} +350 -165
- package/dist/{index-nv34ptht.js → index-77ajfffn.js} +14 -9
- package/dist/index-cy98y87p.js +2597 -0
- package/dist/index-gqz4jn6j.js +13447 -0
- package/dist/index-gvek4r8m.js +710 -0
- package/dist/index-j4k2vdz3.js +1125 -0
- package/dist/index-jh1r4kcn.js +1067 -0
- package/dist/{index-mgh2s9bj.js → index-ykggr043.js} +58 -455
- package/dist/index-z1w83f81.js +4 -0
- package/dist/index.js +14715 -21516
- package/dist/learning/index.js +5 -6
- package/dist/plan/index.js +12 -11
- package/dist/plan-prompt.md +3 -1
- package/dist/ports/index.d.ts +732 -0
- package/dist/ports/learning.d.ts +101 -0
- package/dist/ports/log-level.d.ts +13 -0
- package/dist/ports/spec-review.d.ts +66 -0
- package/dist/pr/checks.d.ts +133 -0
- package/dist/pr/types.d.ts +422 -0
- package/dist/ready-4f8edezt.js +2016 -0
- package/dist/release-templates/release-bot-fragment.yml +153 -0
- package/dist/release-templates/release-publish.yml +110 -0
- package/dist/release-templates/release-settle.yml +122 -0
- package/dist/release-templates/release-tag.yml +102 -0
- package/dist/report/parse.d.ts +415 -0
- package/dist/schema/project-id.d.ts +79 -0
- package/dist/schema/tiers.d.ts +107 -0
- package/package.json +41 -3
- package/dist/index-hf2k497d.js +0 -16
- package/dist/index-nsr78ct2.js +0 -8219
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
activeOutput,
|
|
4
|
-
isStampableStub
|
|
4
|
+
isStampableStub
|
|
5
|
+
} from "./index-2a7nb3an.js";
|
|
6
|
+
import {
|
|
5
7
|
messageOf,
|
|
6
|
-
parseTaskDeclaration
|
|
7
|
-
|
|
8
|
-
} from "./index-mgh2s9bj.js";
|
|
8
|
+
parseTaskDeclaration
|
|
9
|
+
} from "./index-ykggr043.js";
|
|
9
10
|
// src/preflight/prerequisites-md.ts
|
|
10
11
|
import { basename, dirname, join } from "path";
|
|
11
12
|
var SECTION_AUTO_RE = /\[auto\]/i;
|
|
@@ -390,14 +391,341 @@ async function runPreflight(items, options) {
|
|
|
390
391
|
knownMissing: Object.freeze(knownMissing)
|
|
391
392
|
});
|
|
392
393
|
}
|
|
393
|
-
// src/
|
|
394
|
-
|
|
394
|
+
// packages/rafa/src/core/plan/blocks.ts
|
|
395
|
+
var RAFA_BLOCK_KINDS = [
|
|
396
|
+
"plan",
|
|
397
|
+
"context",
|
|
398
|
+
"stage-context",
|
|
399
|
+
"report"
|
|
400
|
+
];
|
|
401
|
+
var RAFA_PREFIX = "rafa:";
|
|
402
|
+
var FENCE_RUN = /^( {0,3})(`{3,}|~{3,})/;
|
|
403
|
+
var CLOSING_FENCE = /^ {0,3}(`{3,}|~{3,})[ \t]*$/;
|
|
404
|
+
function isRafaBlockKind(kind) {
|
|
405
|
+
return RAFA_BLOCK_KINDS.includes(kind);
|
|
406
|
+
}
|
|
407
|
+
function linesOf(markdown) {
|
|
408
|
+
const lines = markdown.split(`
|
|
409
|
+
`);
|
|
410
|
+
if (lines[lines.length - 1] === "")
|
|
411
|
+
lines.pop();
|
|
412
|
+
return lines.map((line) => line.endsWith("\r") ? line.slice(0, -1) : line);
|
|
413
|
+
}
|
|
414
|
+
function kindOf(info) {
|
|
415
|
+
const word = info.trim().split(/\s+/)[0] ?? "";
|
|
416
|
+
return word.startsWith(RAFA_PREFIX) ? word.slice(RAFA_PREFIX.length) : null;
|
|
417
|
+
}
|
|
418
|
+
function openingFence(line) {
|
|
419
|
+
const match = FENCE_RUN.exec(line);
|
|
420
|
+
const opener = match?.[0];
|
|
421
|
+
const indent = match?.[1];
|
|
422
|
+
const run = match?.[2];
|
|
423
|
+
if (opener === undefined || indent === undefined || run === undefined) {
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
426
|
+
const marker = run.charAt(0);
|
|
427
|
+
const info = line.slice(opener.length);
|
|
428
|
+
if (marker === "`" && info.includes("`"))
|
|
429
|
+
return null;
|
|
430
|
+
return { marker, length: run.length, indent: indent.length, kind: kindOf(info) };
|
|
431
|
+
}
|
|
432
|
+
function closes(line, fence) {
|
|
433
|
+
const run = CLOSING_FENCE.exec(line)?.[1];
|
|
434
|
+
return run !== undefined && run.charAt(0) === fence.marker && run.length >= fence.length;
|
|
435
|
+
}
|
|
436
|
+
function closingIndex(lines, from, fence) {
|
|
437
|
+
for (let index = from;index < lines.length; index += 1) {
|
|
438
|
+
if (closes(lines[index] ?? "", fence))
|
|
439
|
+
return index;
|
|
440
|
+
}
|
|
441
|
+
return lines.length;
|
|
442
|
+
}
|
|
443
|
+
function dedent(line, indent) {
|
|
444
|
+
let cut = 0;
|
|
445
|
+
while (cut < indent && line.charAt(cut) === " ")
|
|
446
|
+
cut += 1;
|
|
447
|
+
return line.slice(cut);
|
|
448
|
+
}
|
|
449
|
+
function readRafaBlocks(markdown) {
|
|
450
|
+
const lines = linesOf(markdown);
|
|
451
|
+
const blocks = [];
|
|
452
|
+
let index = 0;
|
|
453
|
+
while (index < lines.length) {
|
|
454
|
+
const fence = openingFence(lines[index] ?? "");
|
|
455
|
+
if (fence === null) {
|
|
456
|
+
index += 1;
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
const closing = closingIndex(lines, index + 1, fence);
|
|
460
|
+
const closed = closing < lines.length;
|
|
461
|
+
if (fence.kind !== null) {
|
|
462
|
+
const body = lines.slice(index + 1, closing).map((line) => dedent(line, fence.indent)).join(`
|
|
463
|
+
`);
|
|
464
|
+
const last = closed ? closing + 1 : lines.length;
|
|
465
|
+
blocks.push({ kind: fence.kind, body, span: { first: index + 1, last }, closed });
|
|
466
|
+
}
|
|
467
|
+
index = closing + 1;
|
|
468
|
+
}
|
|
469
|
+
return blocks;
|
|
470
|
+
}
|
|
471
|
+
// packages/rafa/src/report/parse.ts
|
|
472
|
+
var REPORT_STATUSES = ["done", "blocked"];
|
|
473
|
+
var FINDING_KINDS = ["gotcha", "pattern", "location", "skill-suggestion"];
|
|
474
|
+
var FINDING_SIGNALS = ["loud", "silent"];
|
|
475
|
+
var FINDING_DOMAINS = [
|
|
476
|
+
"code-style",
|
|
477
|
+
"testing",
|
|
478
|
+
"git",
|
|
479
|
+
"debugging",
|
|
480
|
+
"workflow",
|
|
481
|
+
"security",
|
|
482
|
+
"general-best-practices"
|
|
483
|
+
];
|
|
484
|
+
var CHANGE_LEVELS = ["patch", "minor", "major", "none"];
|
|
485
|
+
var BUG_KINDS = ["bug", "own-fallout", "own-gap", "convention", "docs", "machine"];
|
|
486
|
+
var DEFAULT_BUG_KIND = "bug";
|
|
487
|
+
var REPORT_KIND = "report";
|
|
488
|
+
var REQUIRED = true;
|
|
489
|
+
var OPTIONAL = false;
|
|
490
|
+
var REPORT_KEYS = [
|
|
491
|
+
"status",
|
|
492
|
+
"feedback",
|
|
493
|
+
"findings",
|
|
494
|
+
"skills_used",
|
|
495
|
+
"blockers",
|
|
496
|
+
"out_of_scope_bugs",
|
|
497
|
+
"changes",
|
|
498
|
+
"stale_docs"
|
|
499
|
+
];
|
|
500
|
+
var FINDING_KEYS = [
|
|
501
|
+
"trigger",
|
|
502
|
+
"kind",
|
|
503
|
+
"what",
|
|
504
|
+
"cause",
|
|
505
|
+
"resolution",
|
|
506
|
+
"artifact",
|
|
507
|
+
"signal",
|
|
508
|
+
"domain"
|
|
509
|
+
];
|
|
510
|
+
var BLOCKER_KEYS = ["what", "artifact"];
|
|
511
|
+
var BUG_KEYS = ["what", "artifact", "security", "kind", "module", "action", "reproduce", "cause"];
|
|
512
|
+
var CHANGE_KEYS = ["level", "area", "summary"];
|
|
513
|
+
var STALE_DOC_KEYS = ["where", "what"];
|
|
514
|
+
function isMapping(value) {
|
|
515
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
516
|
+
}
|
|
517
|
+
function isOneOf(choices, value) {
|
|
518
|
+
return choices.includes(value);
|
|
519
|
+
}
|
|
520
|
+
function describeValue(value) {
|
|
521
|
+
if (typeof value === "string")
|
|
522
|
+
return JSON.stringify(value);
|
|
523
|
+
if (value === null)
|
|
524
|
+
return "nothing";
|
|
525
|
+
if (Array.isArray(value))
|
|
526
|
+
return "a list";
|
|
527
|
+
if (typeof value === "object")
|
|
528
|
+
return "a mapping";
|
|
529
|
+
return `the ${typeof value} ${String(value)}`;
|
|
530
|
+
}
|
|
531
|
+
function messageOf2(error) {
|
|
532
|
+
return error instanceof Error ? error.message : String(error);
|
|
533
|
+
}
|
|
534
|
+
function reportIssue(reason, field, text) {
|
|
535
|
+
return { reason, field, text };
|
|
536
|
+
}
|
|
537
|
+
function absent(reason, block, text) {
|
|
538
|
+
return { present: false, reason, block, text };
|
|
539
|
+
}
|
|
540
|
+
function scopeOf(mapping, keys, prefix, issues) {
|
|
541
|
+
const fields = new Map;
|
|
542
|
+
const extras = [];
|
|
543
|
+
for (const [key, value] of Object.entries(mapping)) {
|
|
544
|
+
if (keys.includes(key))
|
|
545
|
+
fields.set(key, value);
|
|
546
|
+
else
|
|
547
|
+
extras.push({ key, value });
|
|
548
|
+
}
|
|
549
|
+
return { fields, extras, prefix, issues };
|
|
550
|
+
}
|
|
551
|
+
function valueOf(scope, key, required) {
|
|
552
|
+
const value = scope.fields.get(key) ?? null;
|
|
553
|
+
if (value === null && required) {
|
|
554
|
+
const field = `${scope.prefix}${key}`;
|
|
555
|
+
scope.issues.push(reportIssue("missing-field", field, `${field} is missing`));
|
|
556
|
+
}
|
|
557
|
+
return value;
|
|
558
|
+
}
|
|
559
|
+
function unusable(scope, key, why) {
|
|
560
|
+
const field = `${scope.prefix}${key}`;
|
|
561
|
+
scope.issues.push(reportIssue("unusable-field", field, `${field} ${why}`));
|
|
562
|
+
return null;
|
|
563
|
+
}
|
|
564
|
+
function stringProblem(value) {
|
|
565
|
+
if (typeof value !== "string")
|
|
566
|
+
return `is ${describeValue(value)}, not a string; quote it`;
|
|
567
|
+
if (value.trim().length === 0)
|
|
568
|
+
return "is blank";
|
|
569
|
+
return null;
|
|
570
|
+
}
|
|
571
|
+
function stringField(scope, key, required) {
|
|
572
|
+
const value = valueOf(scope, key, required);
|
|
573
|
+
if (value === null)
|
|
574
|
+
return null;
|
|
575
|
+
const problem = stringProblem(value);
|
|
576
|
+
return problem === null ? value : unusable(scope, key, problem);
|
|
577
|
+
}
|
|
578
|
+
function choiceField(scope, key, choices, required) {
|
|
579
|
+
const value = valueOf(scope, key, required);
|
|
580
|
+
if (value === null || isOneOf(choices, value))
|
|
581
|
+
return value;
|
|
582
|
+
return unusable(scope, key, `is ${describeValue(value)}, not one of ${choices.join(", ")}`);
|
|
583
|
+
}
|
|
584
|
+
function booleanField(scope, key, required) {
|
|
585
|
+
const value = valueOf(scope, key, required);
|
|
586
|
+
if (value === null || typeof value === "boolean")
|
|
587
|
+
return value;
|
|
588
|
+
return unusable(scope, key, `is ${describeValue(value)}, not true or false; write it unquoted`);
|
|
589
|
+
}
|
|
590
|
+
function listField(scope, key, readEntry) {
|
|
591
|
+
const value = valueOf(scope, key, OPTIONAL);
|
|
592
|
+
if (value === null)
|
|
593
|
+
return [];
|
|
594
|
+
if (!Array.isArray(value)) {
|
|
595
|
+
unusable(scope, key, `is ${describeValue(value)}, not a list`);
|
|
596
|
+
return [];
|
|
597
|
+
}
|
|
598
|
+
const entries = [];
|
|
599
|
+
const items = value;
|
|
600
|
+
for (const [index, item] of items.entries()) {
|
|
601
|
+
const entry = readEntry(item, `${scope.prefix}${key}[${index}]`, scope.issues);
|
|
602
|
+
if (entry !== null)
|
|
603
|
+
entries.push(entry);
|
|
604
|
+
}
|
|
605
|
+
return entries;
|
|
606
|
+
}
|
|
607
|
+
function entryScope(item, field, keys, issues) {
|
|
608
|
+
if (isMapping(item))
|
|
609
|
+
return scopeOf(item, keys, `${field}.`, issues);
|
|
610
|
+
const text = `${field} is ${describeValue(item)}, not a mapping of ${keys.join(", ")}; dropped`;
|
|
611
|
+
issues.push(reportIssue("unusable-field", field, text));
|
|
612
|
+
return null;
|
|
613
|
+
}
|
|
614
|
+
function readSkill(item, field, issues) {
|
|
615
|
+
const problem = stringProblem(item);
|
|
616
|
+
if (problem === null)
|
|
617
|
+
return item;
|
|
618
|
+
issues.push(reportIssue("unusable-field", field, `${field} ${problem}; dropped`));
|
|
619
|
+
return null;
|
|
620
|
+
}
|
|
621
|
+
function readFinding(item, field, issues) {
|
|
622
|
+
const scope = entryScope(item, field, FINDING_KEYS, issues);
|
|
623
|
+
if (scope === null)
|
|
624
|
+
return null;
|
|
625
|
+
return {
|
|
626
|
+
trigger: stringField(scope, "trigger", REQUIRED),
|
|
627
|
+
kind: choiceField(scope, "kind", FINDING_KINDS, REQUIRED),
|
|
628
|
+
what: stringField(scope, "what", REQUIRED),
|
|
629
|
+
cause: stringField(scope, "cause", OPTIONAL),
|
|
630
|
+
resolution: stringField(scope, "resolution", OPTIONAL),
|
|
631
|
+
artifact: stringField(scope, "artifact", OPTIONAL),
|
|
632
|
+
signal: choiceField(scope, "signal", FINDING_SIGNALS, REQUIRED),
|
|
633
|
+
domain: choiceField(scope, "domain", FINDING_DOMAINS, OPTIONAL),
|
|
634
|
+
extras: scope.extras
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
function readBlocker(item, field, issues) {
|
|
638
|
+
const scope = entryScope(item, field, BLOCKER_KEYS, issues);
|
|
639
|
+
if (scope === null)
|
|
640
|
+
return null;
|
|
641
|
+
return {
|
|
642
|
+
what: stringField(scope, "what", REQUIRED),
|
|
643
|
+
artifact: stringField(scope, "artifact", OPTIONAL),
|
|
644
|
+
extras: scope.extras
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
function readBug(item, field, issues) {
|
|
648
|
+
const scope = entryScope(item, field, BUG_KEYS, issues);
|
|
649
|
+
if (scope === null)
|
|
650
|
+
return null;
|
|
651
|
+
return {
|
|
652
|
+
what: stringField(scope, "what", REQUIRED),
|
|
653
|
+
artifact: stringField(scope, "artifact", OPTIONAL),
|
|
654
|
+
security: booleanField(scope, "security", REQUIRED),
|
|
655
|
+
kind: choiceField(scope, "kind", BUG_KINDS, OPTIONAL) ?? DEFAULT_BUG_KIND,
|
|
656
|
+
module: stringField(scope, "module", OPTIONAL),
|
|
657
|
+
action: stringField(scope, "action", OPTIONAL),
|
|
658
|
+
reproduce: stringField(scope, "reproduce", OPTIONAL),
|
|
659
|
+
cause: stringField(scope, "cause", OPTIONAL),
|
|
660
|
+
extras: scope.extras
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
function readChange(item, field, issues) {
|
|
664
|
+
const scope = entryScope(item, field, CHANGE_KEYS, issues);
|
|
665
|
+
if (scope === null)
|
|
666
|
+
return null;
|
|
667
|
+
return {
|
|
668
|
+
level: choiceField(scope, "level", CHANGE_LEVELS, REQUIRED),
|
|
669
|
+
area: stringField(scope, "area", OPTIONAL),
|
|
670
|
+
summary: stringField(scope, "summary", REQUIRED),
|
|
671
|
+
extras: scope.extras
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
function readStaleDoc(item, field, issues) {
|
|
675
|
+
const scope = entryScope(item, field, STALE_DOC_KEYS, issues);
|
|
676
|
+
if (scope === null)
|
|
677
|
+
return null;
|
|
678
|
+
const where = stringField(scope, "where", OPTIONAL);
|
|
679
|
+
const what = stringField(scope, "what", REQUIRED);
|
|
680
|
+
if (what === null)
|
|
681
|
+
return null;
|
|
682
|
+
return { where, what, extras: scope.extras };
|
|
683
|
+
}
|
|
684
|
+
function readReport(document, issues) {
|
|
685
|
+
const scope = scopeOf(document, REPORT_KEYS, "", issues);
|
|
686
|
+
return {
|
|
687
|
+
status: choiceField(scope, "status", REPORT_STATUSES, REQUIRED),
|
|
688
|
+
feedback: stringField(scope, "feedback", OPTIONAL),
|
|
689
|
+
findings: listField(scope, "findings", readFinding),
|
|
690
|
+
skillsUsed: listField(scope, "skills_used", readSkill),
|
|
691
|
+
blockers: listField(scope, "blockers", readBlocker),
|
|
692
|
+
outOfScopeBugs: listField(scope, "out_of_scope_bugs", readBug),
|
|
693
|
+
changes: listField(scope, "changes", readChange),
|
|
694
|
+
staleDocs: listField(scope, "stale_docs", readStaleDoc),
|
|
695
|
+
extras: scope.extras
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
function parseReport(output) {
|
|
699
|
+
const reports = readRafaBlocks(output).filter((block2) => block2.kind === REPORT_KIND);
|
|
700
|
+
const block = reports.at(-1);
|
|
701
|
+
if (block === undefined) {
|
|
702
|
+
return absent("no-block", null, "the session output holds no rafa:report block");
|
|
703
|
+
}
|
|
704
|
+
const line = block.span.first;
|
|
705
|
+
if (!block.closed) {
|
|
706
|
+
return absent("unclosed-block", block, `rafa:report block at line ${line} is never closed, so its body may have been cut short ` + "and is not read");
|
|
707
|
+
}
|
|
708
|
+
let document;
|
|
709
|
+
try {
|
|
710
|
+
document = Bun.YAML.parse(block.body);
|
|
711
|
+
} catch (error) {
|
|
712
|
+
const text = `rafa:report block at line ${line} is not valid YAML (${messageOf2(error)})`;
|
|
713
|
+
return absent("malformed-block", block, text);
|
|
714
|
+
}
|
|
715
|
+
if (!isMapping(document)) {
|
|
716
|
+
const text = `rafa:report block at line ${line} holds ${describeValue(document)}, ` + "not a mapping of report fields";
|
|
717
|
+
return absent("malformed-block", block, text);
|
|
718
|
+
}
|
|
719
|
+
const issues = [];
|
|
720
|
+
const report = readReport(document, issues);
|
|
721
|
+
return { present: true, report, block, issues };
|
|
722
|
+
}
|
|
723
|
+
// packages/rafa/src/core/plan/blocker-comment.ts
|
|
395
724
|
var BLOCKER_OPEN = "<!-- blocked: ";
|
|
396
725
|
var REPAIRS_OPEN = "<!-- repairs: ";
|
|
397
726
|
var BLOCKER_CLOSE = " -->";
|
|
398
727
|
var BLOCKER_GAP = " ";
|
|
399
728
|
var TRAILING_COMMENT = /\s<!-- (blocked|repairs): ((?:(?!<!--|-->).)*) -->$/;
|
|
400
|
-
var OPEN_TASK_PREFIX = /^- \[(?: |BLOCKED)\] /;
|
|
401
729
|
var ESCAPE_SEQUENCE = /\\(u[0-9A-Fa-f]{4}|[\s\S])/g;
|
|
402
730
|
var TAB = 9;
|
|
403
731
|
var FIRST_PRINTABLE = 32;
|
|
@@ -472,154 +800,7 @@ function splitBlockerComment(taskText) {
|
|
|
472
800
|
const { text, blocked } = splitTrailingComments(taskText);
|
|
473
801
|
return { text, blocker: commentText(blocked) };
|
|
474
802
|
}
|
|
475
|
-
|
|
476
|
-
return line.endsWith("\r") ? { body: line.slice(0, -1), cr: "\r" } : { body: line, cr: "" };
|
|
477
|
-
}
|
|
478
|
-
function withoutBlockerComment(line) {
|
|
479
|
-
const { body, cr } = splitCarriageReturn(line);
|
|
480
|
-
const prefix = OPEN_TASK_PREFIX.exec(body)?.[0];
|
|
481
|
-
if (prefix === undefined)
|
|
482
|
-
return line;
|
|
483
|
-
const found = splitTrailingComments(body.slice(prefix.length));
|
|
484
|
-
return found.blocked === null ? line : `${prefix}${found.text}${keptRepairs(found.repairs)}${cr}`;
|
|
485
|
-
}
|
|
486
|
-
function closedBlockLines(trackerContent) {
|
|
487
|
-
const inside = new Set;
|
|
488
|
-
for (const block of readRafaBlocks(trackerContent)) {
|
|
489
|
-
if (!block.closed)
|
|
490
|
-
continue;
|
|
491
|
-
for (let line = block.span.first;line <= block.span.last; line += 1) {
|
|
492
|
-
inside.add(line - 1);
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
return inside;
|
|
496
|
-
}
|
|
497
|
-
function taskInfoOf(capture, lineNum, status) {
|
|
498
|
-
const found = splitTrailingComments(capture.trim());
|
|
499
|
-
const blocker = commentText(found.blocked);
|
|
500
|
-
const repairs = commentText(found.repairs);
|
|
501
|
-
return {
|
|
502
|
-
task: found.text,
|
|
503
|
-
lineNum,
|
|
504
|
-
status,
|
|
505
|
-
...blocker === null ? {} : { blocker },
|
|
506
|
-
...repairs === null ? {} : { repairs }
|
|
507
|
-
};
|
|
508
|
-
}
|
|
509
|
-
var TASK_LINE_STATUSES = [
|
|
510
|
-
[/^- \[BLOCKED\] (.+)/, "blocked"],
|
|
511
|
-
[/^- \[ \] (.+)/, "unchecked"],
|
|
512
|
-
[/^- \[x\] (.+)/, "done"]
|
|
513
|
-
];
|
|
514
|
-
var NO_LINES = new Set;
|
|
515
|
-
function findNextTask(trackerContent, options = {}) {
|
|
516
|
-
const skip = options.skipLines ?? NO_LINES;
|
|
517
|
-
const open = listOpenTasks(trackerContent).filter((task) => !skip.has(task.lineNum));
|
|
518
|
-
return open.find((task) => task.status === "blocked") ?? open.find((task) => task.status === "unchecked") ?? null;
|
|
519
|
-
}
|
|
520
|
-
function listTrackerTasks(trackerContent) {
|
|
521
|
-
const lines = trackerContent.split(`
|
|
522
|
-
`);
|
|
523
|
-
const inBlock = closedBlockLines(trackerContent);
|
|
524
|
-
const tasks = [];
|
|
525
|
-
for (let i = 0;i < lines.length; i++) {
|
|
526
|
-
if (inBlock.has(i))
|
|
527
|
-
continue;
|
|
528
|
-
for (const [pattern, status] of TASK_LINE_STATUSES) {
|
|
529
|
-
const capture = lines[i].match(pattern)?.[1];
|
|
530
|
-
if (!capture)
|
|
531
|
-
continue;
|
|
532
|
-
tasks.push(taskInfoOf(capture, i, status));
|
|
533
|
-
break;
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
return tasks;
|
|
537
|
-
}
|
|
538
|
-
function isOpenTask(task) {
|
|
539
|
-
return task.status !== "done";
|
|
540
|
-
}
|
|
541
|
-
function listOpenTasks(trackerContent) {
|
|
542
|
-
return listTrackerTasks(trackerContent).filter(isOpenTask);
|
|
543
|
-
}
|
|
544
|
-
function updateTrackerLine(trackerPath, lineNum, newStatus) {
|
|
545
|
-
const lines = fs.readFileSync(trackerPath, "utf8").split(`
|
|
546
|
-
`);
|
|
547
|
-
const line = lines[lineNum];
|
|
548
|
-
if (!line)
|
|
549
|
-
return;
|
|
550
|
-
if (newStatus === "done") {
|
|
551
|
-
lines[lineNum] = withoutBlockerComment(line).replace(/^- \[ \]/, "- [x]").replace(/^- \[BLOCKED\]/, "- [x]");
|
|
552
|
-
} else {
|
|
553
|
-
lines[lineNum] = line.replace(/^- \[ \]/, "- [BLOCKED]");
|
|
554
|
-
}
|
|
555
|
-
fs.writeFileSync(trackerPath, lines.join(`
|
|
556
|
-
`), "utf8");
|
|
557
|
-
}
|
|
558
|
-
function writeTrackerBlocker(trackerPath, lineNum, blocker) {
|
|
559
|
-
const lines = fs.readFileSync(trackerPath, "utf8").split(`
|
|
560
|
-
`);
|
|
561
|
-
const line = lines[lineNum];
|
|
562
|
-
if (line === undefined)
|
|
563
|
-
return false;
|
|
564
|
-
const { body, cr } = splitCarriageReturn(line);
|
|
565
|
-
const prefix = OPEN_TASK_PREFIX.exec(body)?.[0];
|
|
566
|
-
if (prefix === undefined)
|
|
567
|
-
return false;
|
|
568
|
-
const found = splitTrailingComments(body.slice(prefix.length));
|
|
569
|
-
const text = found.text.trimEnd();
|
|
570
|
-
if (text.trim().length === 0)
|
|
571
|
-
return false;
|
|
572
|
-
const comment = blocker.trim().length === 0 ? "" : `${BLOCKER_GAP}${blockerComment(blocker)}`;
|
|
573
|
-
lines[lineNum] = `- [BLOCKED] ${text}${keptRepairs(found.repairs)}${comment}${cr}`;
|
|
574
|
-
fs.writeFileSync(trackerPath, lines.join(`
|
|
575
|
-
`), "utf8");
|
|
576
|
-
return true;
|
|
577
|
-
}
|
|
578
|
-
var ANY_TASK_PREFIX = /^- \[(?: |x|BLOCKED)\] /;
|
|
579
|
-
var LINE_TERMINATOR = /[\n\r\u2028\u2029]/;
|
|
580
|
-
function assertInsertable(entry) {
|
|
581
|
-
if (entry.task.trim().length === 0 || LINE_TERMINATOR.test(entry.task)) {
|
|
582
|
-
throw new Error("insertTrackerTask: the task text must be one line and not blank");
|
|
583
|
-
}
|
|
584
|
-
if (entry.declaration.trim().length === 0 || /[{}]/.test(entry.declaration) || LINE_TERMINATOR.test(entry.declaration)) {
|
|
585
|
-
throw new Error("insertTrackerTask: the declaration must be one line of entries holding no brace");
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
function endOfChecklist(lines, inBlock) {
|
|
589
|
-
for (let i = lines.length - 1;i >= 0; i -= 1) {
|
|
590
|
-
if (!inBlock.has(i) && ANY_TASK_PREFIX.test(lines[i]))
|
|
591
|
-
return i + 1;
|
|
592
|
-
}
|
|
593
|
-
const last = lines.length - 1;
|
|
594
|
-
return lines[last] === "" ? last : lines.length;
|
|
595
|
-
}
|
|
596
|
-
function insertTrackerTask(trackerPath, entry, beforeLine) {
|
|
597
|
-
assertInsertable(entry);
|
|
598
|
-
const content = fs.readFileSync(trackerPath, "utf8");
|
|
599
|
-
const lines = content.split(`
|
|
600
|
-
`);
|
|
601
|
-
const inBlock = closedBlockLines(content);
|
|
602
|
-
if (beforeLine !== null) {
|
|
603
|
-
const target = lines[beforeLine];
|
|
604
|
-
if (target === undefined || inBlock.has(beforeLine) || !ANY_TASK_PREFIX.test(target)) {
|
|
605
|
-
throw new Error(`insertTrackerTask: line ${beforeLine} is no task line`);
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
const at = beforeLine ?? endOfChecklist(lines, inBlock);
|
|
609
|
-
const { cr } = splitCarriageReturn(lines[0] ?? "");
|
|
610
|
-
const repaired = entry.repairs ?? "";
|
|
611
|
-
const repairs = repaired.trim().length === 0 ? "" : `${BLOCKER_GAP}${repairsComment(repaired)}`;
|
|
612
|
-
const line = `- [BLOCKED] ${entry.task.trim()}${BLOCKER_GAP}{${entry.declaration.trim()}}` + `${repairs}${BLOCKER_GAP}${blockerComment(entry.blocker)}${cr}`;
|
|
613
|
-
const written = [...lines.slice(0, at), line, ...lines.slice(at)];
|
|
614
|
-
fs.writeFileSync(trackerPath, written.join(`
|
|
615
|
-
`), "utf8");
|
|
616
|
-
return at;
|
|
617
|
-
}
|
|
618
|
-
function trackerPathFor(planPath) {
|
|
619
|
-
return planPath.replace(/PLAN(-[^/]*)?\.md$/, (_m, stub) => `PLAN_TRACKER${stub ?? ""}.md`);
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
// src/core/plan/parse.ts
|
|
803
|
+
// packages/rafa/src/core/plan/parse.ts
|
|
623
804
|
var PLAN_BLOCK_KINDS = ["plan", "context", "stage-context"];
|
|
624
805
|
var PLAN_HEADER_FIELDS = ["stub", "issue", "spec", "release"];
|
|
625
806
|
var PLAN_RELEASE_LEVELS = ["patch", "minor", "major", "none"];
|
|
@@ -638,10 +819,10 @@ function isHeaderField(key) {
|
|
|
638
819
|
function isReleaseLevel(value) {
|
|
639
820
|
return PLAN_RELEASE_LEVELS.includes(value);
|
|
640
821
|
}
|
|
641
|
-
function
|
|
822
|
+
function isMapping2(value) {
|
|
642
823
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
643
824
|
}
|
|
644
|
-
function
|
|
825
|
+
function describeValue2(value) {
|
|
645
826
|
if (typeof value === "string")
|
|
646
827
|
return JSON.stringify(value);
|
|
647
828
|
if (value === null)
|
|
@@ -652,7 +833,7 @@ function describeValue(value) {
|
|
|
652
833
|
return "a mapping";
|
|
653
834
|
return String(value);
|
|
654
835
|
}
|
|
655
|
-
function
|
|
836
|
+
function messageOf3(error) {
|
|
656
837
|
return error instanceof Error ? error.message : String(error);
|
|
657
838
|
}
|
|
658
839
|
function planIssue(reason, line, text) {
|
|
@@ -784,10 +965,10 @@ function unusableText(field, value) {
|
|
|
784
965
|
return `${subject} is empty; a value opening with # after a space is a YAML comment unless quoted`;
|
|
785
966
|
}
|
|
786
967
|
if (field === "release") {
|
|
787
|
-
return `${subject} is ${
|
|
968
|
+
return `${subject} is ${describeValue2(value)}, not one of ${PLAN_RELEASE_LEVELS.join(", ")}`;
|
|
788
969
|
}
|
|
789
970
|
if (typeof value !== "string") {
|
|
790
|
-
return field === "issue" ? `${subject} is ${
|
|
971
|
+
return field === "issue" ? `${subject} is ${describeValue2(value)}, not a string or a whole number; quote it` : `${subject} is ${describeValue2(value)}, not a string; quote it`;
|
|
791
972
|
}
|
|
792
973
|
if (value.trim().length === 0)
|
|
793
974
|
return `${subject} is blank`;
|
|
@@ -831,13 +1012,13 @@ function readHeader(block) {
|
|
|
831
1012
|
try {
|
|
832
1013
|
document = Bun.YAML.parse(block.body);
|
|
833
1014
|
} catch (error) {
|
|
834
|
-
const text = `rafa:plan block is not valid YAML (${
|
|
1015
|
+
const text = `rafa:plan block is not valid YAML (${messageOf3(error)})`;
|
|
835
1016
|
return { header: emptyHeader(), issues: [planIssue("malformed-header", line, text)] };
|
|
836
1017
|
}
|
|
837
1018
|
if (document === null)
|
|
838
1019
|
return { header: emptyHeader(), issues: [] };
|
|
839
|
-
if (!
|
|
840
|
-
const text = `rafa:plan block holds ${
|
|
1020
|
+
if (!isMapping2(document)) {
|
|
1021
|
+
const text = `rafa:plan block holds ${describeValue2(document)}, not a mapping of fields`;
|
|
841
1022
|
return { header: emptyHeader(), issues: [planIssue("malformed-header", line, text)] };
|
|
842
1023
|
}
|
|
843
1024
|
return readFields(document, line);
|
|
@@ -863,7 +1044,7 @@ function parsePlan(markdown) {
|
|
|
863
1044
|
issues
|
|
864
1045
|
};
|
|
865
1046
|
}
|
|
866
|
-
// src/core/plan/plan-files.ts
|
|
1047
|
+
// packages/rafa/src/core/plan/plan-files.ts
|
|
867
1048
|
import { statSync } from "fs";
|
|
868
1049
|
import { basename as basename2, dirname as dirname2, join as join2, resolve } from "path";
|
|
869
1050
|
function plansDirAt(root, planDir) {
|
|
@@ -895,6 +1076,10 @@ function issueLine(file, issue) {
|
|
|
895
1076
|
function plural(count, noun) {
|
|
896
1077
|
return count === 1 ? `${count} ${noun}` : `${count} ${noun}s`;
|
|
897
1078
|
}
|
|
1079
|
+
// packages/rafa/src/core/plan/tracker-path.ts
|
|
1080
|
+
function trackerPathFor(planPath) {
|
|
1081
|
+
return planPath.replace(/PLAN(-[^/]*)?\.md$/, (_m, stub) => `PLAN_TRACKER${stub ?? ""}.md`);
|
|
1082
|
+
}
|
|
898
1083
|
// src/plan/inject.ts
|
|
899
1084
|
var PLAN_CONTEXT_HEADING = "## Plan context";
|
|
900
1085
|
var STAGE_HEADING_PREFIX = "## Stage: ";
|
|
@@ -1036,4 +1221,4 @@ function renderInjection(request) {
|
|
|
1036
1221
|
const repair = repairs === undefined ? null : parseTaskDeclaration(task.task).text.trim();
|
|
1037
1222
|
return { requested: mode, mode, text: RENDERERS[mode](model, { task: location.task, repair }), fallback: null };
|
|
1038
1223
|
}
|
|
1039
|
-
export {
|
|
1224
|
+
export { RAFA_BLOCK_KINDS, isRafaBlockKind, readRafaBlocks, REPORT_STATUSES, FINDING_KINDS, FINDING_SIGNALS, FINDING_DOMAINS, CHANGE_LEVELS, BUG_KINDS, parseReport, BLOCKER_GAP, escapeBlockerText, unescapeBlockerText, blockerComment, repairsComment, splitTrailingComments, commentText, keptRepairs, splitBlockerComment, PLAN_BLOCK_KINDS, PLAN_HEADER_FIELDS, PLAN_RELEASE_LEVELS, parsePlan, plansDirAt, countTasks, planFileName, stubOfPlanFile, isFile, rejectedPath, issueLine, plural, trackerPathFor, parsePrerequisites, planPrerequisites, malformedPrerequisiteLines, mergePlanPrerequisites, prerequisitesPathForPlan, loadPlanPrerequisites, PROBE_TIMEOUT_MS, runShellProbe, runPreflight, renderInjection };
|
|
@@ -1,12 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import {
|
|
3
|
-
CONFIDENCE_MAX,
|
|
4
|
-
CONFIDENCE_MIN,
|
|
5
|
-
GAP,
|
|
6
|
-
SOURCE_STEP,
|
|
7
|
-
triggerKey
|
|
8
|
-
} from "./index-hf2k497d.js";
|
|
9
|
-
|
|
10
2
|
// src/learning/bless.ts
|
|
11
3
|
import { createHash } from "crypto";
|
|
12
4
|
var HUNDREDTHS = 100;
|
|
@@ -39,6 +31,19 @@ function bless(held, options) {
|
|
|
39
31
|
function promotable(held, options) {
|
|
40
32
|
return blessedRecords(held, options.minConfidence).filter((each) => each.usage_count >= options.after);
|
|
41
33
|
}
|
|
34
|
+
// src/learning/identity.ts
|
|
35
|
+
import { createHash as createHash2 } from "crypto";
|
|
36
|
+
var GAP = 0.1;
|
|
37
|
+
var SOURCE_STEP = 0.05;
|
|
38
|
+
var CONFIDENCE_MIN = 0.3;
|
|
39
|
+
var CONFIDENCE_MAX = 0.9;
|
|
40
|
+
var WHITESPACE_RUN = /\s+/g;
|
|
41
|
+
function actionHash(action) {
|
|
42
|
+
return createHash2("sha256").update(action.trim().toLowerCase()).digest("hex");
|
|
43
|
+
}
|
|
44
|
+
function triggerKey(trigger) {
|
|
45
|
+
return trigger.trim().toLowerCase().replace(WHITESPACE_RUN, " ");
|
|
46
|
+
}
|
|
42
47
|
// src/learning/merge.ts
|
|
43
48
|
var HUNDREDTHS2 = 100;
|
|
44
49
|
var GAP_H = Math.round(GAP * HUNDREDTHS2);
|
|
@@ -215,4 +220,4 @@ function merge(held, payload, now) {
|
|
|
215
220
|
discarded: keys.flatMap((key) => outcomes.get(key).discarded)
|
|
216
221
|
};
|
|
217
222
|
}
|
|
218
|
-
export { bless, promotable, merge };
|
|
223
|
+
export { bless, promotable, GAP, SOURCE_STEP, CONFIDENCE_MIN, CONFIDENCE_MAX, actionHash, triggerKey, merge };
|