@open-tomato/rafa 0.42.0 → 0.44.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/agents/qa-bug-reporter.md +50 -12
- package/dist/bundled/operators/skills/rafa-stretch-gap-log/SKILL.md +5 -1
- package/dist/cli.js +33280 -30966
- package/dist/effort/store/index.js +2 -2
- package/dist/{index-7ycam8pq.js → index-57mmzkcn.js} +1 -1
- package/dist/{index-q0dmfp8m.js → index-6q30dtgm.js} +790 -875
- package/dist/{index-bceachy6.js → index-cknayrpc.js} +484 -9
- package/dist/index.js +9466 -10153
- package/dist/plan/index.js +2 -2
- package/package.json +1 -1
|
@@ -637,6 +637,163 @@ var BOARD_PROJECT_LIMIT_SETTINGS = {
|
|
|
637
637
|
}
|
|
638
638
|
};
|
|
639
639
|
|
|
640
|
+
// src/errors/codes.ts
|
|
641
|
+
var ERROR_LEVELS = Object.freeze(["error", "warn"]);
|
|
642
|
+
var CODE_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*:[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
643
|
+
var NEW_CONTEXT_LEAF = "new-context";
|
|
644
|
+
var UNKNOWN_FAMILY = "unknown";
|
|
645
|
+
var TEXT_FIELDS = ["description", "hint", "since"];
|
|
646
|
+
var PREFIX = "error codes";
|
|
647
|
+
function familyOf(code) {
|
|
648
|
+
return code.slice(0, code.indexOf(":"));
|
|
649
|
+
}
|
|
650
|
+
function codeProblem(code) {
|
|
651
|
+
if (!CODE_PATTERN.test(code))
|
|
652
|
+
return `${JSON.stringify(code)} is not <family>:<leaf> in kebab-case`;
|
|
653
|
+
const leaf = code.slice(code.indexOf(":") + 1);
|
|
654
|
+
if (leaf === NEW_CONTEXT_LEAF || leaf === UNKNOWN_FAMILY) {
|
|
655
|
+
return `${JSON.stringify(code)} uses the reserved leaf ${leaf}`;
|
|
656
|
+
}
|
|
657
|
+
if (familyOf(code) === UNKNOWN_FAMILY)
|
|
658
|
+
return `${JSON.stringify(code)} uses the reserved family ${UNKNOWN_FAMILY}`;
|
|
659
|
+
return null;
|
|
660
|
+
}
|
|
661
|
+
function entryProblem(entry, index) {
|
|
662
|
+
const codeFault = codeProblem(entry.code);
|
|
663
|
+
if (codeFault !== null)
|
|
664
|
+
return `[${index}].code ${codeFault}`;
|
|
665
|
+
const empty = TEXT_FIELDS.find((field) => (entry[field] ?? "").trim() === "");
|
|
666
|
+
if (empty !== undefined)
|
|
667
|
+
return `[${index}].${empty} is empty`;
|
|
668
|
+
if (!ERROR_LEVELS.includes(entry.level)) {
|
|
669
|
+
return `[${index}].level is ${JSON.stringify(entry.level)}, expected ${ERROR_LEVELS.join(" or ")}`;
|
|
670
|
+
}
|
|
671
|
+
return null;
|
|
672
|
+
}
|
|
673
|
+
function defineErrorCodes(entries) {
|
|
674
|
+
entries.forEach((entry, index) => {
|
|
675
|
+
const fault = entryProblem(entry, index);
|
|
676
|
+
if (fault !== null)
|
|
677
|
+
throw new TypeError(`${PREFIX}: ${fault}`);
|
|
678
|
+
const first = entries.findIndex((other) => other.code === entry.code);
|
|
679
|
+
if (first < index) {
|
|
680
|
+
throw new TypeError(`${PREFIX}: ${JSON.stringify(entry.code)} is declared at [${first}] and [${index}]`);
|
|
681
|
+
}
|
|
682
|
+
});
|
|
683
|
+
return Object.freeze(entries.map((entry) => Object.freeze({ ...entry })));
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
// src/errors/rafa-codes.ts
|
|
687
|
+
var SEED = "#949";
|
|
688
|
+
var FAMILY_DESCRIPTIONS = Object.freeze({
|
|
689
|
+
api: "a call to a remote service",
|
|
690
|
+
cli: "routing a command line and running the command",
|
|
691
|
+
config: "reading the project or user config",
|
|
692
|
+
fs: "reading or writing files",
|
|
693
|
+
git: "running git",
|
|
694
|
+
input: "a value given on the command line or in a file",
|
|
695
|
+
skill: "a skill file's frontmatter",
|
|
696
|
+
spawn: "starting a child process",
|
|
697
|
+
tracker: "the issue tracker",
|
|
698
|
+
tsc: "type-checking"
|
|
699
|
+
});
|
|
700
|
+
var RAFA_CODES = defineErrorCodes([
|
|
701
|
+
{ code: "cli:unknown-subject", description: "the first word names no subject", hint: "run rafa --help for the subjects", level: "error", since: SEED, legacy: "unknown_subject" },
|
|
702
|
+
{ code: "cli:missing-action", description: "a subject is named with no action after it", hint: "run rafa <subject> --help for its actions", level: "error", since: SEED, legacy: "missing_action" },
|
|
703
|
+
{ code: "cli:unknown-action", description: "the action names nothing the subject holds", hint: "run rafa <subject> --help for its actions", level: "error", since: SEED, legacy: "unknown_action" },
|
|
704
|
+
{ code: "cli:unknown-module", description: "a module command names a module that is not mounted", hint: "run rafa module list for the modules that are mounted", level: "error", since: SEED, legacy: "unknown_module" },
|
|
705
|
+
{ code: "cli:unexpected-version", description: "--version is typed beside a command, where it is read alone", hint: "run rafa --version alone, with no command beside it", level: "error", since: SEED, legacy: "unexpected_version" },
|
|
706
|
+
{ code: "cli:invalid-spec", description: "a command declares a shape the dispatcher refuses", hint: "fix the command declaration the message names", level: "error", since: SEED, legacy: "invalid_spec" },
|
|
707
|
+
{ code: "cli:no-project", description: "a command that needs a project ran outside one", hint: "run it inside a project, or run rafa init", level: "error", since: SEED, legacy: "no_project" },
|
|
708
|
+
{ code: "cli:command-exit", description: "a command refused and set its own exit code", hint: "read the message above it", level: "error", since: SEED, legacy: "command_exit" },
|
|
709
|
+
{ code: "cli:command-error", description: "a command threw an error it did not handle", hint: "file a bug with the stack", level: "error", since: SEED, legacy: "command_error" },
|
|
710
|
+
{ code: "cli:result-unwritable", description: "the command result cannot be written, as with data JSON refuses", hint: "file a bug: the command answered data that cannot be written as JSON", level: "error", since: SEED, legacy: "result_unwritable" },
|
|
711
|
+
{ code: "skill:missing-field", description: "a required frontmatter field is absent or empty", hint: "add the field the message names", level: "error", since: SEED, legacy: "missing-field" },
|
|
712
|
+
{ code: "skill:wrong-type", description: "a frontmatter field has a type the schema cannot read", hint: "write the field as the schema expects", level: "error", since: SEED, legacy: "wrong-type" },
|
|
713
|
+
{ code: "skill:invalid-name", description: "a skill name is not kebab-case", hint: "rename the skill in kebab-case", level: "error", since: SEED, legacy: "invalid-name" },
|
|
714
|
+
{ code: "skill:description-too-long", description: "the description is at or past its limit", hint: "shorten the description", level: "error", since: SEED, legacy: "description-too-long" },
|
|
715
|
+
{ code: "skill:listing-too-long", description: "description and when_to_use together pass the listing limit", hint: "shorten when_to_use", level: "error", since: SEED, legacy: "listing-too-long" },
|
|
716
|
+
{ code: "skill:unknown-stack", description: "a stack entry is outside the vocabulary", hint: "use a stack the schema lists", level: "error", since: SEED, legacy: "unknown-stack" },
|
|
717
|
+
{ code: "skill:unpaired-prevents", description: "prevents is set without signal, or signal without prevents", hint: "set both or neither", level: "error", since: SEED, legacy: "unpaired-prevents" },
|
|
718
|
+
{ code: "skill:unknown-signal", description: "signal holds a value the schema does not list", hint: "use a listed signal", level: "error", since: SEED, legacy: "unknown-signal" },
|
|
719
|
+
{ code: "skill:unusable-glob", description: "a paths glob gates on nothing it seems to gate on", hint: "rewrite the glob", level: "error", since: SEED, legacy: "unusable-glob" },
|
|
720
|
+
{ code: "skill:forbidden-field", description: "an instinct field appears on a skill", hint: "remove the field", level: "error", since: SEED, legacy: "forbidden-field" },
|
|
721
|
+
{ code: "skill:unknown-provenance", description: "provenance names neither first-party nor a known mapping", hint: "use first-party or a known mapping", level: "error", since: SEED, legacy: "unknown-provenance" },
|
|
722
|
+
{ code: "skill:invalid-reviewed", description: "provenance.reviewed is not who and a date", hint: "write <who> <YYYY-MM-DD>", level: "error", since: SEED, legacy: "invalid-reviewed" },
|
|
723
|
+
{ code: "skill:empty-failure-string", description: "a failure_strings entry is blank", hint: "remove the blank entry", level: "error", since: SEED, legacy: "empty-failure-string" },
|
|
724
|
+
{ code: "skill:short-failure-string", description: "a failure_strings entry is too short to name one failure", hint: "lengthen the entry", level: "warn", since: SEED, legacy: "short-failure-string" },
|
|
725
|
+
{ code: "git:no-identity", description: "a git commit runs with no author identity set, often in a scratch home", hint: "set user.name and user.email where the commit runs", level: "error", since: SEED },
|
|
726
|
+
{ code: "git:filesystem-boundary", description: "git prints an extra line when run outside a repository", hint: "run inside a repository, or read only the first line", level: "warn", since: SEED },
|
|
727
|
+
{ code: "tsc:tests-excluded", description: "type errors in test files stay hidden because tsc excludes tests", hint: "type-check the test files", level: "error", since: SEED },
|
|
728
|
+
{ code: "fs:gitignored-fixture", description: "a test reads a gitignored file a fresh checkout lacks", hint: "plant the file in the test, never read the live one", level: "error", since: SEED },
|
|
729
|
+
{ code: "fs:live-home", description: "a test reads the live home directory instead of a planted one", hint: "point HOME at a scratch folder in the test", level: "error", since: SEED },
|
|
730
|
+
{ code: "fs:not-found", description: "a file or folder the step needs is missing", hint: "create it, or fix the path", level: "error", since: SEED },
|
|
731
|
+
{ code: "input:missing-param", description: "a required value was not given", hint: "pass the value the message names", level: "error", since: SEED },
|
|
732
|
+
{ code: "input:invalid-value", description: "a given value is outside what the step accepts", hint: "pass one of the values the message lists", level: "error", since: SEED },
|
|
733
|
+
{ code: "api:http-status", description: "a remote service answered with an error status", hint: "read the status, then retry or fix the request", level: "error", since: SEED },
|
|
734
|
+
{ code: "config:invalid-value", description: "a config key holds a value its reader refuses", hint: "fix the key the message names", level: "error", since: SEED },
|
|
735
|
+
{ code: "tracker:unreachable", description: "the issue tracker could not be reached", hint: "check the network and gh auth status", level: "error", since: SEED },
|
|
736
|
+
{ code: "tracker:unavailable", description: "a tracker kind could not be made or failed its preflight, and the chain passed it over", hint: "read the reason given, or leave the fallback tracker in use", level: "warn", since: "#950" },
|
|
737
|
+
{ code: "spawn:nonzero-exit", description: "a child process exited nonzero", hint: "read the child's stderr above", level: "error", since: SEED }
|
|
738
|
+
]);
|
|
739
|
+
|
|
740
|
+
// src/config-schema-errors.ts
|
|
741
|
+
var ERROR_CODE_KEYS = ["code", "description", "hint", "level", "since"];
|
|
742
|
+
var KNOWN_KEYS = new Set(ERROR_CODE_KEYS);
|
|
743
|
+
var ERRORS_DEFAULTS = Object.freeze({ errorsCodes: Object.freeze([]) });
|
|
744
|
+
var codeText = (raw, at) => {
|
|
745
|
+
const read = text("a code, <family>:<leaf>")(raw, at);
|
|
746
|
+
if (read.value === undefined)
|
|
747
|
+
return read;
|
|
748
|
+
const fault = codeProblem(read.value);
|
|
749
|
+
return fault === null ? read : refused(at, raw, `a code: ${fault}`);
|
|
750
|
+
};
|
|
751
|
+
var EXPECTED = {
|
|
752
|
+
description: "a one-line description, a non-empty string",
|
|
753
|
+
hint: "the next action, a non-empty string",
|
|
754
|
+
since: "the version or issue that added it, a non-empty string"
|
|
755
|
+
};
|
|
756
|
+
var NO_SINCE = { value: undefined, problems: [], extras: [] };
|
|
757
|
+
var errorCodeEntry = (raw, at) => {
|
|
758
|
+
if (!isMapping(raw))
|
|
759
|
+
return refused(at, raw, `a mapping of: ${ERROR_CODE_KEYS.join(", ")}`);
|
|
760
|
+
const code = codeText(raw.code, below(at, ".code"));
|
|
761
|
+
const description = text(EXPECTED.description)(raw.description, below(at, ".description"));
|
|
762
|
+
const hint = text(EXPECTED.hint)(raw.hint, below(at, ".hint"));
|
|
763
|
+
const level = oneOf(ERROR_LEVELS)(raw.level, below(at, ".level"));
|
|
764
|
+
const since = raw.since === undefined || raw.since === null ? NO_SINCE : text(EXPECTED.since)(raw.since, below(at, ".since"));
|
|
765
|
+
const problems = [code, description, hint, level, since].flatMap((reading) => reading.problems);
|
|
766
|
+
const extras = Object.entries(raw).filter(([key]) => !KNOWN_KEYS.has(key)).map(([key, value]) => ({ key: `${at.key}.${key}`, value }));
|
|
767
|
+
if (code.value === undefined || description.value === undefined || hint.value === undefined || level.value === undefined || problems.length > 0)
|
|
768
|
+
return { value: undefined, problems, extras };
|
|
769
|
+
const entry = {
|
|
770
|
+
code: code.value,
|
|
771
|
+
description: description.value,
|
|
772
|
+
hint: hint.value,
|
|
773
|
+
level: level.value,
|
|
774
|
+
...since.value === undefined ? {} : { since: since.value }
|
|
775
|
+
};
|
|
776
|
+
return { value: Object.freeze(entry), problems: [], extras };
|
|
777
|
+
};
|
|
778
|
+
var errorCodes = (raw, at) => {
|
|
779
|
+
const read = listOf(errorCodeEntry, "error code entries")(raw, at);
|
|
780
|
+
const entries = read.value;
|
|
781
|
+
if (entries === undefined)
|
|
782
|
+
return read;
|
|
783
|
+
const problems = entries.flatMap((entry, index) => {
|
|
784
|
+
const label = `${below(at, `[${index}]`).label}.code is ${JSON.stringify(entry.code)}`;
|
|
785
|
+
if (RAFA_CODES.some((own) => own.code === entry.code)) {
|
|
786
|
+
return [`${label}, which rafa already declares; add a leaf of your own instead`];
|
|
787
|
+
}
|
|
788
|
+
const first = entries.findIndex((other) => other.code === entry.code);
|
|
789
|
+
return first < index ? [`${label}, already given at [${first}]`] : [];
|
|
790
|
+
});
|
|
791
|
+
return problems.length === 0 ? read : { ...refusedWith(problems), extras: read.extras };
|
|
792
|
+
};
|
|
793
|
+
var ERRORS_SETTINGS = {
|
|
794
|
+
errorsCodes: { key: "errors.codes", read: errorCodes, cli: false, itemKeys: ERROR_CODE_KEYS }
|
|
795
|
+
};
|
|
796
|
+
|
|
640
797
|
// src/config-schema-hub.ts
|
|
641
798
|
var HUB_TIMEOUT_MIN_SECONDS = 1;
|
|
642
799
|
var HUB_TIMEOUT_MAX_SECONDS = 30;
|
|
@@ -692,6 +849,300 @@ function hubContextOf(config) {
|
|
|
692
849
|
return Object.freeze({ url, tokenSecret: config.hubTokenSecret ?? null, timeoutMs });
|
|
693
850
|
}
|
|
694
851
|
|
|
852
|
+
// src/bugs/places.ts
|
|
853
|
+
var BUILT_IN_ENVIRONMENTS = ["local", "ci", "prod"];
|
|
854
|
+
|
|
855
|
+
// src/bugs/title.ts
|
|
856
|
+
var TITLE_VARIABLES = ["type", "project", "projectType", "module", "action", "summary"];
|
|
857
|
+
var UNKNOWN_VALUE = "unknown";
|
|
858
|
+
var DEFAULT_BUG_TITLE = "?(${module}?( - ${action}): )${summary}";
|
|
859
|
+
var MODULE_SHAPE = "[a-z0-9][a-z0-9._-]*";
|
|
860
|
+
var ACTION_SHAPE = "[a-z0-9][a-z0-9._ -]*";
|
|
861
|
+
var SUMMARY = "summary";
|
|
862
|
+
var VARIABLE_SHAPES = { module: MODULE_SHAPE, action: ACTION_SHAPE };
|
|
863
|
+
var FREE_SHAPE = ".+";
|
|
864
|
+
var GROUP_OPEN = "?(";
|
|
865
|
+
var GROUP_CLOSE = ")";
|
|
866
|
+
var VARIABLE_OPEN = "${";
|
|
867
|
+
var VARIABLE_CLOSE = "}";
|
|
868
|
+
|
|
869
|
+
class TitleTemplateError extends Error {
|
|
870
|
+
constructor(message) {
|
|
871
|
+
super(message);
|
|
872
|
+
this.name = "TitleTemplateError";
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
function isPrintable(value) {
|
|
876
|
+
return typeof value === "string" && value.trim() !== "" && value.trim() !== UNKNOWN_VALUE;
|
|
877
|
+
}
|
|
878
|
+
function isTitleVariable(name) {
|
|
879
|
+
return TITLE_VARIABLES.includes(name);
|
|
880
|
+
}
|
|
881
|
+
function readVariable(template, at) {
|
|
882
|
+
const close = template.indexOf(VARIABLE_CLOSE, at);
|
|
883
|
+
if (close === -1)
|
|
884
|
+
throw new TitleTemplateError(`"${VARIABLE_OPEN}" at ${at} is never closed`);
|
|
885
|
+
const name = template.slice(at + VARIABLE_OPEN.length, close);
|
|
886
|
+
if (!isTitleVariable(name)) {
|
|
887
|
+
throw new TitleTemplateError(`\${${name}} names no variable, expected one of: ${TITLE_VARIABLES.join(", ")}`);
|
|
888
|
+
}
|
|
889
|
+
return { node: { kind: "variable", name }, next: close + VARIABLE_CLOSE.length };
|
|
890
|
+
}
|
|
891
|
+
function readNodes(template, start, depth) {
|
|
892
|
+
const nodes = [];
|
|
893
|
+
let text2 = "";
|
|
894
|
+
let at = start;
|
|
895
|
+
const flush = () => {
|
|
896
|
+
if (text2 !== "")
|
|
897
|
+
nodes.push({ kind: "text", text: text2 });
|
|
898
|
+
text2 = "";
|
|
899
|
+
};
|
|
900
|
+
while (at < template.length) {
|
|
901
|
+
if (template.startsWith(GROUP_OPEN, at)) {
|
|
902
|
+
flush();
|
|
903
|
+
const inner = readNodes(template, at + GROUP_OPEN.length, depth + 1);
|
|
904
|
+
nodes.push({ kind: "group", nodes: inner.nodes });
|
|
905
|
+
at = inner.next;
|
|
906
|
+
} else if (depth > 0 && template[at] === GROUP_CLOSE) {
|
|
907
|
+
flush();
|
|
908
|
+
return { nodes, next: at + GROUP_CLOSE.length };
|
|
909
|
+
} else if (template.startsWith(VARIABLE_OPEN, at)) {
|
|
910
|
+
flush();
|
|
911
|
+
const variable = readVariable(template, at);
|
|
912
|
+
nodes.push(variable.node);
|
|
913
|
+
at = variable.next;
|
|
914
|
+
} else {
|
|
915
|
+
text2 += template[at];
|
|
916
|
+
at += 1;
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
if (depth > 0)
|
|
920
|
+
throw new TitleTemplateError(`a "${GROUP_OPEN}" group is never closed`);
|
|
921
|
+
flush();
|
|
922
|
+
return { nodes, next: at };
|
|
923
|
+
}
|
|
924
|
+
function parseTitleTemplate(template) {
|
|
925
|
+
return readNodes(template, 0, 0).nodes;
|
|
926
|
+
}
|
|
927
|
+
function variablesOf(nodes) {
|
|
928
|
+
return nodes.flatMap((node) => {
|
|
929
|
+
if (node.kind === "variable")
|
|
930
|
+
return [node.name];
|
|
931
|
+
return node.kind === "group" ? variablesOf(node.nodes) : [];
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
function groupShows(nodes, values) {
|
|
935
|
+
return nodes.every((node) => node.kind !== "variable" || isPrintable(values[node.name]));
|
|
936
|
+
}
|
|
937
|
+
function printed(values, name) {
|
|
938
|
+
const value = values[name];
|
|
939
|
+
return isPrintable(value) ? value.trim() : "";
|
|
940
|
+
}
|
|
941
|
+
function shownValues(nodes, values) {
|
|
942
|
+
return Object.fromEntries(nodes.flatMap((node) => {
|
|
943
|
+
if (node.kind === "text")
|
|
944
|
+
return [];
|
|
945
|
+
if (node.kind === "variable") {
|
|
946
|
+
return printed(values, node.name) === "" ? [] : [[node.name, printed(values, node.name)]];
|
|
947
|
+
}
|
|
948
|
+
return groupShows(node.nodes, values) ? Object.entries(shownValues(node.nodes, values)) : [];
|
|
949
|
+
}));
|
|
950
|
+
}
|
|
951
|
+
function renderNodes(nodes, values) {
|
|
952
|
+
return nodes.map((node) => {
|
|
953
|
+
if (node.kind === "text")
|
|
954
|
+
return node.text;
|
|
955
|
+
if (node.kind === "variable")
|
|
956
|
+
return printed(values, node.name);
|
|
957
|
+
return groupShows(node.nodes, values) ? renderNodes(node.nodes, values) : "";
|
|
958
|
+
}).join("");
|
|
959
|
+
}
|
|
960
|
+
function renderTitle(template, values) {
|
|
961
|
+
return renderNodes(parseTitleTemplate(template), values).trim();
|
|
962
|
+
}
|
|
963
|
+
function escapeLiteral(text2) {
|
|
964
|
+
return text2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
965
|
+
}
|
|
966
|
+
function patternOf(nodes, last) {
|
|
967
|
+
return nodes.map((node) => {
|
|
968
|
+
if (node.kind === "text")
|
|
969
|
+
return escapeLiteral(node.text);
|
|
970
|
+
if (node.kind === "group")
|
|
971
|
+
return `(?:${patternOf(node.nodes, last)})?`;
|
|
972
|
+
const shape = node.name === last ? FREE_SHAPE : `${VARIABLE_SHAPES[node.name] ?? FREE_SHAPE}?`;
|
|
973
|
+
return `(?<${node.name}>${shape})`;
|
|
974
|
+
}).join("");
|
|
975
|
+
}
|
|
976
|
+
function parseTitle(template, title) {
|
|
977
|
+
const nodes = parseTitleTemplate(template);
|
|
978
|
+
const names = variablesOf(nodes);
|
|
979
|
+
const match = new RegExp(`^${patternOf(nodes, names.at(-1))}$`, "u").exec(title.trim());
|
|
980
|
+
if (match === null)
|
|
981
|
+
return null;
|
|
982
|
+
return Object.fromEntries(names.flatMap((name) => {
|
|
983
|
+
const value = match.groups?.[name];
|
|
984
|
+
return value === undefined ? [] : [[name, value]];
|
|
985
|
+
}));
|
|
986
|
+
}
|
|
987
|
+
function titleRoundTrips(template, values) {
|
|
988
|
+
const nodes = parseTitleTemplate(template);
|
|
989
|
+
const title = renderNodes(nodes, values).trim();
|
|
990
|
+
if (title === "")
|
|
991
|
+
return false;
|
|
992
|
+
const read = parseTitle(template, title) ?? {};
|
|
993
|
+
const shown = shownValues(nodes, values);
|
|
994
|
+
return variablesOf(nodes).every((name) => (read[name] ?? null) === (shown[name] ?? null));
|
|
995
|
+
}
|
|
996
|
+
var SAMPLE = {
|
|
997
|
+
type: "bug",
|
|
998
|
+
project: "api",
|
|
999
|
+
projectType: "cli",
|
|
1000
|
+
module: "loop",
|
|
1001
|
+
action: "start",
|
|
1002
|
+
summary: "Does not find the branch: again"
|
|
1003
|
+
};
|
|
1004
|
+
function samplesOf(names) {
|
|
1005
|
+
const optional = names.filter((name) => name !== SUMMARY);
|
|
1006
|
+
const subsets = optional.reduce((found, name) => [...found, ...found.map((subset) => [...subset, name])], [[]]);
|
|
1007
|
+
return subsets.map((subset) => Object.fromEntries([...subset, SUMMARY].map((name) => [name, SAMPLE[name]])));
|
|
1008
|
+
}
|
|
1009
|
+
function nodesProblem(template, nodes) {
|
|
1010
|
+
const names = variablesOf(nodes);
|
|
1011
|
+
const twice = names.find((name, index) => names.indexOf(name) !== index);
|
|
1012
|
+
if (twice !== undefined)
|
|
1013
|
+
return `\${${twice}} appears twice`;
|
|
1014
|
+
if (names.at(-1) !== SUMMARY)
|
|
1015
|
+
return `\${${SUMMARY}} must be the last variable`;
|
|
1016
|
+
if (!nodes.some((node) => node.kind === "variable" && node.name === SUMMARY)) {
|
|
1017
|
+
return `\${${SUMMARY}} must stand outside every ?( ) group`;
|
|
1018
|
+
}
|
|
1019
|
+
const failed = samplesOf(names).find((sample) => !titleRoundTrips(template, sample));
|
|
1020
|
+
return failed === undefined ? null : `the title ${JSON.stringify(renderTitle(template, failed))} does not read back as the fields it was rendered from`;
|
|
1021
|
+
}
|
|
1022
|
+
function templateProblem(template) {
|
|
1023
|
+
try {
|
|
1024
|
+
return nodesProblem(template, parseTitleTemplate(template));
|
|
1025
|
+
} catch (error) {
|
|
1026
|
+
if (error instanceof TitleTemplateError)
|
|
1027
|
+
return error.message;
|
|
1028
|
+
throw error;
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
// src/config-schema-issues.ts
|
|
1033
|
+
var SUMMARY_MAX_DEFAULT = 80;
|
|
1034
|
+
var SUMMARY_MAX_FLOOR = 20;
|
|
1035
|
+
var SUMMARY_MAX_CEILING = 120;
|
|
1036
|
+
var TEMPLATE_EXPECTED = "a title template";
|
|
1037
|
+
var PLACE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
1038
|
+
var MODULE = new RegExp(`^${MODULE_SHAPE}$`);
|
|
1039
|
+
var ACTION = new RegExp(`^${ACTION_SHAPE}$`);
|
|
1040
|
+
function accepted2(value) {
|
|
1041
|
+
return { value, problems: [], extras: [] };
|
|
1042
|
+
}
|
|
1043
|
+
var titleTemplate = (raw, at) => {
|
|
1044
|
+
if (typeof raw !== "string" || raw.trim() === "")
|
|
1045
|
+
return refused(at, raw, TEMPLATE_EXPECTED);
|
|
1046
|
+
const problem = templateProblem(raw);
|
|
1047
|
+
return problem === null ? accepted2(raw) : refused(at, raw, `${TEMPLATE_EXPECTED}: ${problem}`);
|
|
1048
|
+
};
|
|
1049
|
+
var summaryMax = (raw, at) => typeof raw === "number" && Number.isSafeInteger(raw) && raw >= SUMMARY_MAX_FLOOR && raw <= SUMMARY_MAX_CEILING ? accepted2(raw) : refused(at, raw, `a whole number from ${SUMMARY_MAX_FLOOR} to ${SUMMARY_MAX_CEILING}`);
|
|
1050
|
+
function nameOf(shape, reserved, expected) {
|
|
1051
|
+
return (raw, at) => typeof raw === "string" && shape.test(raw) && !reserved.includes(raw) ? accepted2(raw) : refused(at, raw, expected);
|
|
1052
|
+
}
|
|
1053
|
+
var place = nameOf(PLACE, [...BUILT_IN_ENVIRONMENTS, UNKNOWN_VALUE], `a place name in lower-case kebab-case, other than ${BUILT_IN_ENVIRONMENTS.join(", ")} and ${UNKNOWN_VALUE}`);
|
|
1054
|
+
var moduleName = nameOf(MODULE, [UNKNOWN_VALUE], `a module name in lower-case letters, digits, ".", "_" and "-", other than ${UNKNOWN_VALUE}`);
|
|
1055
|
+
var actionName = nameOf(ACTION, [UNKNOWN_VALUE], `an action in lower-case letters, digits, ".", "_", "-" and spaces, other than ${UNKNOWN_VALUE}`);
|
|
1056
|
+
var ISSUES_DEFAULTS = Object.freeze({
|
|
1057
|
+
issuesTitleBug: DEFAULT_BUG_TITLE,
|
|
1058
|
+
issuesSummaryMax: SUMMARY_MAX_DEFAULT,
|
|
1059
|
+
issuesEnvironments: Object.freeze([]),
|
|
1060
|
+
issuesVocabularyModules: Object.freeze([]),
|
|
1061
|
+
issuesVocabularyActions: Object.freeze([])
|
|
1062
|
+
});
|
|
1063
|
+
var ISSUES_SETTINGS = {
|
|
1064
|
+
issuesTitleBug: { key: "issues.titles.bug", read: titleTemplate, cli: false },
|
|
1065
|
+
issuesSummaryMax: { key: "issues.titles.summaryMax", read: summaryMax, cli: false },
|
|
1066
|
+
issuesEnvironments: { key: "issues.environments", read: listOf(place, "place names"), cli: false },
|
|
1067
|
+
issuesVocabularyModules: { key: "issues.vocabulary.modules", read: listOf(moduleName, "module names"), cli: false },
|
|
1068
|
+
issuesVocabularyActions: { key: "issues.vocabulary.actions", read: listOf(actionName, "actions"), cli: false }
|
|
1069
|
+
};
|
|
1070
|
+
|
|
1071
|
+
// src/adapters/logger/settings.ts
|
|
1072
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
1073
|
+
var LOG_LEVELS = Object.freeze(["error", "warn", "debug"]);
|
|
1074
|
+
var LOGGER_THEMES = Object.freeze(["default", "plain"]);
|
|
1075
|
+
var DEFAULT_LOGGER_KIND = "console";
|
|
1076
|
+
var DEBUG_VERBOSITY = 2;
|
|
1077
|
+
var API_VERBOSITY = 3;
|
|
1078
|
+
var DEFAULT_LOGGER_SETTINGS = Object.freeze({
|
|
1079
|
+
kind: DEFAULT_LOGGER_KIND,
|
|
1080
|
+
level: "warn",
|
|
1081
|
+
theme: "default",
|
|
1082
|
+
modules: new Map,
|
|
1083
|
+
callSite: false,
|
|
1084
|
+
api: false
|
|
1085
|
+
});
|
|
1086
|
+
var scopes = new AsyncLocalStorage;
|
|
1087
|
+
var moduleLevel = { settings: DEFAULT_LOGGER_SETTINGS };
|
|
1088
|
+
function settingsOf(settings) {
|
|
1089
|
+
return settings === null ? DEFAULT_LOGGER_SETTINGS : Object.freeze({ ...settings, modules: new Map(settings.modules) });
|
|
1090
|
+
}
|
|
1091
|
+
function cellHere() {
|
|
1092
|
+
return scopes.getStore() ?? moduleLevel;
|
|
1093
|
+
}
|
|
1094
|
+
function setActiveLoggerSettings(settings) {
|
|
1095
|
+
cellHere().settings = settingsOf(settings);
|
|
1096
|
+
}
|
|
1097
|
+
function activeLoggerSettings() {
|
|
1098
|
+
return cellHere().settings;
|
|
1099
|
+
}
|
|
1100
|
+
function levelEnabled(level, module, settings, verbosity) {
|
|
1101
|
+
if (level === "api")
|
|
1102
|
+
return settings.api || verbosity >= API_VERBOSITY;
|
|
1103
|
+
if (level === "debug" && verbosity >= DEBUG_VERBOSITY)
|
|
1104
|
+
return true;
|
|
1105
|
+
const threshold = (module === undefined ? undefined : settings.modules.get(module)) ?? settings.level;
|
|
1106
|
+
return LOG_LEVELS.indexOf(level) <= LOG_LEVELS.indexOf(threshold);
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
// src/config-schema-logger.ts
|
|
1110
|
+
var MODULE_LEVEL_KEY = "level";
|
|
1111
|
+
var MODULE_EXPECTED = `a mapping holding ${MODULE_LEVEL_KEY}`;
|
|
1112
|
+
var moduleLevel2 = (raw, at) => {
|
|
1113
|
+
if (!isMapping(raw))
|
|
1114
|
+
return refused(at, raw, MODULE_EXPECTED);
|
|
1115
|
+
const level = oneOf(LOG_LEVELS)(raw[MODULE_LEVEL_KEY], below(at, `.${MODULE_LEVEL_KEY}`));
|
|
1116
|
+
const extras = Object.entries(raw).filter(([key]) => key !== MODULE_LEVEL_KEY).map(([key, value]) => ({ key: `${at.key}.${key}`, value }));
|
|
1117
|
+
return { ...level, extras };
|
|
1118
|
+
};
|
|
1119
|
+
var LOGGER_DEFAULTS = Object.freeze({
|
|
1120
|
+
loggerKind: DEFAULT_LOGGER_KIND,
|
|
1121
|
+
loggerLevel: "warn",
|
|
1122
|
+
loggerTheme: "default",
|
|
1123
|
+
loggerModules: new Map,
|
|
1124
|
+
loggerCallSite: false,
|
|
1125
|
+
loggerApi: false
|
|
1126
|
+
});
|
|
1127
|
+
var LOGGER_SETTINGS = {
|
|
1128
|
+
loggerKind: { key: "logger.kind", read: text("an adapter kind, such as console"), cli: false },
|
|
1129
|
+
loggerLevel: { key: "logger.level", read: oneOf(LOG_LEVELS), cli: false },
|
|
1130
|
+
loggerTheme: { key: "logger.theme", read: oneOf(LOGGER_THEMES), cli: false },
|
|
1131
|
+
loggerModules: { key: "logger.modules", read: mapOf(moduleLevel2, MODULE_EXPECTED), cli: false },
|
|
1132
|
+
loggerCallSite: { key: "logger.callSite", read: flag, cli: false },
|
|
1133
|
+
loggerApi: { key: "logger.api", read: flag, cli: false }
|
|
1134
|
+
};
|
|
1135
|
+
function loggerSettingsOf(config) {
|
|
1136
|
+
return {
|
|
1137
|
+
kind: config.loggerKind,
|
|
1138
|
+
level: config.loggerLevel,
|
|
1139
|
+
theme: config.loggerTheme,
|
|
1140
|
+
modules: config.loggerModules,
|
|
1141
|
+
callSite: config.loggerCallSite,
|
|
1142
|
+
api: config.loggerApi
|
|
1143
|
+
};
|
|
1144
|
+
}
|
|
1145
|
+
|
|
695
1146
|
// src/config-schema-loop-continue.ts
|
|
696
1147
|
import { join as join2 } from "path";
|
|
697
1148
|
var RETRIES_ON_CONTINUE_MIN = 1;
|
|
@@ -825,7 +1276,8 @@ var TESTS_DEFAULTS = Object.freeze({
|
|
|
825
1276
|
"**/*-spawned*.test.ts",
|
|
826
1277
|
"**/*-cli.test.ts"
|
|
827
1278
|
]),
|
|
828
|
-
testsAlwaysRun: Object.freeze(["src/**/*.sweep.test.ts"])
|
|
1279
|
+
testsAlwaysRun: Object.freeze(["src/**/*.sweep.test.ts"]),
|
|
1280
|
+
testsRetakeRedAlone: true
|
|
829
1281
|
});
|
|
830
1282
|
var TESTS_SETTINGS = {
|
|
831
1283
|
testsFullSuiteTriggers: {
|
|
@@ -834,7 +1286,8 @@ var TESTS_SETTINGS = {
|
|
|
834
1286
|
cli: false
|
|
835
1287
|
},
|
|
836
1288
|
testsIntegration: { key: "tests.integration", read: globList, cli: false },
|
|
837
|
-
testsAlwaysRun: { key: "tests.alwaysRun", read: globList, cli: false }
|
|
1289
|
+
testsAlwaysRun: { key: "tests.alwaysRun", read: globList, cli: false },
|
|
1290
|
+
testsRetakeRedAlone: { key: "tests.retakeRedAlone", read: flag, cli: false }
|
|
838
1291
|
};
|
|
839
1292
|
|
|
840
1293
|
// src/config-schema-triage.ts
|
|
@@ -1085,6 +1538,9 @@ var CONFIG_DEFAULTS = Object.freeze({
|
|
|
1085
1538
|
claimsAhead: "off",
|
|
1086
1539
|
...TRIAGE_DEFAULTS,
|
|
1087
1540
|
...RELEASE_DEFAULTS,
|
|
1541
|
+
...ERRORS_DEFAULTS,
|
|
1542
|
+
...LOGGER_DEFAULTS,
|
|
1543
|
+
...ISSUES_DEFAULTS,
|
|
1088
1544
|
cleanupStaleDays: 30,
|
|
1089
1545
|
cleanupWorktreeIdleDays: 7,
|
|
1090
1546
|
cleanupKeep: Object.freeze([]),
|
|
@@ -1178,6 +1634,9 @@ var SETTINGS = {
|
|
|
1178
1634
|
claimsAhead: { key: "claims.ahead", read: claimsAhead, cli: false },
|
|
1179
1635
|
...TRIAGE_SETTINGS,
|
|
1180
1636
|
...RELEASE_SETTINGS,
|
|
1637
|
+
...ERRORS_SETTINGS,
|
|
1638
|
+
...LOGGER_SETTINGS,
|
|
1639
|
+
...ISSUES_SETTINGS,
|
|
1181
1640
|
cleanupStaleDays: { key: "cleanup.staleDays", read: dayCount, cli: false },
|
|
1182
1641
|
cleanupWorktreeIdleDays: {
|
|
1183
1642
|
key: "cleanup.worktreeIdleDays",
|
|
@@ -1335,6 +1794,18 @@ function readLayer(rawOf, atOf) {
|
|
|
1335
1794
|
releaseSettle: read("releaseSettle"),
|
|
1336
1795
|
releaseTag: read("releaseTag"),
|
|
1337
1796
|
releasePublishCommand: read("releasePublishCommand"),
|
|
1797
|
+
errorsCodes: read("errorsCodes"),
|
|
1798
|
+
loggerKind: read("loggerKind"),
|
|
1799
|
+
loggerLevel: read("loggerLevel"),
|
|
1800
|
+
loggerTheme: read("loggerTheme"),
|
|
1801
|
+
loggerModules: read("loggerModules"),
|
|
1802
|
+
loggerCallSite: read("loggerCallSite"),
|
|
1803
|
+
loggerApi: read("loggerApi"),
|
|
1804
|
+
issuesTitleBug: read("issuesTitleBug"),
|
|
1805
|
+
issuesSummaryMax: read("issuesSummaryMax"),
|
|
1806
|
+
issuesEnvironments: read("issuesEnvironments"),
|
|
1807
|
+
issuesVocabularyModules: read("issuesVocabularyModules"),
|
|
1808
|
+
issuesVocabularyActions: read("issuesVocabularyActions"),
|
|
1338
1809
|
cleanupStaleDays: read("cleanupStaleDays"),
|
|
1339
1810
|
cleanupWorktreeIdleDays: read("cleanupWorktreeIdleDays"),
|
|
1340
1811
|
cleanupKeep: read("cleanupKeep"),
|
|
@@ -1350,7 +1821,8 @@ function readLayer(rawOf, atOf) {
|
|
|
1350
1821
|
taskLessons: read("taskLessons"),
|
|
1351
1822
|
testsFullSuiteTriggers: read("testsFullSuiteTriggers"),
|
|
1352
1823
|
testsIntegration: read("testsIntegration"),
|
|
1353
|
-
testsAlwaysRun: read("testsAlwaysRun")
|
|
1824
|
+
testsAlwaysRun: read("testsAlwaysRun"),
|
|
1825
|
+
testsRetakeRedAlone: read("testsRetakeRedAlone")
|
|
1354
1826
|
};
|
|
1355
1827
|
return { layer, problems, extras };
|
|
1356
1828
|
}
|
|
@@ -1429,7 +1901,8 @@ function parseConfigText(text2, path) {
|
|
|
1429
1901
|
var MAP_SETTINGS = new Set([
|
|
1430
1902
|
"tiersSkills",
|
|
1431
1903
|
"tiersAgents",
|
|
1432
|
-
"routing"
|
|
1904
|
+
"routing",
|
|
1905
|
+
"loggerModules"
|
|
1433
1906
|
]);
|
|
1434
1907
|
function mergeMaps(...layers) {
|
|
1435
1908
|
const merged = new Map;
|
|
@@ -1846,7 +2319,7 @@ function planStubFromPath(planPath) {
|
|
|
1846
2319
|
}
|
|
1847
2320
|
|
|
1848
2321
|
// src/adapters/output/text.ts
|
|
1849
|
-
var
|
|
2322
|
+
var DEBUG_VERBOSITY2 = 2;
|
|
1850
2323
|
function formatPayload(payload) {
|
|
1851
2324
|
return typeof payload === "string" ? payload : JSON.stringify(payload);
|
|
1852
2325
|
}
|
|
@@ -1864,7 +2337,7 @@ function createTextOutput({ verbosity, stream }) {
|
|
|
1864
2337
|
`);
|
|
1865
2338
|
};
|
|
1866
2339
|
const debug = (message) => {
|
|
1867
|
-
if (verbosity >=
|
|
2340
|
+
if (verbosity >= DEBUG_VERBOSITY2)
|
|
1868
2341
|
writeLine(`debug: ${message}`);
|
|
1869
2342
|
};
|
|
1870
2343
|
const info = (message) => {
|
|
@@ -1926,14 +2399,16 @@ function createTextOutput({ verbosity, stream }) {
|
|
|
1926
2399
|
}
|
|
1927
2400
|
|
|
1928
2401
|
// src/adapters/output/active.ts
|
|
2402
|
+
import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
|
|
2403
|
+
var scopes2 = new AsyncLocalStorage2;
|
|
1929
2404
|
var DEFAULT_OUTPUT = createTextOutput({ verbosity: 0, stream: process.stdout });
|
|
1930
2405
|
var active = DEFAULT_OUTPUT;
|
|
1931
2406
|
var activeMode = "text";
|
|
1932
2407
|
function activeOutput() {
|
|
1933
|
-
return active;
|
|
2408
|
+
return scopes2.getStore()?.output ?? active;
|
|
1934
2409
|
}
|
|
1935
2410
|
function activeOutputMode() {
|
|
1936
|
-
return activeMode;
|
|
2411
|
+
return scopes2.getStore()?.mode ?? activeMode;
|
|
1937
2412
|
}
|
|
1938
2413
|
|
|
1939
|
-
export { MERGE_METHODS, isMergeMethod, SKILL_TIERS, RAFA_INSTINCTS_PATH, BUNDLED_SKILLS_DIR, isSkillTier, realEntry, bundledBinDirectory, skillTierDirectory, resolveSkillTiers, resolveInstinctScopes, tierExists, TEST_SCOPES, isAgentName, BUDGET_FLAG, readTestScope, parseTaskDeclaration, stripTaskDeclaration, resolveDeclarationFlags, isMapping, describeValue, messageOf, CONFIG_VERSIONS, STORE_BACKENDS, SYNC_STRATEGIES, BOARD_RELATIONSHIP_MODES, INJECT_MODES, OUTPUT_MODES, CLAUDE_SETTING_SOURCES, PR_PROVIDERS, RELEASE_AUTO, SKILL_RESOLVERS, CLAIMS_STALE_DISABLED, BUSY_TIMEOUT_MIN_MS, BUSY_TIMEOUT_MAX_MS, isBusyTimeoutMs, claimDurationHours, isGitHubLogin, BOARD_PROJECT_TEMPLATE_DEFAULT, listOf, hubContextOf, PREREQUISITE_KINDS, requiredPrerequisite, optionalPrerequisite, MODULE_SOURCE_KINDS, isLoopRetryCount, RELEASE_DEFAULTS, pinKey, pinLine, collisionMessage, readItemBytes, resolveTiers, findTierItem, DEFAULT_ROUTING, CONFIG_FILE, CONFIG_DEFAULTS, SETTINGS, ConfigError, configFilePath, parseConfigText, resolveConfig, isStampableStub, planStubFromPrompt, stampPrompt, planStubFromPath,
|
|
2414
|
+
export { MERGE_METHODS, isMergeMethod, SKILL_TIERS, RAFA_INSTINCTS_PATH, BUNDLED_SKILLS_DIR, isSkillTier, realEntry, bundledBinDirectory, skillTierDirectory, resolveSkillTiers, resolveInstinctScopes, tierExists, TEST_SCOPES, isAgentName, BUDGET_FLAG, readTestScope, parseTaskDeclaration, stripTaskDeclaration, resolveDeclarationFlags, isMapping, describeValue, messageOf, CONFIG_VERSIONS, STORE_BACKENDS, SYNC_STRATEGIES, BOARD_RELATIONSHIP_MODES, INJECT_MODES, OUTPUT_MODES, CLAUDE_SETTING_SOURCES, PR_PROVIDERS, RELEASE_AUTO, SKILL_RESOLVERS, CLAIMS_STALE_DISABLED, BUSY_TIMEOUT_MIN_MS, BUSY_TIMEOUT_MAX_MS, isBusyTimeoutMs, claimDurationHours, isGitHubLogin, BOARD_PROJECT_TEMPLATE_DEFAULT, listOf, hubContextOf, PREREQUISITE_KINDS, requiredPrerequisite, optionalPrerequisite, MODULE_SOURCE_KINDS, DEFAULT_LOGGER_KIND, setActiveLoggerSettings, activeLoggerSettings, levelEnabled, loggerSettingsOf, isLoopRetryCount, RELEASE_DEFAULTS, pinKey, pinLine, collisionMessage, readItemBytes, resolveTiers, findTierItem, DEFAULT_ROUTING, CONFIG_FILE, CONFIG_DEFAULTS, SETTINGS, ConfigError, configFilePath, parseConfigText, resolveConfig, isStampableStub, planStubFromPrompt, stampPrompt, planStubFromPath, RAFA_BLOCK_KINDS, isRafaBlockKind, readRafaBlocks, REPORT_STATUSES, FINDING_KINDS, FINDING_SIGNALS, FINDING_DOMAINS, CHANGE_LEVELS, parseReport, createTextOutput, activeOutput, activeOutputMode };
|