@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
|
@@ -0,0 +1,1125 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
CORE_SECTION,
|
|
4
|
+
activeSettings,
|
|
5
|
+
registerConfigSections,
|
|
6
|
+
setConfigLoadHook
|
|
7
|
+
} from "./index-gvek4r8m.js";
|
|
8
|
+
import {
|
|
9
|
+
PR_PROVIDERS,
|
|
10
|
+
RELEASE_AUTO,
|
|
11
|
+
below,
|
|
12
|
+
describeValue,
|
|
13
|
+
flag,
|
|
14
|
+
fragmentsDirectory,
|
|
15
|
+
isMapping,
|
|
16
|
+
listOf,
|
|
17
|
+
mapOf,
|
|
18
|
+
oneOf,
|
|
19
|
+
refused,
|
|
20
|
+
refusedWith,
|
|
21
|
+
releaseEnabled,
|
|
22
|
+
releaseFile,
|
|
23
|
+
releasePublishMode,
|
|
24
|
+
releaseSettleMode,
|
|
25
|
+
releaseStrategy,
|
|
26
|
+
releaseTagMode,
|
|
27
|
+
text,
|
|
28
|
+
usdAmount,
|
|
29
|
+
versionCollisionMode
|
|
30
|
+
} from "./index-ykggr043.js";
|
|
31
|
+
|
|
32
|
+
// src/adapters/logger/settings.ts
|
|
33
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
34
|
+
var LOG_LEVELS = Object.freeze(["error", "warn", "debug"]);
|
|
35
|
+
var LOGGER_THEMES = Object.freeze(["default", "plain"]);
|
|
36
|
+
var DEFAULT_LOGGER_KIND = "console";
|
|
37
|
+
var DEBUG_VERBOSITY = 2;
|
|
38
|
+
var API_VERBOSITY = 3;
|
|
39
|
+
var DEFAULT_LOGGER_SETTINGS = Object.freeze({
|
|
40
|
+
kind: DEFAULT_LOGGER_KIND,
|
|
41
|
+
level: "warn",
|
|
42
|
+
theme: "default",
|
|
43
|
+
modules: new Map,
|
|
44
|
+
callSite: false,
|
|
45
|
+
api: false
|
|
46
|
+
});
|
|
47
|
+
var scopes = new AsyncLocalStorage;
|
|
48
|
+
var moduleLevel = { settings: DEFAULT_LOGGER_SETTINGS };
|
|
49
|
+
function settingsOf(settings) {
|
|
50
|
+
return settings === null ? DEFAULT_LOGGER_SETTINGS : Object.freeze({ ...settings, modules: new Map(settings.modules) });
|
|
51
|
+
}
|
|
52
|
+
function cellHere() {
|
|
53
|
+
return scopes.getStore() ?? moduleLevel;
|
|
54
|
+
}
|
|
55
|
+
function setActiveLoggerSettings(settings) {
|
|
56
|
+
cellHere().settings = settingsOf(settings);
|
|
57
|
+
}
|
|
58
|
+
function activeLoggerSettings() {
|
|
59
|
+
return cellHere().settings;
|
|
60
|
+
}
|
|
61
|
+
function levelEnabled(level, module, settings, verbosity) {
|
|
62
|
+
if (level === "api")
|
|
63
|
+
return settings.api || verbosity >= API_VERBOSITY;
|
|
64
|
+
if (level === "debug" && verbosity >= DEBUG_VERBOSITY)
|
|
65
|
+
return true;
|
|
66
|
+
const threshold = (module === undefined ? undefined : settings.modules.get(module)) ?? settings.level;
|
|
67
|
+
return LOG_LEVELS.indexOf(level) <= LOG_LEVELS.indexOf(threshold);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// src/config-schema-board-project.ts
|
|
71
|
+
var BOARD_PROJECT_RETRIES_MIN = 1;
|
|
72
|
+
var BOARD_PROJECT_RETRIES_MAX = 10;
|
|
73
|
+
var BOARD_PROJECT_RETRY_WAIT_MIN_SECONDS = 1;
|
|
74
|
+
var BOARD_PROJECT_RETRY_WAIT_MAX_SECONDS = 60;
|
|
75
|
+
var BOARD_PROJECT_PROGRESS_MIN_SECONDS = 1;
|
|
76
|
+
var BOARD_PROJECT_PROGRESS_MAX_SECONDS = 300;
|
|
77
|
+
var BOARD_PROJECT_WRITE_BATCH_MIN = 1;
|
|
78
|
+
var BOARD_PROJECT_WRITE_BATCH_MAX = 100;
|
|
79
|
+
var BOARD_PROJECT_WRITE_PAUSE_MIN_MS = 0;
|
|
80
|
+
var BOARD_PROJECT_WRITE_PAUSE_MAX_MS = 60000;
|
|
81
|
+
function isWholeBetween(raw, min, max) {
|
|
82
|
+
return typeof raw === "number" && Number.isSafeInteger(raw) && raw >= min && raw <= max;
|
|
83
|
+
}
|
|
84
|
+
function rangeWords(min, max) {
|
|
85
|
+
return `a whole number from ${String(min)} to ${String(max)}`;
|
|
86
|
+
}
|
|
87
|
+
function wholeBetween(min, max) {
|
|
88
|
+
return (raw, at) => isWholeBetween(raw, min, max) ? { value: raw, problems: [], extras: [] } : refused(at, raw, rangeWords(min, max));
|
|
89
|
+
}
|
|
90
|
+
function offOrWholeBetween(min, max) {
|
|
91
|
+
return (raw, at) => raw === false || isWholeBetween(raw, min, max) ? { value: raw, problems: [], extras: [] } : refused(at, raw, `false or ${rangeWords(min, max)}`);
|
|
92
|
+
}
|
|
93
|
+
var boardProjectRetries = offOrWholeBetween(BOARD_PROJECT_RETRIES_MIN, BOARD_PROJECT_RETRIES_MAX);
|
|
94
|
+
var boardProjectRetryWaitSeconds = wholeBetween(BOARD_PROJECT_RETRY_WAIT_MIN_SECONDS, BOARD_PROJECT_RETRY_WAIT_MAX_SECONDS);
|
|
95
|
+
var boardProjectProgressSeconds = offOrWholeBetween(BOARD_PROJECT_PROGRESS_MIN_SECONDS, BOARD_PROJECT_PROGRESS_MAX_SECONDS);
|
|
96
|
+
var boardProjectWriteBatchSize = wholeBetween(BOARD_PROJECT_WRITE_BATCH_MIN, BOARD_PROJECT_WRITE_BATCH_MAX);
|
|
97
|
+
var boardProjectWritePauseMs = wholeBetween(BOARD_PROJECT_WRITE_PAUSE_MIN_MS, BOARD_PROJECT_WRITE_PAUSE_MAX_MS);
|
|
98
|
+
var BOARD_PROJECT_LIMIT_DEFAULTS = Object.freeze({
|
|
99
|
+
boardProjectRetries: 3,
|
|
100
|
+
boardProjectRetryWaitSeconds: 2,
|
|
101
|
+
boardProjectProgressSeconds: 10,
|
|
102
|
+
boardProjectWriteBatchSize: 20,
|
|
103
|
+
boardProjectWritePauseMs: 1000
|
|
104
|
+
});
|
|
105
|
+
var BOARD_PROJECT_LIMIT_SETTINGS = {
|
|
106
|
+
boardProjectRetries: { key: "board.project.retries", read: boardProjectRetries, cli: false },
|
|
107
|
+
boardProjectRetryWaitSeconds: {
|
|
108
|
+
key: "board.project.retryWaitSeconds",
|
|
109
|
+
read: boardProjectRetryWaitSeconds,
|
|
110
|
+
cli: false
|
|
111
|
+
},
|
|
112
|
+
boardProjectProgressSeconds: {
|
|
113
|
+
key: "board.project.progressSeconds",
|
|
114
|
+
read: boardProjectProgressSeconds,
|
|
115
|
+
cli: false
|
|
116
|
+
},
|
|
117
|
+
boardProjectWriteBatchSize: {
|
|
118
|
+
key: "board.project.writeBatchSize",
|
|
119
|
+
read: boardProjectWriteBatchSize,
|
|
120
|
+
cli: false
|
|
121
|
+
},
|
|
122
|
+
boardProjectWritePauseMs: {
|
|
123
|
+
key: "board.project.writePauseMs",
|
|
124
|
+
read: boardProjectWritePauseMs,
|
|
125
|
+
cli: false
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
var BOARD_PROJECT_SECTION = Object.freeze({
|
|
129
|
+
package: "board-project",
|
|
130
|
+
settings: Object.freeze(BOARD_PROJECT_LIMIT_SETTINGS),
|
|
131
|
+
defaults: BOARD_PROJECT_LIMIT_DEFAULTS
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// src/config-schema-bugs.ts
|
|
135
|
+
var BUGS_RECHECK_RUNS_MIN = 1;
|
|
136
|
+
var BUGS_RECHECK_RUNS_MAX = 20;
|
|
137
|
+
var BUGS_RECHECK_TIMEOUT_MIN = 1;
|
|
138
|
+
var BUGS_RECHECK_TIMEOUT_MAX = 3600;
|
|
139
|
+
function wholeNumberIn(min, max) {
|
|
140
|
+
return (raw, at) => typeof raw === "number" && Number.isSafeInteger(raw) && raw >= min && raw <= max ? { value: raw, problems: [], extras: [] } : refused(at, raw, `a whole number from ${String(min)} to ${String(max)}`);
|
|
141
|
+
}
|
|
142
|
+
var bugsRecheckRuns = wholeNumberIn(BUGS_RECHECK_RUNS_MIN, BUGS_RECHECK_RUNS_MAX);
|
|
143
|
+
var bugsRecheckTimeoutSeconds = wholeNumberIn(BUGS_RECHECK_TIMEOUT_MIN, BUGS_RECHECK_TIMEOUT_MAX);
|
|
144
|
+
var BUGS_DEFAULTS = Object.freeze({
|
|
145
|
+
bugsRecheckRuns: 5,
|
|
146
|
+
bugsRecheckTimeoutSeconds: 300
|
|
147
|
+
});
|
|
148
|
+
var BUGS_SETTINGS = {
|
|
149
|
+
bugsRecheckRuns: { key: "bugs.recheck.runs", read: bugsRecheckRuns, cli: false },
|
|
150
|
+
bugsRecheckTimeoutSeconds: { key: "bugs.recheck.timeoutSeconds", read: bugsRecheckTimeoutSeconds, cli: false }
|
|
151
|
+
};
|
|
152
|
+
var BUGS_SECTION = Object.freeze({
|
|
153
|
+
package: "bugs",
|
|
154
|
+
settings: Object.freeze(BUGS_SETTINGS),
|
|
155
|
+
defaults: BUGS_DEFAULTS
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// packages/rafa/src/errors/codes.ts
|
|
159
|
+
var ERROR_LEVELS = Object.freeze(["error", "warn"]);
|
|
160
|
+
var CODE_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*:[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
161
|
+
var NEW_CONTEXT_LEAF = "new-context";
|
|
162
|
+
var UNKNOWN_FAMILY = "unknown";
|
|
163
|
+
var TEXT_FIELDS = ["description", "hint", "since"];
|
|
164
|
+
var PREFIX = "error codes";
|
|
165
|
+
function familyOf(code) {
|
|
166
|
+
return code.slice(0, code.indexOf(":"));
|
|
167
|
+
}
|
|
168
|
+
function codeProblem(code) {
|
|
169
|
+
if (!CODE_PATTERN.test(code))
|
|
170
|
+
return `${JSON.stringify(code)} is not <family>:<leaf> in kebab-case`;
|
|
171
|
+
const leaf = code.slice(code.indexOf(":") + 1);
|
|
172
|
+
if (leaf === NEW_CONTEXT_LEAF || leaf === UNKNOWN_FAMILY) {
|
|
173
|
+
return `${JSON.stringify(code)} uses the reserved leaf ${leaf}`;
|
|
174
|
+
}
|
|
175
|
+
if (familyOf(code) === UNKNOWN_FAMILY)
|
|
176
|
+
return `${JSON.stringify(code)} uses the reserved family ${UNKNOWN_FAMILY}`;
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
function entryProblem(entry, index) {
|
|
180
|
+
const codeFault = codeProblem(entry.code);
|
|
181
|
+
if (codeFault !== null)
|
|
182
|
+
return `[${index}].code ${codeFault}`;
|
|
183
|
+
const empty = TEXT_FIELDS.find((field) => (entry[field] ?? "").trim() === "");
|
|
184
|
+
if (empty !== undefined)
|
|
185
|
+
return `[${index}].${empty} is empty`;
|
|
186
|
+
if (!ERROR_LEVELS.includes(entry.level)) {
|
|
187
|
+
return `[${index}].level is ${JSON.stringify(entry.level)}, expected ${ERROR_LEVELS.join(" or ")}`;
|
|
188
|
+
}
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
function defineErrorCodes(entries) {
|
|
192
|
+
entries.forEach((entry, index) => {
|
|
193
|
+
const fault = entryProblem(entry, index);
|
|
194
|
+
if (fault !== null)
|
|
195
|
+
throw new TypeError(`${PREFIX}: ${fault}`);
|
|
196
|
+
const first = entries.findIndex((other) => other.code === entry.code);
|
|
197
|
+
if (first < index) {
|
|
198
|
+
throw new TypeError(`${PREFIX}: ${JSON.stringify(entry.code)} is declared at [${first}] and [${index}]`);
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
return Object.freeze(entries.map((entry) => Object.freeze({ ...entry })));
|
|
202
|
+
}
|
|
203
|
+
function isKnownCode(code, entries) {
|
|
204
|
+
if (code === `${UNKNOWN_FAMILY}:${NEW_CONTEXT_LEAF}`)
|
|
205
|
+
return true;
|
|
206
|
+
if (entries.some((entry) => entry.code === code))
|
|
207
|
+
return true;
|
|
208
|
+
return code === `${familyOf(code)}:${NEW_CONTEXT_LEAF}` && entries.some((entry) => familyOf(entry.code) === familyOf(code));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// packages/rafa/src/errors/rafa-codes.ts
|
|
212
|
+
var SEED = "#949";
|
|
213
|
+
var FAMILY_DESCRIPTIONS = Object.freeze({
|
|
214
|
+
api: "a call to a remote service",
|
|
215
|
+
cli: "routing a command line and running the command",
|
|
216
|
+
config: "reading the project or user config",
|
|
217
|
+
fs: "reading or writing files",
|
|
218
|
+
git: "running git",
|
|
219
|
+
input: "a value given on the command line or in a file",
|
|
220
|
+
skill: "a skill file's frontmatter",
|
|
221
|
+
spawn: "starting a child process",
|
|
222
|
+
tracker: "the issue tracker",
|
|
223
|
+
tsc: "type-checking"
|
|
224
|
+
});
|
|
225
|
+
var RAFA_CODES = defineErrorCodes([
|
|
226
|
+
{ 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" },
|
|
227
|
+
{ 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" },
|
|
228
|
+
{ 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" },
|
|
229
|
+
{ 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" },
|
|
230
|
+
{ 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" },
|
|
231
|
+
{ 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" },
|
|
232
|
+
{ 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" },
|
|
233
|
+
{ 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" },
|
|
234
|
+
{ 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" },
|
|
235
|
+
{ 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" },
|
|
236
|
+
{ 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" },
|
|
237
|
+
{ 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" },
|
|
238
|
+
{ 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" },
|
|
239
|
+
{ 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" },
|
|
240
|
+
{ 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" },
|
|
241
|
+
{ 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" },
|
|
242
|
+
{ 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" },
|
|
243
|
+
{ 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" },
|
|
244
|
+
{ 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" },
|
|
245
|
+
{ code: "skill:forbidden-field", description: "an instinct field appears on a skill", hint: "remove the field", level: "error", since: SEED, legacy: "forbidden-field" },
|
|
246
|
+
{ 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" },
|
|
247
|
+
{ 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" },
|
|
248
|
+
{ 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" },
|
|
249
|
+
{ 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" },
|
|
250
|
+
{ 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 },
|
|
251
|
+
{ 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 },
|
|
252
|
+
{ 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 },
|
|
253
|
+
{ 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 },
|
|
254
|
+
{ 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 },
|
|
255
|
+
{ 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 },
|
|
256
|
+
{ code: "input:missing-param", description: "a required value was not given", hint: "pass the value the message names", level: "error", since: SEED },
|
|
257
|
+
{ 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 },
|
|
258
|
+
{ 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 },
|
|
259
|
+
{ 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 },
|
|
260
|
+
{ code: "tracker:unreachable", description: "the issue tracker could not be reached", hint: "check the network and gh auth status", level: "error", since: SEED },
|
|
261
|
+
{ 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" },
|
|
262
|
+
{ code: "spawn:nonzero-exit", description: "a child process exited nonzero", hint: "read the child's stderr above", level: "error", since: SEED }
|
|
263
|
+
]);
|
|
264
|
+
function listedCodes(projectCodes) {
|
|
265
|
+
return Object.freeze([
|
|
266
|
+
...RAFA_CODES.map((entry) => Object.freeze({ ...entry, source: "rafa" })),
|
|
267
|
+
...projectCodes.map((entry) => Object.freeze({ ...entry, source: "project" }))
|
|
268
|
+
]);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// src/config-schema-errors.ts
|
|
272
|
+
var ERROR_CODE_KEYS = ["code", "description", "hint", "level", "since"];
|
|
273
|
+
var KNOWN_KEYS = new Set(ERROR_CODE_KEYS);
|
|
274
|
+
var ERRORS_DEFAULTS = Object.freeze({ errorsCodes: Object.freeze([]) });
|
|
275
|
+
var codeText = (raw, at) => {
|
|
276
|
+
const read = text("a code, <family>:<leaf>")(raw, at);
|
|
277
|
+
if (read.value === undefined)
|
|
278
|
+
return read;
|
|
279
|
+
const fault = codeProblem(read.value);
|
|
280
|
+
return fault === null ? read : refused(at, raw, `a code: ${fault}`);
|
|
281
|
+
};
|
|
282
|
+
var EXPECTED = {
|
|
283
|
+
description: "a one-line description, a non-empty string",
|
|
284
|
+
hint: "the next action, a non-empty string",
|
|
285
|
+
since: "the version or issue that added it, a non-empty string"
|
|
286
|
+
};
|
|
287
|
+
var NO_SINCE = { value: undefined, problems: [], extras: [] };
|
|
288
|
+
var errorCodeEntry = (raw, at) => {
|
|
289
|
+
if (!isMapping(raw))
|
|
290
|
+
return refused(at, raw, `a mapping of: ${ERROR_CODE_KEYS.join(", ")}`);
|
|
291
|
+
const code = codeText(raw.code, below(at, ".code"));
|
|
292
|
+
const description = text(EXPECTED.description)(raw.description, below(at, ".description"));
|
|
293
|
+
const hint = text(EXPECTED.hint)(raw.hint, below(at, ".hint"));
|
|
294
|
+
const level = oneOf(ERROR_LEVELS)(raw.level, below(at, ".level"));
|
|
295
|
+
const since = raw.since === undefined || raw.since === null ? NO_SINCE : text(EXPECTED.since)(raw.since, below(at, ".since"));
|
|
296
|
+
const problems = [code, description, hint, level, since].flatMap((reading) => reading.problems);
|
|
297
|
+
const extras = Object.entries(raw).filter(([key]) => !KNOWN_KEYS.has(key)).map(([key, value]) => ({ key: `${at.key}.${key}`, value }));
|
|
298
|
+
if (code.value === undefined || description.value === undefined || hint.value === undefined || level.value === undefined || problems.length > 0)
|
|
299
|
+
return { value: undefined, problems, extras };
|
|
300
|
+
const entry = {
|
|
301
|
+
code: code.value,
|
|
302
|
+
description: description.value,
|
|
303
|
+
hint: hint.value,
|
|
304
|
+
level: level.value,
|
|
305
|
+
...since.value === undefined ? {} : { since: since.value }
|
|
306
|
+
};
|
|
307
|
+
return { value: Object.freeze(entry), problems: [], extras };
|
|
308
|
+
};
|
|
309
|
+
var errorCodes = (raw, at) => {
|
|
310
|
+
const read = listOf(errorCodeEntry, "error code entries")(raw, at);
|
|
311
|
+
const entries = read.value;
|
|
312
|
+
if (entries === undefined)
|
|
313
|
+
return read;
|
|
314
|
+
const problems = entries.flatMap((entry, index) => {
|
|
315
|
+
const label = `${below(at, `[${index}]`).label}.code is ${JSON.stringify(entry.code)}`;
|
|
316
|
+
if (RAFA_CODES.some((own) => own.code === entry.code)) {
|
|
317
|
+
return [`${label}, which rafa already declares; add a leaf of your own instead`];
|
|
318
|
+
}
|
|
319
|
+
const first = entries.findIndex((other) => other.code === entry.code);
|
|
320
|
+
return first < index ? [`${label}, already given at [${first}]`] : [];
|
|
321
|
+
});
|
|
322
|
+
return problems.length === 0 ? read : { ...refusedWith(problems), extras: read.extras };
|
|
323
|
+
};
|
|
324
|
+
var ERRORS_SETTINGS = {
|
|
325
|
+
errorsCodes: { key: "errors.codes", read: errorCodes, cli: false, itemKeys: ERROR_CODE_KEYS }
|
|
326
|
+
};
|
|
327
|
+
var ERRORS_SECTION = Object.freeze({
|
|
328
|
+
package: "errors",
|
|
329
|
+
settings: Object.freeze(ERRORS_SETTINGS),
|
|
330
|
+
defaults: ERRORS_DEFAULTS
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
// src/config-schema-features.ts
|
|
334
|
+
var FEATURES_DEFAULTS = Object.freeze({
|
|
335
|
+
featuresBoard: true,
|
|
336
|
+
featuresPr: true,
|
|
337
|
+
featuresRun: true,
|
|
338
|
+
featuresRelease: true
|
|
339
|
+
});
|
|
340
|
+
var FEATURES_SETTINGS = {
|
|
341
|
+
featuresBoard: { key: "features.board", read: flag, cli: false },
|
|
342
|
+
featuresPr: { key: "features.pr", read: flag, cli: false },
|
|
343
|
+
featuresRun: { key: "features.run", read: flag, cli: false },
|
|
344
|
+
featuresRelease: { key: "features.release", read: flag, cli: false }
|
|
345
|
+
};
|
|
346
|
+
var FEATURES_SECTION = Object.freeze({
|
|
347
|
+
package: "features",
|
|
348
|
+
settings: Object.freeze(FEATURES_SETTINGS),
|
|
349
|
+
defaults: FEATURES_DEFAULTS
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
// src/config-schema-hub.ts
|
|
353
|
+
var HUB_TIMEOUT_MIN_SECONDS = 1;
|
|
354
|
+
var HUB_TIMEOUT_MAX_SECONDS = 30;
|
|
355
|
+
var MS_PER_SECOND = 1000;
|
|
356
|
+
var HUB_TIMEOUT = /^(\d+)s$/;
|
|
357
|
+
var HUB_URL_PROTOCOLS = Object.freeze(["http:", "https:"]);
|
|
358
|
+
var HUB_DEFAULTS = Object.freeze({
|
|
359
|
+
hubUrl: null,
|
|
360
|
+
hubTokenSecret: null,
|
|
361
|
+
hubTimeout: "3s"
|
|
362
|
+
});
|
|
363
|
+
function hubTimeoutMs(raw) {
|
|
364
|
+
const match = typeof raw === "string" ? HUB_TIMEOUT.exec(raw) : null;
|
|
365
|
+
if (match === null)
|
|
366
|
+
return null;
|
|
367
|
+
const seconds = Number(match[1]);
|
|
368
|
+
return seconds >= HUB_TIMEOUT_MIN_SECONDS && seconds <= HUB_TIMEOUT_MAX_SECONDS ? seconds * MS_PER_SECOND : null;
|
|
369
|
+
}
|
|
370
|
+
var hubTimeout = (raw, at) => hubTimeoutMs(raw) === null ? refused(at, raw, `a duration of whole seconds from ${String(HUB_TIMEOUT_MIN_SECONDS)}s to ${String(HUB_TIMEOUT_MAX_SECONDS)}s, such as 3s`) : { value: raw, problems: [], extras: [] };
|
|
371
|
+
function isHubUrl(raw) {
|
|
372
|
+
if (typeof raw !== "string" || raw.trim() !== raw)
|
|
373
|
+
return false;
|
|
374
|
+
const url = URL.parse(raw);
|
|
375
|
+
return url !== null && HUB_URL_PROTOCOLS.includes(url.protocol) && url.username === "" && url.password === "";
|
|
376
|
+
}
|
|
377
|
+
var hubUrl = (raw, at) => isHubUrl(raw) ? { value: raw, problems: [], extras: [] } : refused(at, raw, "an http or https URL with no user name or password, such as https://hub.example.org");
|
|
378
|
+
var HUB_SETTINGS = {
|
|
379
|
+
hubUrl: { key: "hub.url", read: hubUrl, cli: false },
|
|
380
|
+
hubTokenSecret: { key: "hub.tokenSecret", read: text("a secret store name"), cli: false },
|
|
381
|
+
hubTimeout: { key: "hub.timeout", read: hubTimeout, cli: false }
|
|
382
|
+
};
|
|
383
|
+
var HUB_STRATEGY = "service";
|
|
384
|
+
function labelOf(input) {
|
|
385
|
+
const source = input.sources.effortSync;
|
|
386
|
+
const path = source === "user" ? input.userPath : input.path;
|
|
387
|
+
return path ?? source;
|
|
388
|
+
}
|
|
389
|
+
function hubUrlProblems(input) {
|
|
390
|
+
if (input.config.effortSync !== HUB_STRATEGY || input.config.hubUrl !== null)
|
|
391
|
+
return [];
|
|
392
|
+
return [
|
|
393
|
+
`${labelOf(input)}: effort.sync is ${describeValue(HUB_STRATEGY)} and no config file names hub.url;` + " expected hub.url, the address of the hub, such as https://hub.example.org"
|
|
394
|
+
];
|
|
395
|
+
}
|
|
396
|
+
var HUB_SECTION = Object.freeze({
|
|
397
|
+
package: "hub",
|
|
398
|
+
settings: Object.freeze(HUB_SETTINGS),
|
|
399
|
+
defaults: HUB_DEFAULTS,
|
|
400
|
+
checks: Object.freeze([hubUrlProblems])
|
|
401
|
+
});
|
|
402
|
+
function hubContextOf(config) {
|
|
403
|
+
const url = config.hubUrl ?? null;
|
|
404
|
+
if (url === null)
|
|
405
|
+
return;
|
|
406
|
+
const timeout = config.hubTimeout ?? HUB_DEFAULTS.hubTimeout;
|
|
407
|
+
const timeoutMs = hubTimeoutMs(timeout);
|
|
408
|
+
if (timeoutMs === null) {
|
|
409
|
+
throw new TypeError(`hub.timeout is ${describeValue(timeout)}, which no config accepts`);
|
|
410
|
+
}
|
|
411
|
+
return Object.freeze({ url, tokenSecret: config.hubTokenSecret ?? null, timeoutMs });
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// src/bugs/places.ts
|
|
415
|
+
var BUILT_IN_ENVIRONMENTS = ["local", "ci", "prod"];
|
|
416
|
+
var CI_OFF = ["", "0", "false"];
|
|
417
|
+
function suggestedEnvironment(env) {
|
|
418
|
+
return CI_OFF.includes((env["CI"] ?? "").trim().toLowerCase()) ? "local" : "ci";
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// src/bugs/title.ts
|
|
422
|
+
var TITLE_VARIABLES = ["type", "project", "projectType", "module", "action", "summary"];
|
|
423
|
+
var UNKNOWN_VALUE = "unknown";
|
|
424
|
+
var DEFAULT_BUG_TITLE = "?(${module}?( - ${action}): )${summary}";
|
|
425
|
+
var MODULE_SHAPE = "[a-z0-9][a-z0-9._-]*";
|
|
426
|
+
var ACTION_SHAPE = "[a-z0-9][a-z0-9._ -]*";
|
|
427
|
+
var SUMMARY = "summary";
|
|
428
|
+
var VARIABLE_SHAPES = { module: MODULE_SHAPE, action: ACTION_SHAPE };
|
|
429
|
+
var FREE_SHAPE = ".+";
|
|
430
|
+
var GROUP_OPEN = "?(";
|
|
431
|
+
var GROUP_CLOSE = ")";
|
|
432
|
+
var VARIABLE_OPEN = "${";
|
|
433
|
+
var VARIABLE_CLOSE = "}";
|
|
434
|
+
|
|
435
|
+
class TitleTemplateError extends Error {
|
|
436
|
+
constructor(message) {
|
|
437
|
+
super(message);
|
|
438
|
+
this.name = "TitleTemplateError";
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
function isPrintable(value) {
|
|
442
|
+
return typeof value === "string" && value.trim() !== "" && value.trim() !== UNKNOWN_VALUE;
|
|
443
|
+
}
|
|
444
|
+
function isTitleVariable(name) {
|
|
445
|
+
return TITLE_VARIABLES.includes(name);
|
|
446
|
+
}
|
|
447
|
+
function readVariable(template, at) {
|
|
448
|
+
const close = template.indexOf(VARIABLE_CLOSE, at);
|
|
449
|
+
if (close === -1)
|
|
450
|
+
throw new TitleTemplateError(`"${VARIABLE_OPEN}" at ${at} is never closed`);
|
|
451
|
+
const name = template.slice(at + VARIABLE_OPEN.length, close);
|
|
452
|
+
if (!isTitleVariable(name)) {
|
|
453
|
+
throw new TitleTemplateError(`\${${name}} names no variable, expected one of: ${TITLE_VARIABLES.join(", ")}`);
|
|
454
|
+
}
|
|
455
|
+
return { node: { kind: "variable", name }, next: close + VARIABLE_CLOSE.length };
|
|
456
|
+
}
|
|
457
|
+
function readNodes(template, start, depth) {
|
|
458
|
+
const nodes = [];
|
|
459
|
+
let text2 = "";
|
|
460
|
+
let at = start;
|
|
461
|
+
const flush = () => {
|
|
462
|
+
if (text2 !== "")
|
|
463
|
+
nodes.push({ kind: "text", text: text2 });
|
|
464
|
+
text2 = "";
|
|
465
|
+
};
|
|
466
|
+
while (at < template.length) {
|
|
467
|
+
if (template.startsWith(GROUP_OPEN, at)) {
|
|
468
|
+
flush();
|
|
469
|
+
const inner = readNodes(template, at + GROUP_OPEN.length, depth + 1);
|
|
470
|
+
nodes.push({ kind: "group", nodes: inner.nodes });
|
|
471
|
+
at = inner.next;
|
|
472
|
+
} else if (depth > 0 && template[at] === GROUP_CLOSE) {
|
|
473
|
+
flush();
|
|
474
|
+
return { nodes, next: at + GROUP_CLOSE.length };
|
|
475
|
+
} else if (template.startsWith(VARIABLE_OPEN, at)) {
|
|
476
|
+
flush();
|
|
477
|
+
const variable = readVariable(template, at);
|
|
478
|
+
nodes.push(variable.node);
|
|
479
|
+
at = variable.next;
|
|
480
|
+
} else {
|
|
481
|
+
text2 += template[at];
|
|
482
|
+
at += 1;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
if (depth > 0)
|
|
486
|
+
throw new TitleTemplateError(`a "${GROUP_OPEN}" group is never closed`);
|
|
487
|
+
flush();
|
|
488
|
+
return { nodes, next: at };
|
|
489
|
+
}
|
|
490
|
+
function parseTitleTemplate(template) {
|
|
491
|
+
return readNodes(template, 0, 0).nodes;
|
|
492
|
+
}
|
|
493
|
+
function variablesOf(nodes) {
|
|
494
|
+
return nodes.flatMap((node) => {
|
|
495
|
+
if (node.kind === "variable")
|
|
496
|
+
return [node.name];
|
|
497
|
+
return node.kind === "group" ? variablesOf(node.nodes) : [];
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
function groupShows(nodes, values) {
|
|
501
|
+
return nodes.every((node) => node.kind !== "variable" || isPrintable(values[node.name]));
|
|
502
|
+
}
|
|
503
|
+
function printed(values, name) {
|
|
504
|
+
const value = values[name];
|
|
505
|
+
return isPrintable(value) ? value.trim() : "";
|
|
506
|
+
}
|
|
507
|
+
function shownValues(nodes, values) {
|
|
508
|
+
return Object.fromEntries(nodes.flatMap((node) => {
|
|
509
|
+
if (node.kind === "text")
|
|
510
|
+
return [];
|
|
511
|
+
if (node.kind === "variable") {
|
|
512
|
+
return printed(values, node.name) === "" ? [] : [[node.name, printed(values, node.name)]];
|
|
513
|
+
}
|
|
514
|
+
return groupShows(node.nodes, values) ? Object.entries(shownValues(node.nodes, values)) : [];
|
|
515
|
+
}));
|
|
516
|
+
}
|
|
517
|
+
function renderNodes(nodes, values) {
|
|
518
|
+
return nodes.map((node) => {
|
|
519
|
+
if (node.kind === "text")
|
|
520
|
+
return node.text;
|
|
521
|
+
if (node.kind === "variable")
|
|
522
|
+
return printed(values, node.name);
|
|
523
|
+
return groupShows(node.nodes, values) ? renderNodes(node.nodes, values) : "";
|
|
524
|
+
}).join("");
|
|
525
|
+
}
|
|
526
|
+
function renderTitle(template, values) {
|
|
527
|
+
return renderNodes(parseTitleTemplate(template), values).trim();
|
|
528
|
+
}
|
|
529
|
+
function escapeLiteral(text2) {
|
|
530
|
+
return text2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
531
|
+
}
|
|
532
|
+
function patternOf(nodes, last) {
|
|
533
|
+
return nodes.map((node) => {
|
|
534
|
+
if (node.kind === "text")
|
|
535
|
+
return escapeLiteral(node.text);
|
|
536
|
+
if (node.kind === "group")
|
|
537
|
+
return `(?:${patternOf(node.nodes, last)})?`;
|
|
538
|
+
const shape = node.name === last ? FREE_SHAPE : `${VARIABLE_SHAPES[node.name] ?? FREE_SHAPE}?`;
|
|
539
|
+
return `(?<${node.name}>${shape})`;
|
|
540
|
+
}).join("");
|
|
541
|
+
}
|
|
542
|
+
function parseTitle(template, title) {
|
|
543
|
+
const nodes = parseTitleTemplate(template);
|
|
544
|
+
const names = variablesOf(nodes);
|
|
545
|
+
const match = new RegExp(`^${patternOf(nodes, names.at(-1))}$`, "u").exec(title.trim());
|
|
546
|
+
if (match === null)
|
|
547
|
+
return null;
|
|
548
|
+
return Object.fromEntries(names.flatMap((name) => {
|
|
549
|
+
const value = match.groups?.[name];
|
|
550
|
+
return value === undefined ? [] : [[name, value]];
|
|
551
|
+
}));
|
|
552
|
+
}
|
|
553
|
+
function titleRoundTrips(template, values) {
|
|
554
|
+
const nodes = parseTitleTemplate(template);
|
|
555
|
+
const title = renderNodes(nodes, values).trim();
|
|
556
|
+
if (title === "")
|
|
557
|
+
return false;
|
|
558
|
+
const read = parseTitle(template, title) ?? {};
|
|
559
|
+
const shown = shownValues(nodes, values);
|
|
560
|
+
return variablesOf(nodes).every((name) => (read[name] ?? null) === (shown[name] ?? null));
|
|
561
|
+
}
|
|
562
|
+
var SAMPLE = {
|
|
563
|
+
type: "bug",
|
|
564
|
+
project: "api",
|
|
565
|
+
projectType: "cli",
|
|
566
|
+
module: "loop",
|
|
567
|
+
action: "start",
|
|
568
|
+
summary: "Does not find the branch: again"
|
|
569
|
+
};
|
|
570
|
+
function samplesOf(names) {
|
|
571
|
+
const optional = names.filter((name) => name !== SUMMARY);
|
|
572
|
+
const subsets = optional.reduce((found, name) => [...found, ...found.map((subset) => [...subset, name])], [[]]);
|
|
573
|
+
return subsets.map((subset) => Object.fromEntries([...subset, SUMMARY].map((name) => [name, SAMPLE[name]])));
|
|
574
|
+
}
|
|
575
|
+
function nodesProblem(template, nodes) {
|
|
576
|
+
const names = variablesOf(nodes);
|
|
577
|
+
const twice = names.find((name, index) => names.indexOf(name) !== index);
|
|
578
|
+
if (twice !== undefined)
|
|
579
|
+
return `\${${twice}} appears twice`;
|
|
580
|
+
if (names.at(-1) !== SUMMARY)
|
|
581
|
+
return `\${${SUMMARY}} must be the last variable`;
|
|
582
|
+
if (!nodes.some((node) => node.kind === "variable" && node.name === SUMMARY)) {
|
|
583
|
+
return `\${${SUMMARY}} must stand outside every ?( ) group`;
|
|
584
|
+
}
|
|
585
|
+
const failed = samplesOf(names).find((sample) => !titleRoundTrips(template, sample));
|
|
586
|
+
return failed === undefined ? null : `the title ${JSON.stringify(renderTitle(template, failed))} does not read back as the fields it was rendered from`;
|
|
587
|
+
}
|
|
588
|
+
function templateProblem(template) {
|
|
589
|
+
try {
|
|
590
|
+
return nodesProblem(template, parseTitleTemplate(template));
|
|
591
|
+
} catch (error) {
|
|
592
|
+
if (error instanceof TitleTemplateError)
|
|
593
|
+
return error.message;
|
|
594
|
+
throw error;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// src/config-schema-issues.ts
|
|
599
|
+
var SUMMARY_MAX_DEFAULT = 80;
|
|
600
|
+
var SUMMARY_MAX_FLOOR = 20;
|
|
601
|
+
var SUMMARY_MAX_CEILING = 120;
|
|
602
|
+
var TEMPLATE_EXPECTED = "a title template";
|
|
603
|
+
var PLACE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
604
|
+
var MODULE = new RegExp(`^${MODULE_SHAPE}$`);
|
|
605
|
+
var ACTION = new RegExp(`^${ACTION_SHAPE}$`);
|
|
606
|
+
function accepted(value) {
|
|
607
|
+
return { value, problems: [], extras: [] };
|
|
608
|
+
}
|
|
609
|
+
var titleTemplate = (raw, at) => {
|
|
610
|
+
if (typeof raw !== "string" || raw.trim() === "")
|
|
611
|
+
return refused(at, raw, TEMPLATE_EXPECTED);
|
|
612
|
+
const problem = templateProblem(raw);
|
|
613
|
+
return problem === null ? accepted(raw) : refused(at, raw, `${TEMPLATE_EXPECTED}: ${problem}`);
|
|
614
|
+
};
|
|
615
|
+
var summaryMax = (raw, at) => typeof raw === "number" && Number.isSafeInteger(raw) && raw >= SUMMARY_MAX_FLOOR && raw <= SUMMARY_MAX_CEILING ? accepted(raw) : refused(at, raw, `a whole number from ${SUMMARY_MAX_FLOOR} to ${SUMMARY_MAX_CEILING}`);
|
|
616
|
+
function nameOf(shape, reserved, expected) {
|
|
617
|
+
return (raw, at) => typeof raw === "string" && shape.test(raw) && !reserved.includes(raw) ? accepted(raw) : refused(at, raw, expected);
|
|
618
|
+
}
|
|
619
|
+
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}`);
|
|
620
|
+
var moduleName = nameOf(MODULE, [UNKNOWN_VALUE], `a module name in lower-case letters, digits, ".", "_" and "-", other than ${UNKNOWN_VALUE}`);
|
|
621
|
+
var actionName = nameOf(ACTION, [UNKNOWN_VALUE], `an action in lower-case letters, digits, ".", "_", "-" and spaces, other than ${UNKNOWN_VALUE}`);
|
|
622
|
+
var ISSUES_DEFAULTS = Object.freeze({
|
|
623
|
+
issuesTitleBug: DEFAULT_BUG_TITLE,
|
|
624
|
+
issuesSummaryMax: SUMMARY_MAX_DEFAULT,
|
|
625
|
+
issuesEnvironments: Object.freeze([]),
|
|
626
|
+
issuesVocabularyModules: Object.freeze([]),
|
|
627
|
+
issuesVocabularyActions: Object.freeze([])
|
|
628
|
+
});
|
|
629
|
+
var ISSUES_SETTINGS = {
|
|
630
|
+
issuesTitleBug: { key: "issues.titles.bug", read: titleTemplate, cli: false },
|
|
631
|
+
issuesSummaryMax: { key: "issues.titles.summaryMax", read: summaryMax, cli: false },
|
|
632
|
+
issuesEnvironments: { key: "issues.environments", read: listOf(place, "place names"), cli: false },
|
|
633
|
+
issuesVocabularyModules: { key: "issues.vocabulary.modules", read: listOf(moduleName, "module names"), cli: false },
|
|
634
|
+
issuesVocabularyActions: { key: "issues.vocabulary.actions", read: listOf(actionName, "actions"), cli: false }
|
|
635
|
+
};
|
|
636
|
+
var ISSUES_SECTION = Object.freeze({
|
|
637
|
+
package: "issues",
|
|
638
|
+
settings: Object.freeze(ISSUES_SETTINGS),
|
|
639
|
+
defaults: ISSUES_DEFAULTS
|
|
640
|
+
});
|
|
641
|
+
function bugRulesOf(config) {
|
|
642
|
+
return {
|
|
643
|
+
template: config.issuesTitleBug,
|
|
644
|
+
summaryMax: config.issuesSummaryMax,
|
|
645
|
+
environments: [...BUILT_IN_ENVIRONMENTS, ...config.issuesEnvironments],
|
|
646
|
+
modules: config.issuesVocabularyModules,
|
|
647
|
+
actions: config.issuesVocabularyActions,
|
|
648
|
+
codes: listedCodes(config.errorsCodes)
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// src/config-schema-logger.ts
|
|
653
|
+
var MODULE_LEVEL_KEY = "level";
|
|
654
|
+
var MODULE_EXPECTED = `a mapping holding ${MODULE_LEVEL_KEY}`;
|
|
655
|
+
var moduleLevel2 = (raw, at) => {
|
|
656
|
+
if (!isMapping(raw))
|
|
657
|
+
return refused(at, raw, MODULE_EXPECTED);
|
|
658
|
+
const level = oneOf(LOG_LEVELS)(raw[MODULE_LEVEL_KEY], below(at, `.${MODULE_LEVEL_KEY}`));
|
|
659
|
+
const extras = Object.entries(raw).filter(([key]) => key !== MODULE_LEVEL_KEY).map(([key, value]) => ({ key: `${at.key}.${key}`, value }));
|
|
660
|
+
return { ...level, extras };
|
|
661
|
+
};
|
|
662
|
+
var LOGGER_DEFAULTS = Object.freeze({
|
|
663
|
+
loggerKind: DEFAULT_LOGGER_KIND,
|
|
664
|
+
loggerLevel: "warn",
|
|
665
|
+
loggerTheme: "default",
|
|
666
|
+
loggerModules: new Map,
|
|
667
|
+
loggerCallSite: false,
|
|
668
|
+
loggerApi: false
|
|
669
|
+
});
|
|
670
|
+
var LOGGER_SETTINGS = {
|
|
671
|
+
loggerKind: { key: "logger.kind", read: text("an adapter kind, such as console"), cli: false },
|
|
672
|
+
loggerLevel: { key: "logger.level", read: oneOf(LOG_LEVELS), cli: false },
|
|
673
|
+
loggerTheme: { key: "logger.theme", read: oneOf(LOGGER_THEMES), cli: false },
|
|
674
|
+
loggerModules: { key: "logger.modules", read: mapOf(moduleLevel2, MODULE_EXPECTED), cli: false, map: true },
|
|
675
|
+
loggerCallSite: { key: "logger.callSite", read: flag, cli: false },
|
|
676
|
+
loggerApi: { key: "logger.api", read: flag, cli: false }
|
|
677
|
+
};
|
|
678
|
+
var LOGGER_SECTION = Object.freeze({
|
|
679
|
+
package: "logger",
|
|
680
|
+
settings: Object.freeze(LOGGER_SETTINGS),
|
|
681
|
+
defaults: LOGGER_DEFAULTS
|
|
682
|
+
});
|
|
683
|
+
function loggerSettingsOf(config) {
|
|
684
|
+
return {
|
|
685
|
+
kind: config.loggerKind,
|
|
686
|
+
level: config.loggerLevel,
|
|
687
|
+
theme: config.loggerTheme,
|
|
688
|
+
modules: config.loggerModules,
|
|
689
|
+
callSite: config.loggerCallSite,
|
|
690
|
+
api: config.loggerApi
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
// src/config-schema-loop-continue.ts
|
|
695
|
+
import { join } from "path";
|
|
696
|
+
var RETRIES_ON_CONTINUE_MIN = 1;
|
|
697
|
+
var RETRIES_ON_CONTINUE_MAX = 3;
|
|
698
|
+
var FORCE_WRAP_UP_MAX_NEW_FAILURES_MIN = 1;
|
|
699
|
+
var FORCE_WRAP_UP_MAX_NEW_FAILURES_MAX = 50;
|
|
700
|
+
var CONTINUE_CRITERIA_MODES = ["extend", "replace"];
|
|
701
|
+
function countOrFalse(min, max) {
|
|
702
|
+
const expected = `false or a whole number from ${String(min)} to ${String(max)}`;
|
|
703
|
+
return (raw, at) => raw === false || typeof raw === "number" && Number.isSafeInteger(raw) && raw >= min && raw <= max ? { value: raw, problems: [], extras: [] } : refused(at, raw, expected);
|
|
704
|
+
}
|
|
705
|
+
var retriesOnContinue = countOrFalse(RETRIES_ON_CONTINUE_MIN, RETRIES_ON_CONTINUE_MAX);
|
|
706
|
+
var forceWrapUpMaxNewFailures = countOrFalse(FORCE_WRAP_UP_MAX_NEW_FAILURES_MIN, FORCE_WRAP_UP_MAX_NEW_FAILURES_MAX);
|
|
707
|
+
var continueCriteria = text("a file path");
|
|
708
|
+
var continueCriteriaMode = oneOf(CONTINUE_CRITERIA_MODES);
|
|
709
|
+
var LOOP_CONTINUE_DEFAULTS = Object.freeze({
|
|
710
|
+
loopRetriesOnContinue: 1,
|
|
711
|
+
loopContinueCriteria: join(".rafa", "continue-criteria.md"),
|
|
712
|
+
loopContinueCriteriaMode: "extend",
|
|
713
|
+
loopForceWrapUpMaxNewFailures: false
|
|
714
|
+
});
|
|
715
|
+
var LOOP_CONTINUE_SETTINGS = {
|
|
716
|
+
loopRetriesOnContinue: { key: "loop.retriesOnContinue", read: retriesOnContinue, cli: false },
|
|
717
|
+
loopContinueCriteria: { key: "loop.continue.criteria", read: continueCriteria, cli: false },
|
|
718
|
+
loopContinueCriteriaMode: { key: "loop.continue.criteriaMode", read: continueCriteriaMode, cli: false },
|
|
719
|
+
loopForceWrapUpMaxNewFailures: {
|
|
720
|
+
key: "loop.forceWrapUp.maxNewFailures",
|
|
721
|
+
read: forceWrapUpMaxNewFailures,
|
|
722
|
+
cli: false
|
|
723
|
+
}
|
|
724
|
+
};
|
|
725
|
+
var LOOP_CONTINUE_SECTION = Object.freeze({
|
|
726
|
+
package: "loop-continue",
|
|
727
|
+
settings: Object.freeze(LOOP_CONTINUE_SETTINGS),
|
|
728
|
+
defaults: LOOP_CONTINUE_DEFAULTS
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
// src/config-schema-loop-retries.ts
|
|
732
|
+
var LOOP_RETRIES_MIN = 1;
|
|
733
|
+
var LOOP_RETRIES_MAX = 3;
|
|
734
|
+
function isLoopRetryCount(raw) {
|
|
735
|
+
return typeof raw === "number" && Number.isSafeInteger(raw) && raw >= LOOP_RETRIES_MIN && raw <= LOOP_RETRIES_MAX;
|
|
736
|
+
}
|
|
737
|
+
var loopRetries = (raw, at) => raw === false || isLoopRetryCount(raw) ? { value: raw, problems: [], extras: [] } : refused(at, raw, `false or a whole number from ${String(LOOP_RETRIES_MIN)} to ${String(LOOP_RETRIES_MAX)}`);
|
|
738
|
+
var LOOP_RETRIES_DEFAULTS = Object.freeze({
|
|
739
|
+
loopRetries: false
|
|
740
|
+
});
|
|
741
|
+
var LOOP_RETRIES_SETTINGS = {
|
|
742
|
+
loopRetries: { key: "loop.retries", read: loopRetries, cli: false }
|
|
743
|
+
};
|
|
744
|
+
var LOOP_RETRIES_SECTION = Object.freeze({
|
|
745
|
+
package: "loop-retries",
|
|
746
|
+
settings: Object.freeze(LOOP_RETRIES_SETTINGS),
|
|
747
|
+
defaults: LOOP_RETRIES_DEFAULTS
|
|
748
|
+
});
|
|
749
|
+
|
|
750
|
+
// src/pr/types.ts
|
|
751
|
+
var MERGE_METHODS = Object.freeze([
|
|
752
|
+
"squash",
|
|
753
|
+
"merge",
|
|
754
|
+
"rebase"
|
|
755
|
+
]);
|
|
756
|
+
function isMergeMethod(value) {
|
|
757
|
+
return typeof value === "string" && MERGE_METHODS.includes(value);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
// src/config-schema-release.ts
|
|
761
|
+
var PR_DEFAULTS = Object.freeze({
|
|
762
|
+
prProvider: null,
|
|
763
|
+
prMergeMethod: "squash",
|
|
764
|
+
prBase: null,
|
|
765
|
+
prResolveBudget: 2,
|
|
766
|
+
prVersionCollision: "report"
|
|
767
|
+
});
|
|
768
|
+
var RELEASE_DEFAULTS = Object.freeze({
|
|
769
|
+
releaseEnabled: RELEASE_AUTO,
|
|
770
|
+
releaseVersionFile: "package.json",
|
|
771
|
+
releaseChangelog: "CHANGELOG.md",
|
|
772
|
+
releaseHeading: "## {version} \u2014 {date}, {title}",
|
|
773
|
+
releaseFragments: ".changes",
|
|
774
|
+
releaseStrategy: "semver-by-level",
|
|
775
|
+
releaseSettle: "push",
|
|
776
|
+
releaseTag: "manual",
|
|
777
|
+
releasePublishCommand: "npm publish",
|
|
778
|
+
releasePublish: "manual",
|
|
779
|
+
releaseMoveLock: false
|
|
780
|
+
});
|
|
781
|
+
var DANGEROUS_RELEASE_DEFAULTS = Object.freeze({
|
|
782
|
+
dangerousAcceptVersionCollision: false
|
|
783
|
+
});
|
|
784
|
+
var mergeMethod = oneOf(MERGE_METHODS);
|
|
785
|
+
var PR_SETTINGS = {
|
|
786
|
+
prProvider: { key: "pr.provider", read: oneOf(PR_PROVIDERS), cli: false },
|
|
787
|
+
prMergeMethod: { key: "pr.mergeMethod", read: mergeMethod, cli: false },
|
|
788
|
+
prBase: { key: "pr.base", read: text("a branch name"), cli: false },
|
|
789
|
+
prResolveBudget: { key: "pr.resolveBudget", read: usdAmount, cli: false },
|
|
790
|
+
prVersionCollision: {
|
|
791
|
+
key: "pr.versionCollision",
|
|
792
|
+
read: versionCollisionMode,
|
|
793
|
+
cli: false
|
|
794
|
+
}
|
|
795
|
+
};
|
|
796
|
+
var RELEASE_SETTINGS = {
|
|
797
|
+
releaseEnabled: { key: "release.enabled", read: releaseEnabled, cli: false },
|
|
798
|
+
releaseVersionFile: {
|
|
799
|
+
key: "release.versionFile",
|
|
800
|
+
read: releaseFile,
|
|
801
|
+
cli: false
|
|
802
|
+
},
|
|
803
|
+
releaseChangelog: { key: "release.changelog", read: releaseFile, cli: false },
|
|
804
|
+
releaseHeading: {
|
|
805
|
+
key: "release.heading",
|
|
806
|
+
read: text("a changelog heading template"),
|
|
807
|
+
cli: false
|
|
808
|
+
},
|
|
809
|
+
releaseFragments: {
|
|
810
|
+
key: "release.fragments",
|
|
811
|
+
read: fragmentsDirectory,
|
|
812
|
+
cli: false
|
|
813
|
+
},
|
|
814
|
+
releaseStrategy: { key: "release.strategy", read: releaseStrategy, cli: false },
|
|
815
|
+
releaseSettle: { key: "release.settle", read: releaseSettleMode, cli: false },
|
|
816
|
+
releaseTag: { key: "release.tag", read: releaseTagMode, cli: false },
|
|
817
|
+
releasePublishCommand: {
|
|
818
|
+
key: "release.publishCommand",
|
|
819
|
+
read: text("a publish command"),
|
|
820
|
+
cli: false
|
|
821
|
+
},
|
|
822
|
+
releasePublish: { key: "release.publish", read: releasePublishMode, cli: false },
|
|
823
|
+
releaseMoveLock: { key: "release.moveLock", read: flag, cli: false }
|
|
824
|
+
};
|
|
825
|
+
var DANGEROUS_RELEASE_SETTINGS = {
|
|
826
|
+
dangerousAcceptVersionCollision: {
|
|
827
|
+
key: "dangerous.acceptVersionCollision",
|
|
828
|
+
read: flag,
|
|
829
|
+
cli: false
|
|
830
|
+
}
|
|
831
|
+
};
|
|
832
|
+
var RELEASE_SECTION = Object.freeze({
|
|
833
|
+
package: "release",
|
|
834
|
+
settings: Object.freeze({ ...PR_SETTINGS, ...RELEASE_SETTINGS, ...DANGEROUS_RELEASE_SETTINGS }),
|
|
835
|
+
defaults: Object.freeze({ ...PR_DEFAULTS, ...RELEASE_DEFAULTS, ...DANGEROUS_RELEASE_DEFAULTS })
|
|
836
|
+
});
|
|
837
|
+
|
|
838
|
+
// src/config-schema-tests.ts
|
|
839
|
+
import { isAbsolute } from "path";
|
|
840
|
+
var GLOB_PATTERN = "a glob pattern relative to the repository root";
|
|
841
|
+
var repoGlob = (raw, at) => typeof raw === "string" && isAbsolute(raw) ? refused(at, raw, GLOB_PATTERN) : text(GLOB_PATTERN)(raw, at);
|
|
842
|
+
var globList = listOf(repoGlob, "glob patterns");
|
|
843
|
+
var TESTS_DEFAULTS = Object.freeze({
|
|
844
|
+
testsFullSuiteTriggers: Object.freeze([
|
|
845
|
+
"bunfig.toml",
|
|
846
|
+
"tsconfig*.json",
|
|
847
|
+
"package.json",
|
|
848
|
+
"bun.lock",
|
|
849
|
+
"bun.lockb"
|
|
850
|
+
]),
|
|
851
|
+
testsIntegration: Object.freeze([
|
|
852
|
+
"**/*-integration.test.ts",
|
|
853
|
+
"**/*.integration.test.ts",
|
|
854
|
+
"**/*-spawned*.test.ts",
|
|
855
|
+
"**/*-cli.test.ts"
|
|
856
|
+
]),
|
|
857
|
+
testsContract: Object.freeze(["**/*.contract.test.ts"]),
|
|
858
|
+
testsAlwaysRun: Object.freeze(["src/**/*.sweep.test.ts"]),
|
|
859
|
+
testsRetakeRedAlone: true
|
|
860
|
+
});
|
|
861
|
+
var TESTS_SETTINGS = {
|
|
862
|
+
testsFullSuiteTriggers: {
|
|
863
|
+
key: "tests.fullSuiteTriggers",
|
|
864
|
+
read: globList,
|
|
865
|
+
cli: false
|
|
866
|
+
},
|
|
867
|
+
testsIntegration: { key: "tests.integration", read: globList, cli: false },
|
|
868
|
+
testsContract: { key: "tests.contract", read: globList, cli: false },
|
|
869
|
+
testsAlwaysRun: { key: "tests.alwaysRun", read: globList, cli: false },
|
|
870
|
+
testsRetakeRedAlone: { key: "tests.retakeRedAlone", read: flag, cli: false }
|
|
871
|
+
};
|
|
872
|
+
var TESTS_SECTION = Object.freeze({
|
|
873
|
+
package: "tests",
|
|
874
|
+
settings: Object.freeze(TESTS_SETTINGS),
|
|
875
|
+
defaults: TESTS_DEFAULTS
|
|
876
|
+
});
|
|
877
|
+
|
|
878
|
+
// src/config-schema-triage.ts
|
|
879
|
+
var SIMILARITY_THRESHOLD_MAX = 1;
|
|
880
|
+
var SIMILARITY_WEIGHT_MIN = 0;
|
|
881
|
+
var SIMILARITY_WEIGHT_MAX = 1;
|
|
882
|
+
var SIMILARITY_CANDIDATES_MIN = 1;
|
|
883
|
+
var SIMILARITY_CANDIDATES_MAX = 10;
|
|
884
|
+
function isThreshold(raw) {
|
|
885
|
+
return typeof raw === "number" && Number.isFinite(raw) && raw > 0 && raw <= SIMILARITY_THRESHOLD_MAX;
|
|
886
|
+
}
|
|
887
|
+
function isCandidateCount(raw) {
|
|
888
|
+
return typeof raw === "number" && Number.isSafeInteger(raw) && raw >= SIMILARITY_CANDIDATES_MIN && raw <= SIMILARITY_CANDIDATES_MAX;
|
|
889
|
+
}
|
|
890
|
+
function isWeight(raw) {
|
|
891
|
+
return typeof raw === "number" && Number.isFinite(raw) && raw >= SIMILARITY_WEIGHT_MIN && raw <= SIMILARITY_WEIGHT_MAX;
|
|
892
|
+
}
|
|
893
|
+
var similarityThreshold = (raw, at) => raw === false || isThreshold(raw) ? { value: raw, problems: [], extras: [] } : refused(at, raw, `false or a number above 0 and at most ${String(SIMILARITY_THRESHOLD_MAX)}`);
|
|
894
|
+
var similarityCandidates = (raw, at) => isCandidateCount(raw) ? { value: raw, problems: [], extras: [] } : refused(at, raw, `a whole number from ${String(SIMILARITY_CANDIDATES_MIN)} to ${String(SIMILARITY_CANDIDATES_MAX)}`);
|
|
895
|
+
var similarityWeight = (raw, at) => isWeight(raw) ? { value: raw, problems: [], extras: [] } : refused(at, raw, `a number from ${String(SIMILARITY_WEIGHT_MIN)} to ${String(SIMILARITY_WEIGHT_MAX)}`);
|
|
896
|
+
var TRIAGE_DEFAULTS = Object.freeze({
|
|
897
|
+
triageSimilarityThreshold: 0.3,
|
|
898
|
+
triageSimilarityCandidates: 3,
|
|
899
|
+
triageSimilarityWeightsCauseLeaf: 0.15,
|
|
900
|
+
triageSimilarityWeightsCauseFamily: 0.05,
|
|
901
|
+
triageSimilarityWeightsBoundary: 0.1
|
|
902
|
+
});
|
|
903
|
+
var TRIAGE_SETTINGS = {
|
|
904
|
+
triageSimilarityThreshold: {
|
|
905
|
+
key: "triage.similarity.threshold",
|
|
906
|
+
read: similarityThreshold,
|
|
907
|
+
cli: false
|
|
908
|
+
},
|
|
909
|
+
triageSimilarityCandidates: {
|
|
910
|
+
key: "triage.similarity.candidates",
|
|
911
|
+
read: similarityCandidates,
|
|
912
|
+
cli: false
|
|
913
|
+
},
|
|
914
|
+
triageSimilarityWeightsCauseLeaf: {
|
|
915
|
+
key: "triage.similarity.weights.causeLeaf",
|
|
916
|
+
read: similarityWeight,
|
|
917
|
+
cli: false
|
|
918
|
+
},
|
|
919
|
+
triageSimilarityWeightsCauseFamily: {
|
|
920
|
+
key: "triage.similarity.weights.causeFamily",
|
|
921
|
+
read: similarityWeight,
|
|
922
|
+
cli: false
|
|
923
|
+
},
|
|
924
|
+
triageSimilarityWeightsBoundary: {
|
|
925
|
+
key: "triage.similarity.weights.boundary",
|
|
926
|
+
read: similarityWeight,
|
|
927
|
+
cli: false
|
|
928
|
+
}
|
|
929
|
+
};
|
|
930
|
+
var TRIAGE_SECTION = Object.freeze({
|
|
931
|
+
package: "triage",
|
|
932
|
+
settings: Object.freeze(TRIAGE_SETTINGS),
|
|
933
|
+
defaults: TRIAGE_DEFAULTS
|
|
934
|
+
});
|
|
935
|
+
|
|
936
|
+
// src/config-schema-wrap-up.ts
|
|
937
|
+
var WRAP_UP_RETRIES_MIN = 1;
|
|
938
|
+
var WRAP_UP_RETRIES_MAX = 3;
|
|
939
|
+
function isRetryCount(raw) {
|
|
940
|
+
return typeof raw === "number" && Number.isSafeInteger(raw) && raw >= WRAP_UP_RETRIES_MIN && raw <= WRAP_UP_RETRIES_MAX;
|
|
941
|
+
}
|
|
942
|
+
var wrapUpRetries = (raw, at) => raw === false || isRetryCount(raw) ? { value: raw, problems: [], extras: [] } : refused(at, raw, `false or a whole number from ${String(WRAP_UP_RETRIES_MIN)} to ${String(WRAP_UP_RETRIES_MAX)}`);
|
|
943
|
+
var WRAP_UP_DEFAULTS = Object.freeze({
|
|
944
|
+
loopWrapUpRetries: 1
|
|
945
|
+
});
|
|
946
|
+
var WRAP_UP_SETTINGS = {
|
|
947
|
+
loopWrapUpRetries: { key: "loop.wrapUp.retries", read: wrapUpRetries, cli: false }
|
|
948
|
+
};
|
|
949
|
+
var WRAP_UP_SECTION = Object.freeze({
|
|
950
|
+
package: "wrap-up",
|
|
951
|
+
settings: Object.freeze(WRAP_UP_SETTINGS),
|
|
952
|
+
defaults: WRAP_UP_DEFAULTS
|
|
953
|
+
});
|
|
954
|
+
|
|
955
|
+
// src/config-registry.ts
|
|
956
|
+
var CONFIG_SECTIONS = Object.freeze([
|
|
957
|
+
CORE_SECTION,
|
|
958
|
+
HUB_SECTION,
|
|
959
|
+
LOOP_RETRIES_SECTION,
|
|
960
|
+
LOOP_CONTINUE_SECTION,
|
|
961
|
+
WRAP_UP_SECTION,
|
|
962
|
+
RELEASE_SECTION,
|
|
963
|
+
BOARD_PROJECT_SECTION,
|
|
964
|
+
TRIAGE_SECTION,
|
|
965
|
+
ERRORS_SECTION,
|
|
966
|
+
BUGS_SECTION,
|
|
967
|
+
LOGGER_SECTION,
|
|
968
|
+
ISSUES_SECTION,
|
|
969
|
+
TESTS_SECTION,
|
|
970
|
+
FEATURES_SECTION
|
|
971
|
+
]);
|
|
972
|
+
function handConfigToLogger(config) {
|
|
973
|
+
setActiveLoggerSettings(loggerSettingsOf(config));
|
|
974
|
+
}
|
|
975
|
+
var CORE_HEAD = ["version", "store", "effortBusyTimeoutMs", "effortSync"];
|
|
976
|
+
var CORE_PLAN_TO_LOOP = [
|
|
977
|
+
"inject",
|
|
978
|
+
"planDir",
|
|
979
|
+
"specsDir",
|
|
980
|
+
"trackerDefault",
|
|
981
|
+
"trackerFallback",
|
|
982
|
+
"learningAdapter",
|
|
983
|
+
"learningBlessMinConfidence",
|
|
984
|
+
"learningPromoteAfter",
|
|
985
|
+
"learningPromoteMinConfidence",
|
|
986
|
+
"outputMode",
|
|
987
|
+
"prerequisitesRequired",
|
|
988
|
+
"prerequisitesOptional",
|
|
989
|
+
"trackingSpecs",
|
|
990
|
+
"trackingPlans",
|
|
991
|
+
"trackingAll",
|
|
992
|
+
"modules",
|
|
993
|
+
"allowList",
|
|
994
|
+
"settingSources",
|
|
995
|
+
"loopWorktreeDir"
|
|
996
|
+
];
|
|
997
|
+
var CORE_BOARD = [
|
|
998
|
+
"boardTrustedAuthors",
|
|
999
|
+
"boardRelationships",
|
|
1000
|
+
"boardProjectTemplate",
|
|
1001
|
+
"boardProjectNumber"
|
|
1002
|
+
];
|
|
1003
|
+
var CORE_CLAIMS = ["roadmapIssue", "claimsStaleAfter", "claimsAhead"];
|
|
1004
|
+
var CORE_CLEANUP = [
|
|
1005
|
+
"cleanupStaleDays",
|
|
1006
|
+
"cleanupWorktreeIdleDays",
|
|
1007
|
+
"cleanupKeep",
|
|
1008
|
+
"dangerousAcceptStaleRefs"
|
|
1009
|
+
];
|
|
1010
|
+
var CORE_TAIL = [
|
|
1011
|
+
"dangerousSelfUpdateDuringLoop",
|
|
1012
|
+
"statusNotice",
|
|
1013
|
+
"tiersRafa",
|
|
1014
|
+
"tiersSkills",
|
|
1015
|
+
"tiersAgents",
|
|
1016
|
+
"routing",
|
|
1017
|
+
"taskSkills",
|
|
1018
|
+
"taskLessons",
|
|
1019
|
+
"mergeDuplicates",
|
|
1020
|
+
"namingBranch"
|
|
1021
|
+
];
|
|
1022
|
+
function run(record, names) {
|
|
1023
|
+
return Object.fromEntries(names.map((name) => [name, record[name]]));
|
|
1024
|
+
}
|
|
1025
|
+
var CORE_SPECS = CORE_SECTION.settings;
|
|
1026
|
+
var CORE_VALUES = CORE_SECTION.defaults;
|
|
1027
|
+
var CONFIG_DEFAULTS = Object.freeze({
|
|
1028
|
+
...run(CORE_VALUES, CORE_HEAD),
|
|
1029
|
+
...HUB_DEFAULTS,
|
|
1030
|
+
...run(CORE_VALUES, CORE_PLAN_TO_LOOP),
|
|
1031
|
+
...LOOP_RETRIES_DEFAULTS,
|
|
1032
|
+
...LOOP_CONTINUE_DEFAULTS,
|
|
1033
|
+
...WRAP_UP_DEFAULTS,
|
|
1034
|
+
...PR_DEFAULTS,
|
|
1035
|
+
...run(CORE_VALUES, CORE_BOARD),
|
|
1036
|
+
...BOARD_PROJECT_LIMIT_DEFAULTS,
|
|
1037
|
+
...run(CORE_VALUES, CORE_CLAIMS),
|
|
1038
|
+
...TRIAGE_DEFAULTS,
|
|
1039
|
+
...RELEASE_DEFAULTS,
|
|
1040
|
+
...ERRORS_DEFAULTS,
|
|
1041
|
+
...BUGS_DEFAULTS,
|
|
1042
|
+
...LOGGER_DEFAULTS,
|
|
1043
|
+
...ISSUES_DEFAULTS,
|
|
1044
|
+
...run(CORE_VALUES, CORE_CLEANUP),
|
|
1045
|
+
...DANGEROUS_RELEASE_DEFAULTS,
|
|
1046
|
+
...run(CORE_VALUES, CORE_TAIL),
|
|
1047
|
+
...TESTS_DEFAULTS,
|
|
1048
|
+
...FEATURES_DEFAULTS
|
|
1049
|
+
});
|
|
1050
|
+
var SETTINGS = Object.freeze({
|
|
1051
|
+
...run(CORE_SPECS, CORE_HEAD),
|
|
1052
|
+
...HUB_SETTINGS,
|
|
1053
|
+
...run(CORE_SPECS, CORE_PLAN_TO_LOOP),
|
|
1054
|
+
...LOOP_RETRIES_SETTINGS,
|
|
1055
|
+
...LOOP_CONTINUE_SETTINGS,
|
|
1056
|
+
...WRAP_UP_SETTINGS,
|
|
1057
|
+
...PR_SETTINGS,
|
|
1058
|
+
...run(CORE_SPECS, CORE_BOARD),
|
|
1059
|
+
...BOARD_PROJECT_LIMIT_SETTINGS,
|
|
1060
|
+
...run(CORE_SPECS, CORE_CLAIMS),
|
|
1061
|
+
...TRIAGE_SETTINGS,
|
|
1062
|
+
...RELEASE_SETTINGS,
|
|
1063
|
+
...ERRORS_SETTINGS,
|
|
1064
|
+
...BUGS_SETTINGS,
|
|
1065
|
+
...LOGGER_SETTINGS,
|
|
1066
|
+
...ISSUES_SETTINGS,
|
|
1067
|
+
...run(CORE_SPECS, CORE_CLEANUP),
|
|
1068
|
+
...DANGEROUS_RELEASE_SETTINGS,
|
|
1069
|
+
...run(CORE_SPECS, CORE_TAIL),
|
|
1070
|
+
...TESTS_SETTINGS,
|
|
1071
|
+
...FEATURES_SETTINGS
|
|
1072
|
+
});
|
|
1073
|
+
var SETTING_NAMES = Object.freeze(Object.keys(SETTINGS));
|
|
1074
|
+
function inSettingOrder(sections, names) {
|
|
1075
|
+
const cuts = names.reduce((runs, name) => {
|
|
1076
|
+
const section = sections.find((candidate) => Object.hasOwn(candidate.settings, name));
|
|
1077
|
+
if (section === undefined)
|
|
1078
|
+
throw new Error(`rafa config registry: no section defines setting ${name}`);
|
|
1079
|
+
const last = runs.at(-1);
|
|
1080
|
+
return last?.section === section ? [...runs.slice(0, -1), { section, names: [...last.names, name] }] : [...runs, { section, names: [name] }];
|
|
1081
|
+
}, []);
|
|
1082
|
+
return cuts.map(({ section, names: run2 }, index) => ({
|
|
1083
|
+
package: section.package,
|
|
1084
|
+
settings: Object.fromEntries(run2.map((name) => [name, section.settings[name]])),
|
|
1085
|
+
defaults: Object.fromEntries(run2.map((name) => [name, section.defaults[name]])),
|
|
1086
|
+
checks: cuts.findIndex((cut) => cut.section === section) === index ? section.checks ?? [] : []
|
|
1087
|
+
}));
|
|
1088
|
+
}
|
|
1089
|
+
function holdsCoreSections() {
|
|
1090
|
+
const active = activeSettings();
|
|
1091
|
+
return SETTING_NAMES.every((name) => active[name] === SETTINGS[name]);
|
|
1092
|
+
}
|
|
1093
|
+
function registerCoreConfigSections() {
|
|
1094
|
+
if (holdsCoreSections())
|
|
1095
|
+
return;
|
|
1096
|
+
registerConfigSections(inSettingOrder(CONFIG_SECTIONS, SETTING_NAMES));
|
|
1097
|
+
setConfigLoadHook(handConfigToLogger);
|
|
1098
|
+
}
|
|
1099
|
+
var SETTING_BY_KEY = new Map(SETTING_NAMES.map((setting) => [
|
|
1100
|
+
SETTINGS[setting].key,
|
|
1101
|
+
setting
|
|
1102
|
+
]));
|
|
1103
|
+
function sectionsOf(key) {
|
|
1104
|
+
const parts = key.split(".");
|
|
1105
|
+
return parts.slice(1).map((_, index) => parts.slice(0, index + 1).join("."));
|
|
1106
|
+
}
|
|
1107
|
+
var SECTIONS = new Set([...SETTING_BY_KEY.keys()].flatMap(sectionsOf));
|
|
1108
|
+
var KNOWN_UNDER = (() => {
|
|
1109
|
+
const known = new Map;
|
|
1110
|
+
const add = (parent, name) => {
|
|
1111
|
+
const names = known.get(parent) ?? [];
|
|
1112
|
+
if (!names.includes(name))
|
|
1113
|
+
known.set(parent, [...names, name]);
|
|
1114
|
+
};
|
|
1115
|
+
for (const setting of SETTING_NAMES) {
|
|
1116
|
+
const { key, itemKeys } = SETTINGS[setting];
|
|
1117
|
+
const parts = key.split(".");
|
|
1118
|
+
parts.forEach((part, index) => add(parts.slice(0, index).join("."), part));
|
|
1119
|
+
for (const name of itemKeys ?? [])
|
|
1120
|
+
add(`${key}[]`, name);
|
|
1121
|
+
}
|
|
1122
|
+
return known;
|
|
1123
|
+
})();
|
|
1124
|
+
|
|
1125
|
+
export { DEFAULT_LOGGER_KIND, activeLoggerSettings, levelEnabled, hubContextOf, CODE_PATTERN, NEW_CONTEXT_LEAF, UNKNOWN_FAMILY, familyOf, codeProblem, isKnownCode, RAFA_CODES, ERRORS_DEFAULTS, FEATURES_SETTINGS, suggestedEnvironment, UNKNOWN_VALUE, MODULE_SHAPE, ACTION_SHAPE, renderTitle, titleRoundTrips, ISSUES_DEFAULTS, bugRulesOf, isLoopRetryCount, MERGE_METHODS, isMergeMethod, RELEASE_DEFAULTS, CONFIG_DEFAULTS, SETTINGS, SETTING_NAMES, registerCoreConfigSections };
|