@open-tomato/rafa 0.33.0 → 0.34.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 +25 -0
- package/dist/bundled/operators/agents/rafa-stretch-engineer.md +10 -5
- package/dist/bundled/operators/skills/rafa-stretch-pit-stop/SKILL.md +8 -2
- package/dist/bundled/skills/dev-planner/SKILL.md +3 -3
- package/dist/bundled/skills/git-workflow/SKILL.md +1 -1
- package/dist/cli.js +1415 -600
- package/dist/effort/store/index.js +2 -2
- package/dist/{index-w3vyb08t.js → index-4b3m7s0z.js} +688 -197
- package/dist/{index-13caphhp.js → index-b8t7q5hc.js} +220 -22
- package/dist/{index-kz7e4gtt.js → index-bvfbfa63.js} +112 -58
- package/dist/{index-zn08ywsv.js → index-v8d7c6sw.js} +1 -1
- package/dist/{index-dv0ycmp8.js → index-vp0xghk2.js} +40 -0
- package/dist/index.js +4 -4
- package/dist/plan/index.js +2 -2
- package/package.json +1 -1
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
trackerPathFor,
|
|
14
14
|
updateTrackerLine,
|
|
15
15
|
writeTrackerBlocker
|
|
16
|
-
} from "./index-
|
|
16
|
+
} from "./index-v8d7c6sw.js";
|
|
17
17
|
import {
|
|
18
18
|
ACROSS_STORES_ORDER,
|
|
19
19
|
CORE_ADAPTER_REGISTRY,
|
|
@@ -127,7 +127,7 @@ import {
|
|
|
127
127
|
writeNames,
|
|
128
128
|
writePositionFile,
|
|
129
129
|
writeSqliteStore
|
|
130
|
-
} from "./index-
|
|
130
|
+
} from "./index-bvfbfa63.js";
|
|
131
131
|
import {
|
|
132
132
|
CHANGE_LEVELS,
|
|
133
133
|
CONFIG_DEFAULTS,
|
|
@@ -155,7 +155,7 @@ import {
|
|
|
155
155
|
requiredPrerequisite,
|
|
156
156
|
resolveTiers,
|
|
157
157
|
stampPrompt
|
|
158
|
-
} from "./index-
|
|
158
|
+
} from "./index-vp0xghk2.js";
|
|
159
159
|
import {
|
|
160
160
|
promotable
|
|
161
161
|
} from "./index-d6d0942q.js";
|
|
@@ -8183,6 +8183,11 @@ function createGhPullRequests(options) {
|
|
|
8183
8183
|
const text = textArgument(title, "editTitle", "title", false);
|
|
8184
8184
|
await succeed(["pr", "edit", target, "--title", text], `gh pr edit ${target} --title <title>`);
|
|
8185
8185
|
},
|
|
8186
|
+
editBase: async (number, base) => {
|
|
8187
|
+
const target = pullNumber(number, "editBase");
|
|
8188
|
+
const branch = textArgument(base, "editBase", "base", false);
|
|
8189
|
+
await succeed(["pr", "edit", target, "--base", branch], `gh pr edit ${target} --base ${branch}`);
|
|
8190
|
+
},
|
|
8186
8191
|
editBody: async (number, body) => {
|
|
8187
8192
|
const target = pullNumber(number, "editBody");
|
|
8188
8193
|
const text = bodyText(body, "editBody");
|
|
@@ -14329,7 +14334,7 @@ function withOutlineCache(outline, root) {
|
|
|
14329
14334
|
import path2 from "path";
|
|
14330
14335
|
async function coreRoster() {
|
|
14331
14336
|
const [{ CORE_REGISTRY }, { describeRegistry }] = await Promise.all([
|
|
14332
|
-
import("./index-
|
|
14337
|
+
import("./index-b8t7q5hc.js"),
|
|
14333
14338
|
import("./describe-5hqfwbjc.js")
|
|
14334
14339
|
]);
|
|
14335
14340
|
return describeRegistry(CORE_REGISTRY, version);
|
|
@@ -20569,6 +20574,47 @@ function hasBranch(refs, stub) {
|
|
|
20569
20574
|
const branch = `${BRANCH_PREFIX2}${stub}`;
|
|
20570
20575
|
return refs.some((ref7) => ref7 === branch || ref7.endsWith(`/${branch}`));
|
|
20571
20576
|
}
|
|
20577
|
+
function readBranchTips(sources, remote, stub, note) {
|
|
20578
|
+
const branch = `${BRANCH_PREFIX2}${stub}`;
|
|
20579
|
+
const tips = [];
|
|
20580
|
+
for (const ref7 of [`refs/heads/${branch}`, `refs/remotes/${remote}/${branch}`]) {
|
|
20581
|
+
const resolved = sources.git(["rev-parse", "--verify", "--quiet", `${ref7}^{commit}`]);
|
|
20582
|
+
const said = gitSaid(resolved);
|
|
20583
|
+
if (resolved.ok && resolved.stdout.trim() !== "") {
|
|
20584
|
+
tips.push(ref7);
|
|
20585
|
+
} else if (said !== "") {
|
|
20586
|
+
note(`\`${ref7}\` could not be read, so its plan reads as started: ${said}`);
|
|
20587
|
+
return null;
|
|
20588
|
+
}
|
|
20589
|
+
}
|
|
20590
|
+
return tips;
|
|
20591
|
+
}
|
|
20592
|
+
function readBranchMessages(sources, ref7, note) {
|
|
20593
|
+
const result = sources.git(["log", "-z", "--format=%B", `${sources.base}..${ref7}`]);
|
|
20594
|
+
if (!result.ok) {
|
|
20595
|
+
note(`the commits of \`${ref7}\` past \`${sources.base}\` could not be read, so its plan reads as started: ${gitSaid(result)}`);
|
|
20596
|
+
return null;
|
|
20597
|
+
}
|
|
20598
|
+
return result.stdout.split("\x00").map((message) => message.trim()).filter((message) => message !== "");
|
|
20599
|
+
}
|
|
20600
|
+
function claimsOnly(messages) {
|
|
20601
|
+
return messages.length > 0 && messages.every((message) => parseClaimMessage(message).kind === "ownership");
|
|
20602
|
+
}
|
|
20603
|
+
function hasStartedBranch(sources, remote, refs, stub, note) {
|
|
20604
|
+
if (!hasBranch(refs, stub))
|
|
20605
|
+
return false;
|
|
20606
|
+
const tips = readBranchTips(sources, remote, stub, note);
|
|
20607
|
+
if (tips === null)
|
|
20608
|
+
return true;
|
|
20609
|
+
if (tips.length === 0) {
|
|
20610
|
+
note(`\`${BRANCH_PREFIX2}${stub}\` is on ${remote} but not fetched here, so its commits were not read and its plan reads as started`);
|
|
20611
|
+
return true;
|
|
20612
|
+
}
|
|
20613
|
+
return tips.some((ref7) => {
|
|
20614
|
+
const messages = readBranchMessages(sources, ref7, note);
|
|
20615
|
+
return messages === null || !claimsOnly(messages);
|
|
20616
|
+
});
|
|
20617
|
+
}
|
|
20572
20618
|
function openWorld(sources) {
|
|
20573
20619
|
let problems = [];
|
|
20574
20620
|
const note = (problem) => {
|
|
@@ -20593,7 +20639,7 @@ function openWorld(sources) {
|
|
|
20593
20639
|
tracked: once2(() => readTracked(sources, note)),
|
|
20594
20640
|
checkout: once2(() => readCheckout(sources, note)),
|
|
20595
20641
|
branchPlan: once2(() => readBranchPlan(branch(), plans())),
|
|
20596
|
-
unstartedPlan: once2(() => plans().find((plan) => !hasRun(runs(), plan.stub) && !
|
|
20642
|
+
unstartedPlan: once2(() => plans().find((plan) => !hasRun(runs(), plan.stub) && !hasStartedBranch(sources, remote, refs(), plan.stub, note)) ?? null),
|
|
20597
20643
|
openPull: once2(() => readOpenPull(sources, branch(), note)),
|
|
20598
20644
|
roadmap,
|
|
20599
20645
|
picked: once2(async () => {
|
|
@@ -21674,7 +21720,7 @@ var ready_default = createIssueReadyCommand();
|
|
|
21674
21720
|
|
|
21675
21721
|
// src/start.ts
|
|
21676
21722
|
import fs from "fs";
|
|
21677
|
-
import { homedir as
|
|
21723
|
+
import { homedir as homedir9 } from "os";
|
|
21678
21724
|
import path4 from "path";
|
|
21679
21725
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
21680
21726
|
|
|
@@ -23761,6 +23807,26 @@ async function handOut(handout, task, resolution, repoRoot) {
|
|
|
23761
23807
|
return { resolver: handout.resolver, skills, lessons };
|
|
23762
23808
|
}
|
|
23763
23809
|
|
|
23810
|
+
// src/start/inherited-notice.ts
|
|
23811
|
+
var INHERITED_HEADING = "## Failures this run inherited";
|
|
23812
|
+
var INHERITED_SENTENCE = "These tests were already failing when this run started. " + "They need no proof that they predate your task: do not run `git stash` or check out a clean worktree of `main` to show it. " + "A bug you report for one of them, by its file and case, is recognised as inherited and files nothing.";
|
|
23813
|
+
var INHERITED_LIST_CAP = 20;
|
|
23814
|
+
function oneLine7(text) {
|
|
23815
|
+
return text.replace(/\s+/g, " ").trim();
|
|
23816
|
+
}
|
|
23817
|
+
function failureLine(failure3) {
|
|
23818
|
+
return `- \`${oneLine7(failure3.file)}\`: ${oneLine7(failure3.name)}`;
|
|
23819
|
+
}
|
|
23820
|
+
function renderInheritedSection(failures) {
|
|
23821
|
+
if (failures.length === 0)
|
|
23822
|
+
return "";
|
|
23823
|
+
const listed = failures.slice(0, INHERITED_LIST_CAP).map(failureLine);
|
|
23824
|
+
const rest = failures.length - listed.length;
|
|
23825
|
+
const more = rest > 0 ? [`- ...and ${rest} more.`] : [];
|
|
23826
|
+
return [INHERITED_HEADING, INHERITED_SENTENCE, ...listed, ...more].join(`
|
|
23827
|
+
`);
|
|
23828
|
+
}
|
|
23829
|
+
|
|
23764
23830
|
// src/start/preflight.ts
|
|
23765
23831
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
23766
23832
|
import { existsSync as existsSync27, readFileSync as readFileSync33 } from "fs";
|
|
@@ -24584,16 +24650,16 @@ function baseLines(base) {
|
|
|
24584
24650
|
}
|
|
24585
24651
|
var NO_TASK_SECTIONS = { skills: "", lessons: "" };
|
|
24586
24652
|
function sectionLines(sections2) {
|
|
24587
|
-
return [sections2.skills, sections2.lessons].filter((section) => section.trim().length > 0).flatMap((section) => [section, ""]);
|
|
24653
|
+
return [sections2.skills, sections2.lessons, sections2.inherited].filter((section) => section.trim().length > 0).flatMap((section) => [section, ""]);
|
|
24588
24654
|
}
|
|
24589
|
-
function buildTaskPrompt(taskText, promptContent, planText, knownMissing = [], blocker = null, sections2 = NO_TASK_SECTIONS, base = null) {
|
|
24655
|
+
function buildTaskPrompt(taskText, promptContent, planText, knownMissing = [], blocker = null, sections2 = NO_TASK_SECTIONS, base = null, inherited = []) {
|
|
24590
24656
|
return [
|
|
24591
24657
|
`Your scoped task is: ${taskText}`,
|
|
24592
24658
|
"Consider tasks listed above this one in the plan checklist as completed. Do not re-evaluate or re-do them. Focus only on the scoped task.",
|
|
24593
24659
|
...blockerLines(blocker),
|
|
24594
24660
|
...baseLines(base),
|
|
24595
24661
|
"",
|
|
24596
|
-
...sectionLines(sections2),
|
|
24662
|
+
...sectionLines({ ...sections2, inherited: renderInheritedSection(inherited) }),
|
|
24597
24663
|
promptContent,
|
|
24598
24664
|
planText,
|
|
24599
24665
|
...knownMissingNotice(knownMissing)
|
|
@@ -24635,7 +24701,7 @@ async function dispatchTask(options) {
|
|
|
24635
24701
|
const resolution = options.serving === null ? EMPTY_RESOLUTION : resolveSessionTiers(options.serving);
|
|
24636
24702
|
const task = taskInputFor(taskInfo, taskText, declaration, options.planContent);
|
|
24637
24703
|
const handed = await handOut(options.handout, task, resolution, options.repoRoot);
|
|
24638
|
-
const prompt = withStamp(buildTaskPrompt(taskText, options.promptContent, injection.text, options.knownMissing, taskInfo.blocker ?? null, { skills: renderSkillsSection(handed.skills), lessons: renderLessonsSection(handed.lessons) }, options.base));
|
|
24704
|
+
const prompt = withStamp(buildTaskPrompt(taskText, options.promptContent, injection.text, options.knownMissing, taskInfo.blocker ?? null, { skills: renderSkillsSection(handed.skills), lessons: renderLessonsSection(handed.lessons) }, options.base, options.inherited));
|
|
24639
24705
|
const served = serveForSession(options.serving, resolution);
|
|
24640
24706
|
const sessionId = (options.newSessionId ?? randomUUID8)();
|
|
24641
24707
|
const session = await run(prompt, flags, sessionId, options.settingSources, served, options.checkout);
|
|
@@ -24770,6 +24836,8 @@ function summaryOf3(event) {
|
|
|
24770
24836
|
return `${padKind("no pr")}${oneLine(event.reason)}`;
|
|
24771
24837
|
case "halt":
|
|
24772
24838
|
return `${padKind("halt")}${oneLine(event.reason)}`;
|
|
24839
|
+
case "inherited":
|
|
24840
|
+
return `${padKind("inherited")}${oneLine(`${event.file} > ${event.name}`)}`;
|
|
24773
24841
|
}
|
|
24774
24842
|
}
|
|
24775
24843
|
function emitLoopEvent(event, now = () => new Date) {
|
|
@@ -26276,6 +26344,9 @@ function baselinePathFor(trackerPath) {
|
|
|
26276
26344
|
}
|
|
26277
26345
|
return join32(dirname11(trackerPath), `${BASELINE_FILE_PREFIX}${match[1] ?? ""}.json`);
|
|
26278
26346
|
}
|
|
26347
|
+
function copyFailure(failure3) {
|
|
26348
|
+
return failure3.message === undefined ? { file: failure3.file, name: failure3.name } : { file: failure3.file, name: failure3.name, message: failure3.message };
|
|
26349
|
+
}
|
|
26279
26350
|
function baselineOf(result, recordedAt, commit) {
|
|
26280
26351
|
return {
|
|
26281
26352
|
version: BASELINE_VERSION,
|
|
@@ -26284,7 +26355,7 @@ function baselineOf(result, recordedAt, commit) {
|
|
|
26284
26355
|
command: [...result.command],
|
|
26285
26356
|
exitCode: result.exitCode,
|
|
26286
26357
|
summary: result.summary,
|
|
26287
|
-
failures: result.failures.map(
|
|
26358
|
+
failures: result.failures.map(copyFailure),
|
|
26288
26359
|
errors: result.errors,
|
|
26289
26360
|
junit: result.junit
|
|
26290
26361
|
};
|
|
@@ -26303,7 +26374,8 @@ function isFailure(value) {
|
|
|
26303
26374
|
if (typeof value !== "object" || value === null)
|
|
26304
26375
|
return false;
|
|
26305
26376
|
const record = value;
|
|
26306
|
-
|
|
26377
|
+
const message = record["message"];
|
|
26378
|
+
return typeof record["file"] === "string" && typeof record["name"] === "string" && (message === undefined || typeof message === "string");
|
|
26307
26379
|
}
|
|
26308
26380
|
function badField(record) {
|
|
26309
26381
|
const checks = [
|
|
@@ -26503,8 +26575,18 @@ function closeCase(walk) {
|
|
|
26503
26575
|
if (open === null || !open.failed)
|
|
26504
26576
|
return;
|
|
26505
26577
|
const held = walk.failures.some((failure3) => failure3.file === open.file && failure3.name === open.name);
|
|
26506
|
-
if (
|
|
26507
|
-
|
|
26578
|
+
if (held)
|
|
26579
|
+
return;
|
|
26580
|
+
walk.failures.push(open.message === undefined ? { file: open.file, name: open.name } : { file: open.file, name: open.name, message: open.message });
|
|
26581
|
+
}
|
|
26582
|
+
function firstMessageLine(message) {
|
|
26583
|
+
const line = message?.split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
26584
|
+
return line === "" ? undefined : line;
|
|
26585
|
+
}
|
|
26586
|
+
function failCase(open, attributes) {
|
|
26587
|
+
open.failed = true;
|
|
26588
|
+
if (open.message === undefined)
|
|
26589
|
+
open.message = firstMessageLine(attributes["message"]);
|
|
26508
26590
|
}
|
|
26509
26591
|
function openCase(walk, attributes) {
|
|
26510
26592
|
const [fileSuite, ...describes] = walk.suites;
|
|
@@ -26531,7 +26613,7 @@ function takeTag(walk, match) {
|
|
|
26531
26613
|
return;
|
|
26532
26614
|
}
|
|
26533
26615
|
if ((element === "failure" || element === "error") && closing !== "/" && walk.open !== null)
|
|
26534
|
-
walk.open
|
|
26616
|
+
failCase(walk.open, attributes);
|
|
26535
26617
|
}
|
|
26536
26618
|
function parseJunitFailures(xml) {
|
|
26537
26619
|
if (!/<testsuites\b/.test(xml) || !xml.includes("</testsuites>"))
|
|
@@ -27108,9 +27190,266 @@ function createRunSuiteSteps(options) {
|
|
|
27108
27190
|
return { beforeSession, afterTask };
|
|
27109
27191
|
}
|
|
27110
27192
|
|
|
27193
|
+
// src/start/triage.ts
|
|
27194
|
+
import { homedir as homedir8 } from "os";
|
|
27195
|
+
|
|
27196
|
+
// src/triage/bug-key.ts
|
|
27197
|
+
import { basename as basename11 } from "path";
|
|
27198
|
+
|
|
27199
|
+
// src/triage/test-failure.ts
|
|
27200
|
+
var TEST_FILE = "(?:/?(?:[\\w.@+-]+/)*)[\\w.@+-]+\\.(?:test|spec)\\.[cm]?[jt]sx?";
|
|
27201
|
+
var TEST_FILE_ANYWHERE = new RegExp(`(?<![\\w.@+/-])${TEST_FILE}(?![\\w])`, "g");
|
|
27202
|
+
var FAIL_LINE = /^\s*\(fail\)\s+(.+?)(?:\s+\[\d+(?:\.\d+)?m?s\])?\s*$/;
|
|
27203
|
+
var FILE_CASE_LINE = new RegExp(`^\\s*(${TEST_FILE})\\s+>\\s+(.+?)\\s*$`);
|
|
27204
|
+
var FILE_HEADER = new RegExp(`^\\s*(${TEST_FILE}):\\s*$`);
|
|
27205
|
+
var NOISE_LINES = [
|
|
27206
|
+
/^\s*$/,
|
|
27207
|
+
FILE_HEADER,
|
|
27208
|
+
/^\s*\d+\s+\|/,
|
|
27209
|
+
/^\s*\^+\s*$/,
|
|
27210
|
+
/^\s*at\s/,
|
|
27211
|
+
/^\s*bun test v/
|
|
27212
|
+
];
|
|
27213
|
+
var ERROR_PREFIX = /^error:\s+/;
|
|
27214
|
+
function caseLineOf(line, index) {
|
|
27215
|
+
const fail = FAIL_LINE.exec(line);
|
|
27216
|
+
if (fail !== null)
|
|
27217
|
+
return { index, name: fail[1], file: null };
|
|
27218
|
+
const fileCase = FILE_CASE_LINE.exec(line);
|
|
27219
|
+
return fileCase === null ? null : { index, name: fileCase[2], file: fileCase[1] };
|
|
27220
|
+
}
|
|
27221
|
+
function linesOf2(text) {
|
|
27222
|
+
return text.split(/\r?\n/);
|
|
27223
|
+
}
|
|
27224
|
+
function caseLinesOf(lines) {
|
|
27225
|
+
return lines.map((line, index) => caseLineOf(line, index)).filter((found) => found !== null);
|
|
27226
|
+
}
|
|
27227
|
+
function testFilesIn(text) {
|
|
27228
|
+
return text.match(TEST_FILE_ANYWHERE) ?? [];
|
|
27229
|
+
}
|
|
27230
|
+
function firstEvidence(lines) {
|
|
27231
|
+
const found = lines.find((line) => caseLineOf(line, 0) === null && !NOISE_LINES.some((noise) => noise.test(line)));
|
|
27232
|
+
return found === undefined ? null : found.trim().replace(ERROR_PREFIX, "");
|
|
27233
|
+
}
|
|
27234
|
+
function testFileOf(found, artifactLines, what) {
|
|
27235
|
+
if (found.file !== null)
|
|
27236
|
+
return found.file;
|
|
27237
|
+
const above = artifactLines.slice(0, found.index);
|
|
27238
|
+
const header = above.map((line) => FILE_HEADER.exec(line)?.[1]).filter((file) => file !== undefined).at(-1);
|
|
27239
|
+
const before = testFilesIn(above.join(`
|
|
27240
|
+
`));
|
|
27241
|
+
const after = testFilesIn(artifactLines.slice(found.index).join(`
|
|
27242
|
+
`));
|
|
27243
|
+
return header ?? before.at(-1) ?? after[0] ?? testFilesIn(what)[0] ?? null;
|
|
27244
|
+
}
|
|
27245
|
+
function evidenceOf(found, artifactLines) {
|
|
27246
|
+
if (found === null)
|
|
27247
|
+
return firstEvidence(artifactLines);
|
|
27248
|
+
const cases = caseLinesOf(artifactLines);
|
|
27249
|
+
const previous = cases.filter((other) => other.index < found.index).at(-1);
|
|
27250
|
+
const next = cases.find((other) => other.index > found.index);
|
|
27251
|
+
const before = artifactLines.slice(previous === undefined ? 0 : previous.index + 1, found.index);
|
|
27252
|
+
const after = artifactLines.slice(found.index + 1, next === undefined ? artifactLines.length : next.index);
|
|
27253
|
+
return firstEvidence(before) ?? firstEvidence(after);
|
|
27254
|
+
}
|
|
27255
|
+
function testFailureOf(bug) {
|
|
27256
|
+
const artifactLines = linesOf2(bug.artifact ?? "");
|
|
27257
|
+
const what = bug.what ?? "";
|
|
27258
|
+
const inArtifact = caseLinesOf(artifactLines)[0];
|
|
27259
|
+
if (inArtifact !== undefined) {
|
|
27260
|
+
return {
|
|
27261
|
+
file: testFileOf(inArtifact, artifactLines, what),
|
|
27262
|
+
name: inArtifact.name,
|
|
27263
|
+
evidence: evidenceOf(inArtifact, artifactLines)
|
|
27264
|
+
};
|
|
27265
|
+
}
|
|
27266
|
+
const inWhat = caseLinesOf(linesOf2(what))[0];
|
|
27267
|
+
if (inWhat === undefined)
|
|
27268
|
+
return null;
|
|
27269
|
+
return {
|
|
27270
|
+
file: inWhat.file ?? testFilesIn(bug.artifact ?? "")[0] ?? testFilesIn(what)[0] ?? null,
|
|
27271
|
+
name: inWhat.name,
|
|
27272
|
+
evidence: evidenceOf(null, artifactLines)
|
|
27273
|
+
};
|
|
27274
|
+
}
|
|
27275
|
+
|
|
27276
|
+
// src/triage/bug-key.ts
|
|
27277
|
+
var KEY_SEPARATOR = ": ";
|
|
27278
|
+
var CASE_SEPARATOR = " > ";
|
|
27279
|
+
function hasText2(value) {
|
|
27280
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
27281
|
+
}
|
|
27282
|
+
function artifactOf(bug) {
|
|
27283
|
+
return hasText2(bug.artifact) && textProblem(bug.artifact) === null ? bug.artifact : null;
|
|
27284
|
+
}
|
|
27285
|
+
function oneLine8(text) {
|
|
27286
|
+
return text.replace(/\s+/g, " ").trim();
|
|
27287
|
+
}
|
|
27288
|
+
var COMMIT_HASH = /\b[0-9a-f]{7,40}\b/gi;
|
|
27289
|
+
var FOLDER_PREFIX = /[^\s'"`()[\]{}<>,;|]*\//g;
|
|
27290
|
+
var NUMBER = /\d+/g;
|
|
27291
|
+
function strippedText(text) {
|
|
27292
|
+
const taken = text.replace(COMMIT_HASH, "").replace(FOLDER_PREFIX, "").replace(NUMBER, "");
|
|
27293
|
+
return oneLine8(taken);
|
|
27294
|
+
}
|
|
27295
|
+
function keyText(text) {
|
|
27296
|
+
const stripped = strippedText(text);
|
|
27297
|
+
return stripped.length > 0 ? stripped : oneLine8(text);
|
|
27298
|
+
}
|
|
27299
|
+
function testFailureKeyOf(failure3) {
|
|
27300
|
+
const test = failure3.file === null ? oneLine8(failure3.name) : `${basename11(failure3.file)}${CASE_SEPARATOR}${oneLine8(failure3.name)}`;
|
|
27301
|
+
return failure3.evidence === null ? test : `${test}${KEY_SEPARATOR}${keyText(failure3.evidence)}`;
|
|
27302
|
+
}
|
|
27303
|
+
function bugKeyOf(trackerPath, artifact, what = null) {
|
|
27304
|
+
const failure3 = testFailureOf({ what, artifact });
|
|
27305
|
+
return failure3 === null ? `${basename11(trackerPath)}${KEY_SEPARATOR}${keyText(artifact)}` : testFailureKeyOf(failure3);
|
|
27306
|
+
}
|
|
27307
|
+
function legacyBugKeyOf(trackerPath, artifact) {
|
|
27308
|
+
return `${basename11(trackerPath)}${KEY_SEPARATOR}${oneLine8(artifact)}`;
|
|
27309
|
+
}
|
|
27310
|
+
|
|
27311
|
+
// src/triage/inherited.ts
|
|
27312
|
+
import { basename as basename12 } from "path";
|
|
27313
|
+
var CLOSED_ISSUE_STATES = ["done", "released", "cancelled"];
|
|
27314
|
+
function isOpenIssueState(state) {
|
|
27315
|
+
return !CLOSED_ISSUE_STATES.includes(state);
|
|
27316
|
+
}
|
|
27317
|
+
function sameFailure(failure3, baseline) {
|
|
27318
|
+
const { file, evidence } = failure3;
|
|
27319
|
+
if (file === null)
|
|
27320
|
+
return false;
|
|
27321
|
+
const sameTest = basename12(file) === basename12(baseline.file) && oneLine8(failure3.name) === oneLine8(baseline.name);
|
|
27322
|
+
const message = baseline.message ?? null;
|
|
27323
|
+
if (!sameTest || !hasText2(message))
|
|
27324
|
+
return sameTest;
|
|
27325
|
+
return evidence !== null && keyText(evidence).includes(keyText(message));
|
|
27326
|
+
}
|
|
27327
|
+
function inheritedFailureOf(bug, failures) {
|
|
27328
|
+
const failure3 = testFailureOf(bug);
|
|
27329
|
+
if (failure3 === null)
|
|
27330
|
+
return null;
|
|
27331
|
+
return failures.find((baseline) => sameFailure(failure3, baseline)) ?? null;
|
|
27332
|
+
}
|
|
27333
|
+
|
|
27334
|
+
// src/triage/issue-text.ts
|
|
27335
|
+
var TITLE_MAX_LENGTH = 120;
|
|
27336
|
+
var TITLE_CUT = "...";
|
|
27337
|
+
var MIN_FENCE_LENGTH = 3;
|
|
27338
|
+
var ISSUE_OPENING = "An out-of-scope bug a rafa task session reported. The loop filed it and" + " dispatches no task for it: a plan that wants it fixed declares a task.";
|
|
27339
|
+
var COMMENT_OPENING = "Reported again by a rafa task session.";
|
|
27340
|
+
function fenced(value) {
|
|
27341
|
+
const runs = Array.from(value.matchAll(/`+/g), (run) => run[0].length);
|
|
27342
|
+
const fence = "`".repeat(Math.max(MIN_FENCE_LENGTH, ...runs.map((length) => length + 1)));
|
|
27343
|
+
const body = value.endsWith(`
|
|
27344
|
+
`) ? value : `${value}
|
|
27345
|
+
`;
|
|
27346
|
+
return `${fence}
|
|
27347
|
+
${body}${fence}`;
|
|
27348
|
+
}
|
|
27349
|
+
function issueTitle2(redactedWhat) {
|
|
27350
|
+
const line = oneLine8(redactedWhat);
|
|
27351
|
+
const points = Array.from(line);
|
|
27352
|
+
if (points.length <= TITLE_MAX_LENGTH)
|
|
27353
|
+
return line;
|
|
27354
|
+
const kept = points.slice(0, TITLE_MAX_LENGTH - TITLE_CUT.length).join("");
|
|
27355
|
+
return `${kept.trimEnd()}${TITLE_CUT}`;
|
|
27356
|
+
}
|
|
27357
|
+
function scoreText(score) {
|
|
27358
|
+
return score.toFixed(2);
|
|
27359
|
+
}
|
|
27360
|
+
function similarCommentOpening(score, threshold) {
|
|
27361
|
+
return `${COMMENT_OPENING} No key found this issue: the report's words match its first report` + ` at a Jaccard similarity of ${scoreText(score)}, at or above the threshold of` + ` ${String(threshold)}, so it is taken for the same bug.`;
|
|
27362
|
+
}
|
|
27363
|
+
function possibleDuplicatesSection(duplicates2, redact) {
|
|
27364
|
+
const intro = `No open bug scored at or above the similarity threshold of ${String(duplicates2.threshold)}.`;
|
|
27365
|
+
const listed = duplicates2.nearest.length === 0 ? "No open bug shares a word with this one." : duplicates2.nearest.map(({ issue: issue3, score }) => `- ${issueNameOf(issue3.ref)} (score ${scoreText(score)})`).join(`
|
|
27366
|
+
`);
|
|
27367
|
+
return `## Possible duplicates
|
|
27368
|
+
|
|
27369
|
+
${redact(`${intro}
|
|
27370
|
+
|
|
27371
|
+
${listed}`)}`;
|
|
27372
|
+
}
|
|
27373
|
+
function issueNameOf(ref8) {
|
|
27374
|
+
return ref8.url ?? `${ref8.kind} issue ${ref8.externalId}`;
|
|
27375
|
+
}
|
|
27376
|
+
function supersedesSection(closed, redact) {
|
|
27377
|
+
const sentence = `This bug came back after ${issueNameOf(closed)} was closed as completed;` + " this issue is filed in its place.";
|
|
27378
|
+
return `## Supersedes
|
|
27379
|
+
|
|
27380
|
+
${redact(sentence)}`;
|
|
27381
|
+
}
|
|
27382
|
+
function section(heading, value, absent2, redact) {
|
|
27383
|
+
const shown = value === null ? absent2 : fenced(redact(value));
|
|
27384
|
+
return `## ${heading}
|
|
27385
|
+
|
|
27386
|
+
${shown}`;
|
|
27387
|
+
}
|
|
27388
|
+
function issueText(opening, values, redact) {
|
|
27389
|
+
return [
|
|
27390
|
+
opening,
|
|
27391
|
+
...values.supersedes === undefined ? [] : [supersedesSection(values.supersedes, redact)],
|
|
27392
|
+
section("What", values.what, "", redact),
|
|
27393
|
+
section("Artifact", values.artifact, "The report gave no artifact, so a recurrence files again.", redact),
|
|
27394
|
+
...values.refs === null ? [] : [values.refs],
|
|
27395
|
+
section("Recurrence key", values.key, "The report gave no artifact, so this bug has no key.", redact),
|
|
27396
|
+
section("Plan", values.planStub, "The dispatch resolved no plan stub.", redact),
|
|
27397
|
+
section("Task", values.taskText, "", redact),
|
|
27398
|
+
section("Feedback", values.feedback, "The report gave no feedback.", redact),
|
|
27399
|
+
...values.duplicates === undefined ? [] : [possibleDuplicatesSection(values.duplicates, redact)]
|
|
27400
|
+
].join(`
|
|
27401
|
+
|
|
27402
|
+
`) + `
|
|
27403
|
+
`;
|
|
27404
|
+
}
|
|
27405
|
+
|
|
27406
|
+
// src/triage/local-paths.ts
|
|
27407
|
+
import { realpathSync as realpathSync5 } from "fs";
|
|
27408
|
+
import { resolve as resolve20 } from "path";
|
|
27409
|
+
var HOME_MARKER = "[redacted: HOME]";
|
|
27410
|
+
var SEGMENT = "[^/\\s'\"`()<>:,;]+";
|
|
27411
|
+
var HOME_PATTERN = `(?:/${SEGMENT})*?/(?:Users|home)/${SEGMENT}`;
|
|
27412
|
+
var PATH_START = "(?:(?<![\\w.\\-])|(?<=(?:^|\\s)-[A-Za-z]))";
|
|
27413
|
+
var UNDER = "(/)(?=[^\\s'\"`()<>])";
|
|
27414
|
+
var PATH_END = "(?![\\w\\-]|\\.[\\w.\\-/])";
|
|
27415
|
+
function literalPattern(text) {
|
|
27416
|
+
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
27417
|
+
}
|
|
27418
|
+
function forms(path3) {
|
|
27419
|
+
const given = resolve20(path3);
|
|
27420
|
+
try {
|
|
27421
|
+
const real = realpathSync5(given);
|
|
27422
|
+
return real === given ? [given] : [given, real];
|
|
27423
|
+
} catch {
|
|
27424
|
+
return [given];
|
|
27425
|
+
}
|
|
27426
|
+
}
|
|
27427
|
+
function isRoot(path3) {
|
|
27428
|
+
return path3.length > 1;
|
|
27429
|
+
}
|
|
27430
|
+
function localPathRedactor(repoRoot, home) {
|
|
27431
|
+
const asHome = (pattern) => ({ pattern, under: `${HOME_MARKER}/`, bare: HOME_MARKER });
|
|
27432
|
+
const asRepo = (pattern) => ({ pattern, under: "", bare: "." });
|
|
27433
|
+
const literals = [
|
|
27434
|
+
...forms(repoRoot).filter(isRoot).map((root) => asRepo(literalPattern(root))),
|
|
27435
|
+
...forms(home).filter(isRoot).map((root) => asHome(literalPattern(root)))
|
|
27436
|
+
];
|
|
27437
|
+
const roots = [
|
|
27438
|
+
...[...literals].sort((a, b) => b.pattern.length - a.pattern.length),
|
|
27439
|
+
asHome(HOME_PATTERN)
|
|
27440
|
+
];
|
|
27441
|
+
const alternatives = roots.map(({ pattern }) => `(${pattern})(?:${UNDER}|${PATH_END})`);
|
|
27442
|
+
const matcher = new RegExp(`${PATH_START}(?:${alternatives.join("|")})`, "g");
|
|
27443
|
+
return (text) => text.replace(matcher, (...groups) => {
|
|
27444
|
+
const index = roots.findIndex((_, at) => groups[1 + at * 2] !== undefined);
|
|
27445
|
+
const root = roots[index];
|
|
27446
|
+
return groups[2 + index * 2] === undefined ? root.bare : root.under;
|
|
27447
|
+
});
|
|
27448
|
+
}
|
|
27449
|
+
|
|
27111
27450
|
// src/triage/triage.ts
|
|
27112
27451
|
import { homedir as homedir7 } from "os";
|
|
27113
|
-
import {
|
|
27452
|
+
import { join as join35 } from "path";
|
|
27114
27453
|
|
|
27115
27454
|
// src/effort/store/tracker-refs.ts
|
|
27116
27455
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
@@ -27129,10 +27468,11 @@ var INSERT_REF = `
|
|
|
27129
27468
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ${stampedValues("findings")})
|
|
27130
27469
|
`;
|
|
27131
27470
|
var ATTACH_REF = "UPDATE findings SET tracker_ref = ? WHERE seq = ? AND tracker_ref IS NULL";
|
|
27132
|
-
var
|
|
27471
|
+
var NEWEST_FIRST = ACROSS_STORES_ORDER.split(",").map((term) => `${term.trim()} DESC`).join(", ");
|
|
27472
|
+
var SELECT_NEWEST = `
|
|
27133
27473
|
SELECT seq, tracker_ref FROM findings
|
|
27134
27474
|
WHERE artifact = ? AND tracker_ref IS NOT NULL
|
|
27135
|
-
ORDER BY
|
|
27475
|
+
ORDER BY ${NEWEST_FIRST}
|
|
27136
27476
|
LIMIT 1
|
|
27137
27477
|
`;
|
|
27138
27478
|
var REFUSAL_TAILS = { write: "nothing written", read: "nothing opened" };
|
|
@@ -27205,7 +27545,18 @@ function heldRefOf(path3, seq, text) {
|
|
|
27205
27545
|
return stored;
|
|
27206
27546
|
throw new Error(`effort store: ${path3}: findings row ${seq} holds a tracker_ref ${stored};` + " no writer stores one");
|
|
27207
27547
|
}
|
|
27208
|
-
|
|
27548
|
+
|
|
27549
|
+
class SupersedeInSessionRefusal extends Error {
|
|
27550
|
+
path;
|
|
27551
|
+
seq;
|
|
27552
|
+
constructor(path3, seq) {
|
|
27553
|
+
super(`effort store: ${path3}: tracker ref write supersedes the reference findings row ${seq} holds` + " for this session and artifact, and findings_by_artifact holds one row per session and" + " artifact; nothing written");
|
|
27554
|
+
this.name = "SupersedeInSessionRefusal";
|
|
27555
|
+
this.path = path3;
|
|
27556
|
+
this.seq = seq;
|
|
27557
|
+
}
|
|
27558
|
+
}
|
|
27559
|
+
function placeRef(db, path3, write, wanted, superseded, insertValues) {
|
|
27209
27560
|
const held = db.query(SELECT_HELD2).get(write.dispatch.sessionId, write.artifact);
|
|
27210
27561
|
if (held === null) {
|
|
27211
27562
|
db.query(INSERT_REF).run(...insertValues());
|
|
@@ -27216,14 +27567,27 @@ function placeRef(db, path3, write, wanted, insertValues) {
|
|
|
27216
27567
|
return ["attached", wanted.ref];
|
|
27217
27568
|
}
|
|
27218
27569
|
const kept = heldRefOf(path3, held.seq, held.tracker_ref);
|
|
27570
|
+
if (kept.json === superseded?.json)
|
|
27571
|
+
throw new SupersedeInSessionRefusal(path3, held.seq);
|
|
27219
27572
|
return kept.json === wanted.json ? ["held", kept.ref] : ["conflict", kept.ref];
|
|
27220
27573
|
}
|
|
27574
|
+
function supersededOf(write, wanted) {
|
|
27575
|
+
if (write.supersedes === undefined)
|
|
27576
|
+
return null;
|
|
27577
|
+
const superseded = storedRefOf(write.supersedes);
|
|
27578
|
+
if (typeof superseded === "string")
|
|
27579
|
+
throw refused("write", `supersedes a reference ${superseded}`);
|
|
27580
|
+
if (superseded.json === wanted.json)
|
|
27581
|
+
throw refused("write", "supersedes the reference it writes");
|
|
27582
|
+
return superseded;
|
|
27583
|
+
}
|
|
27221
27584
|
function writeTrackerRef(repoRoot, write, seams = {}) {
|
|
27222
27585
|
checkDispatch("tracker ref", write.dispatch, write.outcome);
|
|
27223
27586
|
checkArtifact("write", write.artifact);
|
|
27224
27587
|
const wanted = storedRefOf(write.ref);
|
|
27225
27588
|
if (typeof wanted === "string")
|
|
27226
27589
|
throw refused("write", `has a reference ${wanted}`);
|
|
27590
|
+
const superseded = supersededOf(write, wanted);
|
|
27227
27591
|
const path3 = sqliteStorePath(repoRoot);
|
|
27228
27592
|
const { sessionId, planStub: planStub2, taskLine } = write.dispatch;
|
|
27229
27593
|
const collectedAt = (seams.now ?? (() => new Date))().toISOString();
|
|
@@ -27239,7 +27603,7 @@ function writeTrackerRef(repoRoot, write, seams = {}) {
|
|
|
27239
27603
|
collectedAt
|
|
27240
27604
|
];
|
|
27241
27605
|
const [action, stored] = withSqliteStore(path3, "write", !existsSync33(path3), (db) => {
|
|
27242
|
-
const place = db.transaction(() => placeRef(db, path3, write, wanted, insertValues));
|
|
27606
|
+
const place = db.transaction(() => placeRef(db, path3, write, wanted, superseded, insertValues));
|
|
27243
27607
|
return place.immediate();
|
|
27244
27608
|
});
|
|
27245
27609
|
return { path: path3, action, stored };
|
|
@@ -27249,52 +27613,8 @@ function readTrackerRef(repoRoot, artifact) {
|
|
|
27249
27613
|
const path3 = sqliteStorePath(repoRoot);
|
|
27250
27614
|
if (!existsSync33(path3))
|
|
27251
27615
|
return null;
|
|
27252
|
-
const
|
|
27253
|
-
return
|
|
27254
|
-
}
|
|
27255
|
-
|
|
27256
|
-
// src/triage/local-paths.ts
|
|
27257
|
-
import { realpathSync as realpathSync5 } from "fs";
|
|
27258
|
-
import { resolve as resolve20 } from "path";
|
|
27259
|
-
var HOME_MARKER = "[redacted: HOME]";
|
|
27260
|
-
var SEGMENT = "[^/\\s'\"`()<>:,;]+";
|
|
27261
|
-
var HOME_PATTERN = `(?:/${SEGMENT})*?/(?:Users|home)/${SEGMENT}`;
|
|
27262
|
-
var PATH_START = "(?:(?<![\\w.\\-])|(?<=(?:^|\\s)-[A-Za-z]))";
|
|
27263
|
-
var UNDER = "(/)(?=[^\\s'\"`()<>])";
|
|
27264
|
-
var PATH_END = "(?![\\w\\-]|\\.[\\w.\\-/])";
|
|
27265
|
-
function literalPattern(text) {
|
|
27266
|
-
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
27267
|
-
}
|
|
27268
|
-
function forms(path3) {
|
|
27269
|
-
const given = resolve20(path3);
|
|
27270
|
-
try {
|
|
27271
|
-
const real = realpathSync5(given);
|
|
27272
|
-
return real === given ? [given] : [given, real];
|
|
27273
|
-
} catch {
|
|
27274
|
-
return [given];
|
|
27275
|
-
}
|
|
27276
|
-
}
|
|
27277
|
-
function isRoot(path3) {
|
|
27278
|
-
return path3.length > 1;
|
|
27279
|
-
}
|
|
27280
|
-
function localPathRedactor(repoRoot, home) {
|
|
27281
|
-
const asHome = (pattern) => ({ pattern, under: `${HOME_MARKER}/`, bare: HOME_MARKER });
|
|
27282
|
-
const asRepo = (pattern) => ({ pattern, under: "", bare: "." });
|
|
27283
|
-
const literals = [
|
|
27284
|
-
...forms(repoRoot).filter(isRoot).map((root) => asRepo(literalPattern(root))),
|
|
27285
|
-
...forms(home).filter(isRoot).map((root) => asHome(literalPattern(root)))
|
|
27286
|
-
];
|
|
27287
|
-
const roots = [
|
|
27288
|
-
...[...literals].sort((a, b) => b.pattern.length - a.pattern.length),
|
|
27289
|
-
asHome(HOME_PATTERN)
|
|
27290
|
-
];
|
|
27291
|
-
const alternatives = roots.map(({ pattern }) => `(${pattern})(?:${UNDER}|${PATH_END})`);
|
|
27292
|
-
const matcher = new RegExp(`${PATH_START}(?:${alternatives.join("|")})`, "g");
|
|
27293
|
-
return (text) => text.replace(matcher, (...groups) => {
|
|
27294
|
-
const index = roots.findIndex((_, at) => groups[1 + at * 2] !== undefined);
|
|
27295
|
-
const root = roots[index];
|
|
27296
|
-
return groups[2 + index * 2] === undefined ? root.bare : root.under;
|
|
27297
|
-
});
|
|
27616
|
+
const newest = withSqliteStore(path3, "read", false, (db) => db.query(SELECT_NEWEST).get(artifact));
|
|
27617
|
+
return newest === null ? null : heldRefOf(path3, newest.seq, newest.tracker_ref).ref;
|
|
27298
27618
|
}
|
|
27299
27619
|
|
|
27300
27620
|
// src/triage/refs-section.ts
|
|
@@ -27358,17 +27678,72 @@ function createArtifactRefsVerifier(repoRoot, env) {
|
|
|
27358
27678
|
};
|
|
27359
27679
|
}
|
|
27360
27680
|
|
|
27681
|
+
// src/triage/similarity.ts
|
|
27682
|
+
import { basename as basename13 } from "path";
|
|
27683
|
+
var NON_WORD2 = /\W+/;
|
|
27684
|
+
var FENCE_LINE6 = /^`{3,}$/;
|
|
27685
|
+
var HEADING_LINE3 = /^## (.+)$/;
|
|
27686
|
+
function wordSetOf(text) {
|
|
27687
|
+
const words = strippedText(text).toLowerCase().split(NON_WORD2).filter((word) => word.length > 0);
|
|
27688
|
+
return new Set(words);
|
|
27689
|
+
}
|
|
27690
|
+
function reportWordsOf(report2) {
|
|
27691
|
+
return wordSetOf(`${report2.what ?? ""}
|
|
27692
|
+
${report2.artifact ?? ""}`);
|
|
27693
|
+
}
|
|
27694
|
+
function jaccard(a, b) {
|
|
27695
|
+
const shared = [...a].filter((word) => b.has(word)).length;
|
|
27696
|
+
const all = a.size + b.size - shared;
|
|
27697
|
+
return all === 0 ? 0 : shared / all;
|
|
27698
|
+
}
|
|
27699
|
+
function fencedValueAt(lines, start) {
|
|
27700
|
+
const open = lines.slice(start).findIndex((line) => line.trim().length > 0);
|
|
27701
|
+
if (open === -1)
|
|
27702
|
+
return null;
|
|
27703
|
+
const fence = lines[start + open];
|
|
27704
|
+
if (!FENCE_LINE6.test(fence))
|
|
27705
|
+
return null;
|
|
27706
|
+
const body = lines.slice(start + open + 1);
|
|
27707
|
+
const close = body.indexOf(fence);
|
|
27708
|
+
return close === -1 ? null : body.slice(0, close).join(`
|
|
27709
|
+
`);
|
|
27710
|
+
}
|
|
27711
|
+
function sectionValueOf(body, heading) {
|
|
27712
|
+
const lines = body.split(/\r?\n/);
|
|
27713
|
+
const at = lines.findIndex((line) => HEADING_LINE3.exec(line)?.[1]?.trim() === heading);
|
|
27714
|
+
return at === -1 ? null : fencedValueAt(lines, at + 1);
|
|
27715
|
+
}
|
|
27716
|
+
function issueTextOf(body) {
|
|
27717
|
+
return {
|
|
27718
|
+
what: sectionValueOf(body, "What"),
|
|
27719
|
+
artifact: sectionValueOf(body, "Artifact")
|
|
27720
|
+
};
|
|
27721
|
+
}
|
|
27722
|
+
function testFileOf2(text) {
|
|
27723
|
+
const file = testFailureOf(text)?.file ?? testFilesIn(text.artifact ?? "")[0] ?? testFilesIn(text.what ?? "")[0] ?? null;
|
|
27724
|
+
return file === null ? null : basename13(file);
|
|
27725
|
+
}
|
|
27726
|
+
function namesOtherTestFile(reportFile, issueFile) {
|
|
27727
|
+
return reportFile !== null && issueFile !== null && reportFile !== issueFile;
|
|
27728
|
+
}
|
|
27729
|
+
function nearestOpenBugs(report2, openBugs) {
|
|
27730
|
+
const words = reportWordsOf(report2);
|
|
27731
|
+
const reportFile = testFileOf2(report2);
|
|
27732
|
+
const scored = openBugs.flatMap((issue3) => {
|
|
27733
|
+
const text = issueTextOf(issue3.body);
|
|
27734
|
+
if (namesOtherTestFile(reportFile, testFileOf2(text)))
|
|
27735
|
+
return [];
|
|
27736
|
+
const score = jaccard(words, reportWordsOf(text));
|
|
27737
|
+
return score > 0 ? [{ issue: issue3, score }] : [];
|
|
27738
|
+
});
|
|
27739
|
+
return [...scored].sort((a, b) => b.score - a.score);
|
|
27740
|
+
}
|
|
27741
|
+
|
|
27361
27742
|
// src/triage/triage.ts
|
|
27362
27743
|
var PRIVATE_TRIAGE_DIR = join35(".rafa", "triage", "private");
|
|
27363
27744
|
var SECRET_ENV_NAMES = ["GITHUB_TOKEN", "ANTHROPIC_API_KEY", "LINEAR_API_KEY"];
|
|
27364
27745
|
var TRIAGE_MODULE = "unassigned";
|
|
27365
27746
|
var BLOCKER_SEPARATOR = "; ";
|
|
27366
|
-
var KEY_SEPARATOR = ": ";
|
|
27367
|
-
var TITLE_MAX_LENGTH = 120;
|
|
27368
|
-
var TITLE_CUT = "...";
|
|
27369
|
-
var MIN_FENCE_LENGTH = 3;
|
|
27370
|
-
var ISSUE_OPENING = "An out-of-scope bug a rafa task session reported. The loop filed it and" + " dispatches no task for it: a plan that wants it fixed declares a task.";
|
|
27371
|
-
var COMMENT_OPENING = "Reported again by a rafa task session.";
|
|
27372
27747
|
function privateTriageDir(repoRoot) {
|
|
27373
27748
|
return join35(repoRoot, PRIVATE_TRIAGE_DIR);
|
|
27374
27749
|
}
|
|
@@ -27405,9 +27780,6 @@ function redactSecrets(text, secrets) {
|
|
|
27405
27780
|
const pattern = new RegExp(values.map(literalPattern2).join("|"), "g");
|
|
27406
27781
|
return text.replace(pattern, (value) => `[redacted: ${nameByValue.get(value)}]`);
|
|
27407
27782
|
}
|
|
27408
|
-
function hasText2(value) {
|
|
27409
|
-
return typeof value === "string" && value.trim().length > 0;
|
|
27410
|
-
}
|
|
27411
27783
|
function blockerTextOf(blockers) {
|
|
27412
27784
|
const texts = blockers.map((blocker) => blocker.what).filter(hasText2);
|
|
27413
27785
|
return texts.length === 0 ? null : texts.join(BLOCKER_SEPARATOR);
|
|
@@ -27426,57 +27798,11 @@ function triageBlockers(options) {
|
|
|
27426
27798
|
return { text, written: false, problem: `the blocker was not written: ${messageOf(error)}` };
|
|
27427
27799
|
}
|
|
27428
27800
|
}
|
|
27429
|
-
function artifactOf(bug) {
|
|
27430
|
-
return hasText2(bug.artifact) && textProblem(bug.artifact) === null ? bug.artifact : null;
|
|
27431
|
-
}
|
|
27432
|
-
function oneLine7(text) {
|
|
27433
|
-
return text.replace(/\s+/g, " ").trim();
|
|
27434
|
-
}
|
|
27435
|
-
function bugKeyOf(trackerPath, artifact) {
|
|
27436
|
-
return `${basename11(trackerPath)}${KEY_SEPARATOR}${oneLine7(artifact)}`;
|
|
27437
|
-
}
|
|
27438
|
-
function fenced(value) {
|
|
27439
|
-
const runs = Array.from(value.matchAll(/`+/g), (run) => run[0].length);
|
|
27440
|
-
const fence = "`".repeat(Math.max(MIN_FENCE_LENGTH, ...runs.map((length) => length + 1)));
|
|
27441
|
-
const body = value.endsWith(`
|
|
27442
|
-
`) ? value : `${value}
|
|
27443
|
-
`;
|
|
27444
|
-
return `${fence}
|
|
27445
|
-
${body}${fence}`;
|
|
27446
|
-
}
|
|
27447
|
-
function issueTitle2(redactedWhat) {
|
|
27448
|
-
const line = oneLine7(redactedWhat);
|
|
27449
|
-
const points = Array.from(line);
|
|
27450
|
-
if (points.length <= TITLE_MAX_LENGTH)
|
|
27451
|
-
return line;
|
|
27452
|
-
const kept = points.slice(0, TITLE_MAX_LENGTH - TITLE_CUT.length).join("");
|
|
27453
|
-
return `${kept.trimEnd()}${TITLE_CUT}`;
|
|
27454
|
-
}
|
|
27455
|
-
function section(heading, value, absent2, redact) {
|
|
27456
|
-
const shown = value === null ? absent2 : fenced(redact(value));
|
|
27457
|
-
return `## ${heading}
|
|
27458
|
-
|
|
27459
|
-
${shown}`;
|
|
27460
|
-
}
|
|
27461
|
-
function issueText(opening, values, redact) {
|
|
27462
|
-
return [
|
|
27463
|
-
opening,
|
|
27464
|
-
section("What", values.what, "", redact),
|
|
27465
|
-
section("Artifact", values.artifact, "The report gave no artifact, so a recurrence files again.", redact),
|
|
27466
|
-
...values.refs === null ? [] : [values.refs],
|
|
27467
|
-
section("Recurrence key", values.key, "The report gave no artifact, so this bug has no key.", redact),
|
|
27468
|
-
section("Plan", values.planStub, "The dispatch resolved no plan stub.", redact),
|
|
27469
|
-
section("Task", values.taskText, "", redact),
|
|
27470
|
-
section("Feedback", values.feedback, "The report gave no feedback.", redact)
|
|
27471
|
-
].join(`
|
|
27472
|
-
|
|
27473
|
-
`) + `
|
|
27474
|
-
`;
|
|
27475
|
-
}
|
|
27476
27801
|
async function filingFor(what, bug, options, local, redact, verifyRefs) {
|
|
27477
27802
|
const reported = artifactOf(bug);
|
|
27478
27803
|
const artifact = reported === null ? null : local(reported);
|
|
27479
|
-
const searchText = artifact === null ? null : bugKeyOf(options.trackerPath, redact(artifact));
|
|
27804
|
+
const searchText = artifact === null ? null : bugKeyOf(options.trackerPath, redact(artifact), redact(what));
|
|
27805
|
+
const key = artifact === null ? null : bugKeyOf(options.trackerPath, artifact, local(what));
|
|
27480
27806
|
const refs = await buildRefsSection(artifact === null ? null : redact(artifact), verifyRefs);
|
|
27481
27807
|
const values = {
|
|
27482
27808
|
what,
|
|
@@ -27500,10 +27826,23 @@ async function filingFor(what, bug, options, local, redact, verifyRefs) {
|
|
|
27500
27826
|
},
|
|
27501
27827
|
comment: issueText(COMMENT_OPENING, values, redact),
|
|
27502
27828
|
searchText,
|
|
27503
|
-
key
|
|
27504
|
-
|
|
27829
|
+
key,
|
|
27830
|
+
legacyKeys: legacyKeysOf(options.trackerPath, key, reported, artifact),
|
|
27831
|
+
values,
|
|
27832
|
+
compared: { what: local(what), artifact }
|
|
27505
27833
|
};
|
|
27506
27834
|
}
|
|
27835
|
+
function legacyKeysOf(trackerPath, key, reported, artifact) {
|
|
27836
|
+
if (key === null || reported === null || artifact === null)
|
|
27837
|
+
return [];
|
|
27838
|
+
const keys = [legacyBugKeyOf(trackerPath, artifact), legacyBugKeyOf(trackerPath, reported)];
|
|
27839
|
+
return [...new Set(keys)].filter((legacy) => legacy !== key);
|
|
27840
|
+
}
|
|
27841
|
+
function similarityStepOf(options) {
|
|
27842
|
+
const threshold = options.similarity?.triageSimilarityThreshold;
|
|
27843
|
+
const candidates = options.similarity?.triageSimilarityCandidates;
|
|
27844
|
+
return typeof threshold === "number" && typeof candidates === "number" ? { threshold, candidates } : null;
|
|
27845
|
+
}
|
|
27507
27846
|
async function step(run, name2, action) {
|
|
27508
27847
|
try {
|
|
27509
27848
|
return { ok: true, value: await action() };
|
|
@@ -27523,47 +27862,110 @@ function resultOf(run, action, fields = {}) {
|
|
|
27523
27862
|
...fields
|
|
27524
27863
|
};
|
|
27525
27864
|
}
|
|
27526
|
-
async function settle(run, action, ref8, foundBy) {
|
|
27865
|
+
async function settle(run, action, ref8, foundBy, supersedes) {
|
|
27527
27866
|
const { store } = run.route;
|
|
27528
27867
|
const { key } = run.filing;
|
|
27529
27868
|
if (store === null || key === null)
|
|
27530
27869
|
return resultOf(run, action, { ref: ref8, foundBy });
|
|
27531
|
-
const stored = await step(run, "storing the reference", () => store(key, ref8));
|
|
27870
|
+
const stored = await step(run, "storing the reference", () => store(key, ref8, supersedes));
|
|
27532
27871
|
return stored.ok ? resultOf(run, action, { ref: ref8, foundBy, stored: stored.value }) : resultOf(run, action, { ref: ref8, foundBy, problem: stored.problem });
|
|
27533
27872
|
}
|
|
27534
|
-
async function fileNew(run) {
|
|
27535
|
-
const
|
|
27536
|
-
|
|
27873
|
+
async function fileNew(run, extras = {}) {
|
|
27874
|
+
const { filing } = run;
|
|
27875
|
+
const draft = extras.supersedes === undefined && extras.duplicates === undefined ? filing.draft : { ...filing.draft, body: issueText(ISSUE_OPENING, { ...filing.values, ...extras }, run.redact) };
|
|
27876
|
+
const created = await step(run, `the ${run.route.channel} tracker create`, () => run.route.tracker.create(draft));
|
|
27877
|
+
return created.ok ? settle(run, "filed", created.value, null, extras.supersedes) : resultOf(run, "failed", { problem: created.problem });
|
|
27537
27878
|
}
|
|
27538
|
-
async function commentOn(run, ref8, foundBy) {
|
|
27539
|
-
const commented = await step(run, `the ${run.route.channel} tracker comment`, () => run.route.tracker.comment(ref8,
|
|
27879
|
+
async function commentOn(run, ref8, foundBy, action = "commented", comment = run.filing.comment) {
|
|
27880
|
+
const commented = await step(run, `the ${run.route.channel} tracker comment`, () => run.route.tracker.comment(ref8, comment));
|
|
27540
27881
|
if (!commented.ok)
|
|
27541
27882
|
return resultOf(run, "failed", { ref: ref8, foundBy, problem: commented.problem });
|
|
27542
|
-
return foundBy === "store" ? resultOf(run,
|
|
27883
|
+
return foundBy === "store" ? resultOf(run, action, { ref: ref8, foundBy }) : settle(run, action, ref8, foundBy);
|
|
27543
27884
|
}
|
|
27544
|
-
async function
|
|
27885
|
+
async function lookUp2(run, key, searchText) {
|
|
27545
27886
|
const { route, filing } = run;
|
|
27546
|
-
const { key, searchText } = filing;
|
|
27547
|
-
if (key === null || searchText === null)
|
|
27548
|
-
return fileNew(run);
|
|
27549
27887
|
const { readStored } = route;
|
|
27550
27888
|
if (readStored !== null) {
|
|
27551
|
-
for (const storedKey of [key, filing.
|
|
27552
|
-
if (storedKey === null)
|
|
27553
|
-
continue;
|
|
27889
|
+
for (const storedKey of [key, ...filing.legacyKeys]) {
|
|
27554
27890
|
const stored = await step(run, "reading the stored reference", () => readStored(storedKey));
|
|
27555
27891
|
if (!stored.ok)
|
|
27556
|
-
return
|
|
27892
|
+
return stored;
|
|
27557
27893
|
if (stored.value !== null && stored.value.kind === route.tracker.kind) {
|
|
27558
|
-
return
|
|
27894
|
+
return { ok: true, value: { ref: stored.value, foundBy: "store" } };
|
|
27559
27895
|
}
|
|
27560
27896
|
}
|
|
27561
27897
|
}
|
|
27562
27898
|
const found = await step(run, `the ${route.channel} tracker find`, () => route.tracker.find({ text: searchText, type: "bug" }));
|
|
27563
27899
|
if (!found.ok)
|
|
27564
|
-
return
|
|
27900
|
+
return found;
|
|
27565
27901
|
const [match] = found.value;
|
|
27566
|
-
return
|
|
27902
|
+
return {
|
|
27903
|
+
ok: true,
|
|
27904
|
+
value: match === undefined ? null : { ref: match, foundBy: "find" }
|
|
27905
|
+
};
|
|
27906
|
+
}
|
|
27907
|
+
var COMPLETED_ISSUE_STATES = ["done", "released"];
|
|
27908
|
+
async function answerRecurrence(run, { ref: ref8, foundBy }) {
|
|
27909
|
+
if (!run.route.readsState)
|
|
27910
|
+
return commentOn(run, ref8, foundBy);
|
|
27911
|
+
const issue3 = await step(run, `the ${run.route.channel} tracker get`, () => run.route.tracker.get(ref8));
|
|
27912
|
+
if (!issue3.ok)
|
|
27913
|
+
return resultOf(run, "failed", { ref: ref8, foundBy, problem: issue3.problem });
|
|
27914
|
+
return COMPLETED_ISSUE_STATES.includes(issue3.value.state) ? fileNew(run, { supersedes: ref8 }) : commentOn(run, ref8, foundBy);
|
|
27915
|
+
}
|
|
27916
|
+
async function commentOnNearest(run, nearest, threshold) {
|
|
27917
|
+
const opening = similarCommentOpening(nearest.score, threshold);
|
|
27918
|
+
const comment = issueText(opening, run.filing.values, run.redact);
|
|
27919
|
+
const result = await commentOn(run, nearest.issue.ref, "similarity", "commented", comment);
|
|
27920
|
+
return { ...result, score: nearest.score };
|
|
27921
|
+
}
|
|
27922
|
+
async function answerMiss(run) {
|
|
27923
|
+
const { tracker, similarity } = run.route;
|
|
27924
|
+
const list = tracker.openIssues;
|
|
27925
|
+
if (similarity === null || list === undefined)
|
|
27926
|
+
return fileNew(run);
|
|
27927
|
+
const listed = await step(run, `the ${run.route.channel} tracker openIssues`, () => list.call(tracker, "bug"));
|
|
27928
|
+
if (!listed.ok)
|
|
27929
|
+
return resultOf(run, "failed", { problem: listed.problem });
|
|
27930
|
+
const nearest = nearestOpenBugs(run.filing.compared, listed.value);
|
|
27931
|
+
const [first] = nearest;
|
|
27932
|
+
return first !== undefined && first.score >= similarity.threshold ? commentOnNearest(run, first, similarity.threshold) : fileNew(run, { duplicates: { threshold: similarity.threshold, nearest: nearest.slice(0, similarity.candidates) } });
|
|
27933
|
+
}
|
|
27934
|
+
async function triageBug(run) {
|
|
27935
|
+
const { key, searchText } = run.filing;
|
|
27936
|
+
if (key === null || searchText === null)
|
|
27937
|
+
return fileNew(run);
|
|
27938
|
+
const found = await lookUp2(run, key, searchText);
|
|
27939
|
+
if (!found.ok)
|
|
27940
|
+
return resultOf(run, "failed", { problem: found.problem });
|
|
27941
|
+
return found.value === null ? answerMiss(run) : answerRecurrence(run, found.value);
|
|
27942
|
+
}
|
|
27943
|
+
async function triageInherited(run, commented) {
|
|
27944
|
+
const { key, searchText } = run.filing;
|
|
27945
|
+
if (key === null || searchText === null || commented.has(key))
|
|
27946
|
+
return resultOf(run, "inherited");
|
|
27947
|
+
const found = await lookUp2(run, key, searchText);
|
|
27948
|
+
if (!found.ok)
|
|
27949
|
+
return resultOf(run, "failed", { problem: found.problem });
|
|
27950
|
+
if (found.value === null)
|
|
27951
|
+
return resultOf(run, "inherited");
|
|
27952
|
+
const { ref: ref8, foundBy } = found.value;
|
|
27953
|
+
const issue3 = await step(run, `the ${run.route.channel} tracker get`, () => run.route.tracker.get(ref8));
|
|
27954
|
+
if (!issue3.ok)
|
|
27955
|
+
return resultOf(run, "failed", { ref: ref8, foundBy, problem: issue3.problem });
|
|
27956
|
+
if (!isOpenIssueState(issue3.value.state))
|
|
27957
|
+
return resultOf(run, "inherited");
|
|
27958
|
+
const result = await commentOn(run, ref8, foundBy, "inherited");
|
|
27959
|
+
if (result.action === "inherited")
|
|
27960
|
+
commented.add(key);
|
|
27961
|
+
return result;
|
|
27962
|
+
}
|
|
27963
|
+
function localBug(bug, what, local) {
|
|
27964
|
+
const artifact = artifactOf(bug);
|
|
27965
|
+
return {
|
|
27966
|
+
what: local(what),
|
|
27967
|
+
artifact: artifact === null ? null : local(artifact)
|
|
27968
|
+
};
|
|
27567
27969
|
}
|
|
27568
27970
|
function skippedRow(index, channel, problem) {
|
|
27569
27971
|
return { index, channel, action: "skipped", ref: null, foundBy: null, stored: null, problem };
|
|
@@ -27592,14 +27994,24 @@ async function triageReport(options) {
|
|
|
27592
27994
|
channel: "public",
|
|
27593
27995
|
tracker: options.tracker,
|
|
27594
27996
|
readStored: (key) => readTrackerRef(repoRoot, key),
|
|
27595
|
-
store: (key, ref8) => writeTrackerRef(repoRoot, {
|
|
27997
|
+
store: (key, ref8, supersedes) => writeTrackerRef(repoRoot, {
|
|
27596
27998
|
dispatch: options.dispatch,
|
|
27597
27999
|
outcome: options.outcome,
|
|
27598
28000
|
artifact: key,
|
|
27599
|
-
ref: ref8
|
|
27600
|
-
|
|
28001
|
+
ref: ref8,
|
|
28002
|
+
...supersedes === undefined ? {} : { supersedes }
|
|
28003
|
+
}, options.seams).action,
|
|
28004
|
+
readsState: true,
|
|
28005
|
+
similarity: similarityStepOf(options)
|
|
27601
28006
|
},
|
|
27602
|
-
private: {
|
|
28007
|
+
private: {
|
|
28008
|
+
channel: "private",
|
|
28009
|
+
tracker: privateTracker,
|
|
28010
|
+
readStored: null,
|
|
28011
|
+
store: null,
|
|
28012
|
+
readsState: false,
|
|
28013
|
+
similarity: null
|
|
28014
|
+
}
|
|
27603
28015
|
};
|
|
27604
28016
|
const bugs = [];
|
|
27605
28017
|
for (const [index, bug] of options.report.outOfScopeBugs.entries()) {
|
|
@@ -27615,7 +28027,10 @@ async function triageReport(options) {
|
|
|
27615
28027
|
continue;
|
|
27616
28028
|
}
|
|
27617
28029
|
const filing = await filingFor(what, bug, options, local, redact, verifyRefs);
|
|
27618
|
-
|
|
28030
|
+
const run = { route, index, filing, redact };
|
|
28031
|
+
const { inherited } = options;
|
|
28032
|
+
const isInherited = route.channel === "public" && inherited !== undefined && inheritedFailureOf(localBug(bug, what, local), inherited.failures) !== null;
|
|
28033
|
+
bugs.push(isInherited ? await triageInherited(run, inherited.commented) : await triageBug(run));
|
|
27619
28034
|
}
|
|
27620
28035
|
return { blocker, bugs };
|
|
27621
28036
|
}
|
|
@@ -27626,8 +28041,13 @@ var LINE_PREFIX = "Triage: ";
|
|
|
27626
28041
|
var INDENT8 = " ";
|
|
27627
28042
|
var FOUND_BY = {
|
|
27628
28043
|
store: "its stored reference",
|
|
27629
|
-
find: "a tracker find"
|
|
28044
|
+
find: "a tracker find",
|
|
28045
|
+
similarity: "word similarity"
|
|
27630
28046
|
};
|
|
28047
|
+
function foundByText(bug) {
|
|
28048
|
+
const found = FOUND_BY[bug.foundBy ?? "find"];
|
|
28049
|
+
return bug.score === undefined ? found : `${found} (score ${scoreText(bug.score)})`;
|
|
28050
|
+
}
|
|
27631
28051
|
function unresolvedTracker(kind, reason) {
|
|
27632
28052
|
const refuse7 = () => Promise.reject(new Error(reason));
|
|
27633
28053
|
return Object.freeze({
|
|
@@ -27650,7 +28070,15 @@ function hasTriage(report2) {
|
|
|
27650
28070
|
function issueName2(ref8) {
|
|
27651
28071
|
return ref8.url ?? `${ref8.kind} issue ${ref8.externalId}`;
|
|
27652
28072
|
}
|
|
27653
|
-
function
|
|
28073
|
+
function failureName(failure3) {
|
|
28074
|
+
return `${failure3.file} > ${failure3.name}`;
|
|
28075
|
+
}
|
|
28076
|
+
function inheritedNote(bug, name2, where, failure3) {
|
|
28077
|
+
const test = failure3 === undefined ? "a red test the run started with" : `the run-start failure ${failureName(failure3)}`;
|
|
28078
|
+
const comment = bug.ref === null ? "" : `, and ${issueName2(bug.ref)} on ${where}, found by ${foundByText(bug)}, was commented on`;
|
|
28079
|
+
return `${name2}: inherited: ${test}; nothing was filed${comment}.`;
|
|
28080
|
+
}
|
|
28081
|
+
function bugLines(bug, inherited) {
|
|
27654
28082
|
const name2 = `out_of_scope_bugs[${bug.index}]`;
|
|
27655
28083
|
const where = `the ${bug.channel} tracker`;
|
|
27656
28084
|
if (bug.action === "skipped") {
|
|
@@ -27661,16 +28089,17 @@ function bugLines(bug) {
|
|
|
27661
28089
|
return { notes: [], warnings: [warning] };
|
|
27662
28090
|
}
|
|
27663
28091
|
const issue3 = bug.ref === null ? "an issue" : issueName2(bug.ref);
|
|
27664
|
-
const
|
|
28092
|
+
const reached = bug.action === "filed" ? `${name2}: filed on ${where} as ${issue3}.` : `${name2}: recurs in ${issue3} on ${where}, found by ${foundByText(bug)}; commented on it.`;
|
|
28093
|
+
const note = bug.action === "inherited" ? inheritedNote(bug, name2, where, inherited) : reached;
|
|
27665
28094
|
const problem = bug.problem === null ? [] : [`${name2}: ${bug.problem}`];
|
|
27666
28095
|
const conflict = bug.stored === "conflict" ? [`${name2}: the store keeps another reference for its artifact, in place of ${issue3}.`] : [];
|
|
27667
28096
|
return { notes: [note], warnings: [...problem, ...conflict] };
|
|
27668
28097
|
}
|
|
27669
|
-
function describeStartTriage(result) {
|
|
28098
|
+
function describeStartTriage(result, inherited = new Map) {
|
|
27670
28099
|
const { blocker } = result;
|
|
27671
28100
|
const blockerNotes = blocker.written ? ["blockers: written onto the task line, for the next dispatch of this task."] : [];
|
|
27672
28101
|
const blockerWarnings = blocker.problem === null ? [] : [`blockers: ${blocker.problem}`];
|
|
27673
|
-
const bugs = result.bugs.map(bugLines);
|
|
28102
|
+
const bugs = result.bugs.map((bug) => bugLines(bug, inherited.get(bug.index)));
|
|
27674
28103
|
const prefixed = (lines) => lines.map((line) => `${LINE_PREFIX}${line}`);
|
|
27675
28104
|
return {
|
|
27676
28105
|
notes: prefixed([...blockerNotes, ...bugs.flatMap((lines) => lines.notes)]),
|
|
@@ -27694,10 +28123,42 @@ async function resolvePublicTracker(options, redact) {
|
|
|
27694
28123
|
return unresolvedTracker(options.config.trackerDefault, reason);
|
|
27695
28124
|
}
|
|
27696
28125
|
}
|
|
28126
|
+
function baselinePathOrNull(trackerPath) {
|
|
28127
|
+
try {
|
|
28128
|
+
return baselinePathFor(trackerPath);
|
|
28129
|
+
} catch {
|
|
28130
|
+
return null;
|
|
28131
|
+
}
|
|
28132
|
+
}
|
|
28133
|
+
function runStartFailures(trackerPath) {
|
|
28134
|
+
const path3 = baselinePathOrNull(trackerPath);
|
|
28135
|
+
const reading2 = path3 === null ? null : readBaseline(path3);
|
|
28136
|
+
return reading2?.state === "read" && reading2.baseline.junit === "read" ? reading2.baseline.failures : [];
|
|
28137
|
+
}
|
|
28138
|
+
function inheritedByIndex(result, report2, failures, local, redact) {
|
|
28139
|
+
const named3 = result.bugs.flatMap((bug) => {
|
|
28140
|
+
const reported = report2.outOfScopeBugs[bug.index];
|
|
28141
|
+
if (bug.action !== "inherited" || reported === undefined || !hasText2(reported.what))
|
|
28142
|
+
return [];
|
|
28143
|
+
const artifact = artifactOf(reported);
|
|
28144
|
+
const failure3 = inheritedFailureOf({
|
|
28145
|
+
what: local(reported.what),
|
|
28146
|
+
artifact: artifact === null ? null : local(artifact)
|
|
28147
|
+
}, failures);
|
|
28148
|
+
return failure3 === null ? [] : [[bug.index, { file: redact(failure3.file), name: redact(failure3.name) }]];
|
|
28149
|
+
});
|
|
28150
|
+
return new Map(named3);
|
|
28151
|
+
}
|
|
27697
28152
|
function createStartTriage(options) {
|
|
27698
28153
|
const secrets = namedSecrets(options.config, options.env ?? process.env);
|
|
27699
28154
|
const redact = (text) => redactSecrets(text, secrets);
|
|
28155
|
+
const local = localPathRedactor(options.repoRoot, homedir8());
|
|
27700
28156
|
let publicTracker = null;
|
|
28157
|
+
let inherited = null;
|
|
28158
|
+
const inheritedFor = (trackerPath) => {
|
|
28159
|
+
inherited ??= { failures: runStartFailures(trackerPath), commented: new Set };
|
|
28160
|
+
return inherited;
|
|
28161
|
+
};
|
|
27701
28162
|
const trackerFor = (report2) => {
|
|
27702
28163
|
if (!report2.outOfScopeBugs.some(filesPublicly)) {
|
|
27703
28164
|
return Promise.resolve(unresolvedTracker(options.config.trackerDefault, NOT_RESOLVED_REASON));
|
|
@@ -27710,6 +28171,7 @@ function createStartTriage(options) {
|
|
|
27710
28171
|
if (!reading2.present || !hasTriage(reading2.report))
|
|
27711
28172
|
return null;
|
|
27712
28173
|
const { report: report2 } = reading2;
|
|
28174
|
+
const run = inheritedFor(input.trackerPath);
|
|
27713
28175
|
const result = await triageReport({
|
|
27714
28176
|
repoRoot: options.repoRoot,
|
|
27715
28177
|
trackerPath: input.trackerPath,
|
|
@@ -27724,13 +28186,18 @@ function createStartTriage(options) {
|
|
|
27724
28186
|
tracker: await trackerFor(report2),
|
|
27725
28187
|
privateTracker: options.privateTracker,
|
|
27726
28188
|
secrets,
|
|
27727
|
-
seams: options.seams
|
|
28189
|
+
seams: options.seams,
|
|
28190
|
+
inherited: run,
|
|
28191
|
+
similarity: options.config
|
|
27728
28192
|
});
|
|
27729
|
-
const
|
|
28193
|
+
const named3 = inheritedByIndex(result, report2, run.failures, local, redact);
|
|
28194
|
+
const { notes, warnings } = describeStartTriage(result, named3);
|
|
27730
28195
|
for (const note of notes)
|
|
27731
28196
|
activeOutput().info(`${INDENT8}${note}`);
|
|
27732
28197
|
for (const warning of warnings)
|
|
27733
28198
|
activeOutput().warn(`${INDENT8}${warning}`);
|
|
28199
|
+
for (const failure3 of named3.values())
|
|
28200
|
+
emitLoopEvent({ kind: "inherited", file: failure3.file, name: failure3.name });
|
|
27734
28201
|
return result;
|
|
27735
28202
|
};
|
|
27736
28203
|
return async (input) => {
|
|
@@ -28447,6 +28914,28 @@ function firstLine6(text) {
|
|
|
28447
28914
|
`).map((line) => line.trim()).find((line) => line !== "") ?? "";
|
|
28448
28915
|
}
|
|
28449
28916
|
|
|
28917
|
+
// src/start/pr-retarget.ts
|
|
28918
|
+
function retargetedLine(number, from, to) {
|
|
28919
|
+
return `\u21AA Retargeted pull request #${String(number)} from ${from} to ${to} (pr.base).`;
|
|
28920
|
+
}
|
|
28921
|
+
function refusedRetargetLine(number, from, to, detail) {
|
|
28922
|
+
return `\u26A0\uFE0F Could not retarget pull request #${String(number)} from ${from} to ${to} (pr.base): ${detail}. Retarget it by hand; the run carries on to the CI wait.`;
|
|
28923
|
+
}
|
|
28924
|
+
async function retargetPullRequest(pull, base, seams) {
|
|
28925
|
+
const from = pull.baseRefName;
|
|
28926
|
+
if (from === base)
|
|
28927
|
+
return { kind: "unchanged" };
|
|
28928
|
+
try {
|
|
28929
|
+
await seams.pulls.editBase(pull.number, base);
|
|
28930
|
+
} catch (error) {
|
|
28931
|
+
const detail = messageOf(error);
|
|
28932
|
+
seams.output.warn(refusedRetargetLine(pull.number, from, base, detail));
|
|
28933
|
+
return { kind: "refused", from, to: base, detail };
|
|
28934
|
+
}
|
|
28935
|
+
seams.output.info(retargetedLine(pull.number, from, base));
|
|
28936
|
+
return { kind: "retargeted", from, to: base };
|
|
28937
|
+
}
|
|
28938
|
+
|
|
28450
28939
|
// src/release/prepare.ts
|
|
28451
28940
|
import { mkdirSync as mkdirSync13, readFileSync as readFileSync40, writeFileSync as writeFileSync15 } from "fs";
|
|
28452
28941
|
import { dirname as dirname14, join as join38, posix as posix4 } from "path";
|
|
@@ -28688,7 +29177,6 @@ var RELEASE_STAGE_SEAMS = {
|
|
|
28688
29177
|
push: pushBranch,
|
|
28689
29178
|
pulls: ghPullRequestsIn,
|
|
28690
29179
|
readProvider: (repoRoot) => resolvePrProvider({ configured: null, dir: repoRoot }),
|
|
28691
|
-
currentBranch: getCurrentBranch,
|
|
28692
29180
|
now: () => new Date
|
|
28693
29181
|
};
|
|
28694
29182
|
var PLAN_HEADING = /^# +(.+)$/;
|
|
@@ -28831,18 +29319,18 @@ function announceBody(write, count) {
|
|
|
28831
29319
|
}
|
|
28832
29320
|
out.info(` ${noun} ${verb} now in the body of pull request #${write.number}.`);
|
|
28833
29321
|
}
|
|
28834
|
-
async function writeBody(io,
|
|
28835
|
-
const reading2 = io.readProvider(repoRoot);
|
|
29322
|
+
async function writeBody(io, input, write) {
|
|
29323
|
+
const reading2 = io.readProvider(input.repoRoot);
|
|
28836
29324
|
if (reading2.provider !== "gh") {
|
|
28837
29325
|
const problem = noProviderProblem(reading2);
|
|
28838
29326
|
activeOutput().info(` No pull request body carries ${JSON.stringify(write.lines.join(" "))}: ${problem}.`);
|
|
28839
29327
|
return unwritten(null, problem);
|
|
28840
29328
|
}
|
|
28841
|
-
const body = await carryIntoBody(io.pulls(repoRoot),
|
|
29329
|
+
const body = await carryIntoBody(io.pulls(input.repoRoot), input.branch, write);
|
|
28842
29330
|
announceBody(body, write.lines.length);
|
|
28843
29331
|
return body;
|
|
28844
29332
|
}
|
|
28845
|
-
async function reportFailure(io,
|
|
29333
|
+
async function reportFailure(io, input, outcome2, sentence, facts) {
|
|
28846
29334
|
const out = activeOutput();
|
|
28847
29335
|
if (outcome2 === "skipped") {
|
|
28848
29336
|
out.info(`
|
|
@@ -28853,7 +29341,7 @@ async function reportFailure(io, repoRoot, outcome2, sentence, facts) {
|
|
|
28853
29341
|
}
|
|
28854
29342
|
const parts = { forecast: null, levelReport: facts.levelReport };
|
|
28855
29343
|
const block = releaseBodyBlock(parts);
|
|
28856
|
-
const body = await writeBody(io,
|
|
29344
|
+
const body = await writeBody(io, input, { sentence, block, lines: [sentence, ...releaseBodyLines(parts)] });
|
|
28857
29345
|
return { outcome: outcome2, sentence, forecast: null, body, ...facts };
|
|
28858
29346
|
}
|
|
28859
29347
|
var NO_RELEASE = {
|
|
@@ -28873,12 +29361,12 @@ async function reportForecast(io, input, forecast, facts) {
|
|
|
28873
29361
|
out.warn(` \u26A0\uFE0F ${problem}`);
|
|
28874
29362
|
const parts = { forecast, levelReport: facts.levelReport };
|
|
28875
29363
|
const block = releaseBodyBlock(parts);
|
|
28876
|
-
const body = await writeBody(io, input
|
|
29364
|
+
const body = await writeBody(io, input, { sentence: null, block, lines: releaseBodyLines(parts) });
|
|
28877
29365
|
return { outcome: "released", sentence: null, forecast, body, ...facts };
|
|
28878
29366
|
}
|
|
28879
29367
|
async function finishRelease(input, seams = {}) {
|
|
28880
29368
|
const io = { ...RELEASE_STAGE_SEAMS, ...seams };
|
|
28881
|
-
const { preparation, repoRoot, settings } = input;
|
|
29369
|
+
const { preparation, repoRoot, branch, settings } = input;
|
|
28882
29370
|
if (preparation === null)
|
|
28883
29371
|
return NO_RELEASE;
|
|
28884
29372
|
const levelReport = releaseLevelReport({
|
|
@@ -28888,31 +29376,30 @@ async function finishRelease(input, seams = {}) {
|
|
|
28888
29376
|
});
|
|
28889
29377
|
const none2 = { fragment: null, subject: null, sha: null, levelReport };
|
|
28890
29378
|
if (preparation.kind === "skipped") {
|
|
28891
|
-
return reportFailure(io,
|
|
29379
|
+
return reportFailure(io, input, "skipped", preparation.sentence, none2);
|
|
28892
29380
|
}
|
|
28893
29381
|
const git = io.git(repoRoot);
|
|
28894
29382
|
const verification = io.verify(preparation, { git, settings });
|
|
28895
29383
|
if (verification.kind === "refused") {
|
|
28896
|
-
return reportFailure(io,
|
|
29384
|
+
return reportFailure(io, input, "refused", verification.sentence, none2);
|
|
28897
29385
|
}
|
|
28898
29386
|
const fragment = verification.path;
|
|
28899
29387
|
const subject = releaseSubject(preparation);
|
|
28900
29388
|
const commit = commitFragment(git, fragment, subject);
|
|
28901
29389
|
if (!commit.committed) {
|
|
28902
|
-
return reportFailure(io,
|
|
29390
|
+
return reportFailure(io, input, "uncommitted", commit.sentence, { ...none2, fragment, subject });
|
|
28903
29391
|
}
|
|
28904
29392
|
const out = activeOutput();
|
|
28905
29393
|
const sha = commit.sha;
|
|
28906
29394
|
const facts = { fragment, subject, sha, levelReport };
|
|
28907
29395
|
out.info(`
|
|
28908
29396
|
\uD83D\uDCE6 Committed ${commitName(sha, subject)} over ${fragment}.`);
|
|
28909
|
-
const branch = io.currentBranch();
|
|
28910
29397
|
const pushed = io.push(repoRoot, branch);
|
|
28911
29398
|
if (!pushed.ok) {
|
|
28912
29399
|
const said = pushed.output.trim() === "" ? "" : `: ${pushed.output.trim().split(`
|
|
28913
29400
|
`)[0] ?? ""}`;
|
|
28914
29401
|
const sentence = `${commitName(sha, subject)} was made but could not be pushed to ${branch}${said}`;
|
|
28915
|
-
return reportFailure(io,
|
|
29402
|
+
return reportFailure(io, input, "unpushed", sentence, facts);
|
|
28916
29403
|
}
|
|
28917
29404
|
out.info(` Pushed it to ${branch}.`);
|
|
28918
29405
|
const forecast = io.forecast({ git, settings, prepared: preparation, verified: verification, now: io.now() });
|
|
@@ -29225,7 +29712,7 @@ async function checkWrapUpAnswer(input) {
|
|
|
29225
29712
|
}
|
|
29226
29713
|
|
|
29227
29714
|
// src/start/wrap-up.ts
|
|
29228
|
-
function buildWrapUpPrompt(branch, planContent, openPullRequest = null, release = null, lessons = []) {
|
|
29715
|
+
function buildWrapUpPrompt(branch, base, planContent, openPullRequest = null, release = null, lessons = []) {
|
|
29229
29716
|
return [
|
|
29230
29717
|
"* Read `@progress.txt` in full.",
|
|
29231
29718
|
"* `@progress.txt` above names the file `progress.txt` at the repo root; the `@` is a reference marker, never part of a path. Do not create or write a file whose name starts with `@`.",
|
|
@@ -29238,7 +29725,7 @@ function buildWrapUpPrompt(branch, planContent, openPullRequest = null, release
|
|
|
29238
29725
|
"* If the merge touched `bun.lock` or any `package.json`, run `bun install --frozen-lockfile` and require it to pass BEFORE pushing. It is the one-second local reproduction of the CI install step, and it catches a lockfile that no longer matches the merged manifests \u2014 the failure mode where every CI job dies at its first step and nothing downstream runs. When it fails, do NOT hand-edit the lockfile: restore the base's copy (`git checkout origin/main -- bun.lock`), run a plain `bun install` so this branch's own dependencies are re-added, and confirm the frozen run then passes.",
|
|
29239
29726
|
...releaseBullets(release),
|
|
29240
29727
|
`* Commit these changes and push them to the CURRENT branch (${branch}). Never create a branch here: the work under review is this branch's, and a second branch splits one plan across two reviews.`,
|
|
29241
|
-
pullRequestStep(branch, openPullRequest),
|
|
29728
|
+
pullRequestStep(branch, base, openPullRequest),
|
|
29242
29729
|
"* Do not include Claude attribution in the commit or PR message.",
|
|
29243
29730
|
...lessonsSection(lessons),
|
|
29244
29731
|
"",
|
|
@@ -29248,15 +29735,15 @@ function buildWrapUpPrompt(branch, planContent, openPullRequest = null, release
|
|
|
29248
29735
|
].join(`
|
|
29249
29736
|
`);
|
|
29250
29737
|
}
|
|
29251
|
-
function
|
|
29738
|
+
function oneLine9(text) {
|
|
29252
29739
|
return text.trim().replace(/\s+/g, " ");
|
|
29253
29740
|
}
|
|
29254
29741
|
function lessonLines(lesson) {
|
|
29255
|
-
const artifact = lesson.artifact === undefined ||
|
|
29742
|
+
const artifact = lesson.artifact === undefined || oneLine9(lesson.artifact) === "" ? "none" : oneLine9(lesson.artifact);
|
|
29256
29743
|
return [
|
|
29257
29744
|
`- \`${lesson.id}\``,
|
|
29258
|
-
` - trigger: ${
|
|
29259
|
-
` - action: ${
|
|
29745
|
+
` - trigger: ${oneLine9(lesson.trigger)}`,
|
|
29746
|
+
` - action: ${oneLine9(lesson.action)}`,
|
|
29260
29747
|
` - artifact: ${artifact}`
|
|
29261
29748
|
];
|
|
29262
29749
|
}
|
|
@@ -29281,8 +29768,8 @@ function lessonsSection(lessons) {
|
|
|
29281
29768
|
"```"
|
|
29282
29769
|
];
|
|
29283
29770
|
}
|
|
29284
|
-
function pullRequestStep(branch, openPullRequest) {
|
|
29285
|
-
return openPullRequest === null ? `* No open PR was found for ${branch}: open one with \`gh pr create\`. If it answers that a PR already exists, push to that PR and update its body with \`gh pr edit\`; never open a second PR from a new branch.` : `* PR #${openPullRequest} is already open for ${branch}, likely opened by the plan's close-out: push to it and update its body with \`gh pr edit ${openPullRequest}\` so the description covers the promotions this session committed.`;
|
|
29771
|
+
function pullRequestStep(branch, base, openPullRequest) {
|
|
29772
|
+
return openPullRequest === null ? `* No open PR was found for ${branch}: open one with \`gh pr create --base ${base}\`. If it answers that a PR already exists, push to that PR and update its body with \`gh pr edit\`; never open a second PR from a new branch.` : `* PR #${openPullRequest} is already open for ${branch}, likely opened by the plan's close-out: push to it and update its body with \`gh pr edit ${openPullRequest}\` so the description covers the promotions this session committed.`;
|
|
29286
29773
|
}
|
|
29287
29774
|
function releaseBullets(release) {
|
|
29288
29775
|
if (release === null)
|
|
@@ -29344,11 +29831,11 @@ async function lessonsToPromote(learning) {
|
|
|
29344
29831
|
return [];
|
|
29345
29832
|
}
|
|
29346
29833
|
}
|
|
29347
|
-
async function preserveProgress(planContent, settingSources, release, serving, learning, checkout) {
|
|
29834
|
+
async function preserveProgress(planContent, settingSources, release, serving, learning, base, checkout) {
|
|
29348
29835
|
const branch = getCurrentBranch(checkout);
|
|
29349
29836
|
const openPullRequest = await openPullRequestNumber(checkout, branch);
|
|
29350
29837
|
return runWrapUpSession({
|
|
29351
|
-
buildPrompt: (lessons) => buildWrapUpPrompt(branch, planContent, openPullRequest, release, lessons),
|
|
29838
|
+
buildPrompt: (lessons) => buildWrapUpPrompt(branch, base, planContent, openPullRequest, release, lessons),
|
|
29352
29839
|
settingSources,
|
|
29353
29840
|
serving,
|
|
29354
29841
|
learning,
|
|
@@ -29402,8 +29889,8 @@ function missingPullRequestBullet(branch, previousMessage) {
|
|
|
29402
29889
|
return [opening, " Its final message follows, quoted:", "", ...quoted3(previousMessage), ""];
|
|
29403
29890
|
}
|
|
29404
29891
|
function buildWrapUpRetryPrompt(retry) {
|
|
29405
|
-
const
|
|
29406
|
-
const [classifierKey, ...rest] =
|
|
29892
|
+
const first = buildWrapUpPrompt(retry.branch, retry.base, retry.planContent, null, retry.release, retry.lessons);
|
|
29893
|
+
const [classifierKey, ...rest] = first.split(`
|
|
29407
29894
|
`);
|
|
29408
29895
|
return [
|
|
29409
29896
|
classifierKey,
|
|
@@ -29413,9 +29900,9 @@ function buildWrapUpRetryPrompt(retry) {
|
|
|
29413
29900
|
`);
|
|
29414
29901
|
}
|
|
29415
29902
|
function retryWrapUp(run) {
|
|
29416
|
-
const { branch, planContent, previousMessage } = run;
|
|
29903
|
+
const { branch, base, planContent, previousMessage } = run;
|
|
29417
29904
|
return runWrapUpSession({
|
|
29418
|
-
buildPrompt: (lessons) => buildWrapUpRetryPrompt({ branch, planContent, release: null, lessons, previousMessage }),
|
|
29905
|
+
buildPrompt: (lessons) => buildWrapUpRetryPrompt({ branch, base, planContent, release: null, lessons, previousMessage }),
|
|
29419
29906
|
settingSources: run.settingSources,
|
|
29420
29907
|
serving: run.serving,
|
|
29421
29908
|
learning: run.learning,
|
|
@@ -29457,8 +29944,9 @@ async function runWrapUp(input) {
|
|
|
29457
29944
|
planStub: planStub2,
|
|
29458
29945
|
planContent
|
|
29459
29946
|
});
|
|
29947
|
+
const base = resolveBaseBranch(createGitRunner(checkout), settings.prBase);
|
|
29460
29948
|
emitLoopEvent({ kind: "wrap-up", phase: "session" });
|
|
29461
|
-
const finalMessage = await preserveProgress(planContent, settingSources, release, serving, wrapUpLearning, checkout);
|
|
29949
|
+
const finalMessage = await preserveProgress(planContent, settingSources, release, serving, wrapUpLearning, base, checkout);
|
|
29462
29950
|
if (activeOutputMode() !== "text") {
|
|
29463
29951
|
const pullRequest = await openPullRequestNumber(checkout, expected2.branch);
|
|
29464
29952
|
emitLoopEvent(pullRequest === null ? { kind: "no-pr", reason: `no open pull request for ${expected2.branch}` } : { kind: "pr", number: pullRequest });
|
|
@@ -29472,13 +29960,14 @@ async function runWrapUp(input) {
|
|
|
29472
29960
|
dir: checkout
|
|
29473
29961
|
});
|
|
29474
29962
|
emitLoopEvent({ kind: "wrap-up", phase: "release" });
|
|
29475
|
-
const finish = await finishRelease({ repoRoot: checkout, settings, preparation: release }, { readProvider });
|
|
29963
|
+
const finish = await finishRelease({ repoRoot: checkout, branch: expected2.branch, settings, preparation: release }, { readProvider });
|
|
29476
29964
|
if (readProvider().provider !== "none") {
|
|
29477
|
-
const delivery = await deliverPullRequest({ branch: expected2.branch, retries: settings.loopWrapUpRetries, previousMessage: finalMessage }, deliverySeamsIn({ ...input, fragment: finish.fragment }));
|
|
29965
|
+
const delivery = await deliverPullRequest({ branch: expected2.branch, retries: settings.loopWrapUpRetries, previousMessage: finalMessage }, deliverySeamsIn({ ...input, base, fragment: finish.fragment }));
|
|
29478
29966
|
if (delivery.kind === "interrupted")
|
|
29479
29967
|
return;
|
|
29480
29968
|
if (delivery.kind === "blocked")
|
|
29481
29969
|
throw new CommandExit(1, delivery.message);
|
|
29970
|
+
await retargetPullRequest(delivery.pull, base, { pulls: ghPullRequestsIn(checkout), output: activeOutput() });
|
|
29482
29971
|
}
|
|
29483
29972
|
if (ciWait) {
|
|
29484
29973
|
emitLoopEvent({ kind: "wrap-up", phase: "ci" });
|
|
@@ -29576,6 +30065,7 @@ function deliverySeamsIn(context) {
|
|
|
29576
30065
|
retry: (previousMessage) => retryWrapUp({
|
|
29577
30066
|
previousMessage,
|
|
29578
30067
|
branch: expected2.branch,
|
|
30068
|
+
base: context.base,
|
|
29579
30069
|
planContent: context.planContent,
|
|
29580
30070
|
settingSources: context.settingSources,
|
|
29581
30071
|
serving: context.serving,
|
|
@@ -29585,7 +30075,7 @@ function deliverySeamsIn(context) {
|
|
|
29585
30075
|
openRunnerPullRequest: async () => {
|
|
29586
30076
|
const runnerInput = runnerPrInputFor({
|
|
29587
30077
|
branch: expected2.branch,
|
|
29588
|
-
base:
|
|
30078
|
+
base: context.base,
|
|
29589
30079
|
planContent: context.planContent,
|
|
29590
30080
|
planStub: context.planStub,
|
|
29591
30081
|
notes: fragmentNotesIn(checkout, context.fragment)
|
|
@@ -29638,7 +30128,7 @@ async function start(args, repoRoot) {
|
|
|
29638
30128
|
return;
|
|
29639
30129
|
let runConfig;
|
|
29640
30130
|
try {
|
|
29641
|
-
runConfig = loadRunConfig({ root: repoRoot, home:
|
|
30131
|
+
runConfig = loadRunConfig({ root: repoRoot, home: homedir9() }, args);
|
|
29642
30132
|
} catch (error) {
|
|
29643
30133
|
if (!(error instanceof ConfigError))
|
|
29644
30134
|
throw error;
|
|
@@ -29669,7 +30159,7 @@ async function start(args, repoRoot) {
|
|
|
29669
30159
|
let expected2 = openCheckoutExpectation({ projectRoot: repoRoot, checkout, branch });
|
|
29670
30160
|
await announceRiskTotal({
|
|
29671
30161
|
repoRoot,
|
|
29672
|
-
home:
|
|
30162
|
+
home: homedir9(),
|
|
29673
30163
|
planPath,
|
|
29674
30164
|
config: runConfig.config,
|
|
29675
30165
|
environment: process.env
|
|
@@ -29694,16 +30184,16 @@ async function start(args, repoRoot) {
|
|
|
29694
30184
|
tiersRafa: runConfig.config.tiersRafa,
|
|
29695
30185
|
tiersSkills: runConfig.config.tiersSkills,
|
|
29696
30186
|
tiersAgents: runConfig.config.tiersAgents,
|
|
29697
|
-
home:
|
|
30187
|
+
home: homedir9()
|
|
29698
30188
|
},
|
|
29699
|
-
sync: { resolved: runConfig, home:
|
|
30189
|
+
sync: { resolved: runConfig, home: homedir9() },
|
|
29700
30190
|
claim: createStartPreflightClaim(repoRoot, runConfig.config),
|
|
29701
30191
|
drift: createStartPreflightDrift(repoRoot, runConfig.config)
|
|
29702
30192
|
});
|
|
29703
|
-
const serving = { root: repoRoot, run: session.id, home:
|
|
30193
|
+
const serving = { root: repoRoot, run: session.id, home: homedir9(), settings: runConfig.config };
|
|
29704
30194
|
const learning = {
|
|
29705
30195
|
kind: runConfig.config.learningAdapter,
|
|
29706
|
-
home:
|
|
30196
|
+
home: homedir9(),
|
|
29707
30197
|
blessMinConfidence: runConfig.config.learningBlessMinConfidence
|
|
29708
30198
|
};
|
|
29709
30199
|
const handout = {
|
|
@@ -29719,7 +30209,7 @@ async function start(args, repoRoot) {
|
|
|
29719
30209
|
};
|
|
29720
30210
|
const hubContact = createHubContact({
|
|
29721
30211
|
root: repoRoot,
|
|
29722
|
-
home:
|
|
30212
|
+
home: homedir9(),
|
|
29723
30213
|
resolved: runConfig,
|
|
29724
30214
|
warn: (message) => activeOutput().warn(message),
|
|
29725
30215
|
sessionId: session.id
|
|
@@ -29798,9 +30288,10 @@ async function start(args, repoRoot) {
|
|
|
29798
30288
|
inject: injectMode,
|
|
29799
30289
|
repoRoot,
|
|
29800
30290
|
checkout,
|
|
29801
|
-
home:
|
|
30291
|
+
home: homedir9(),
|
|
29802
30292
|
settingSources,
|
|
29803
30293
|
knownMissing,
|
|
30294
|
+
inherited: runStartFailures(trackerPath),
|
|
29804
30295
|
serving,
|
|
29805
30296
|
handout,
|
|
29806
30297
|
base
|
|
@@ -29895,7 +30386,7 @@ function buildBar(pct, width = 20) {
|
|
|
29895
30386
|
|
|
29896
30387
|
// src/plan.ts
|
|
29897
30388
|
import fs4 from "fs";
|
|
29898
|
-
import { homedir as
|
|
30389
|
+
import { homedir as homedir10 } from "os";
|
|
29899
30390
|
import path8 from "path";
|
|
29900
30391
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
29901
30392
|
|
|
@@ -30705,7 +31196,7 @@ function resolvePlanConfig(repoRoot, home) {
|
|
|
30705
31196
|
}
|
|
30706
31197
|
}
|
|
30707
31198
|
async function plan(args, repoRoot, registry = CORE_ADAPTER_REGISTRY) {
|
|
30708
|
-
const home =
|
|
31199
|
+
const home = homedir10();
|
|
30709
31200
|
const config = resolvePlanConfig(repoRoot, home);
|
|
30710
31201
|
const {
|
|
30711
31202
|
settingSources,
|