@oscharko-dev/keiko-workflows 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -0
- package/dist/bug-investigation/context.d.ts +7 -0
- package/dist/bug-investigation/context.d.ts.map +1 -0
- package/dist/bug-investigation/context.js +119 -0
- package/dist/bug-investigation/descriptor.d.ts +4 -0
- package/dist/bug-investigation/descriptor.d.ts.map +1 -0
- package/dist/bug-investigation/descriptor.js +46 -0
- package/dist/bug-investigation/emit.d.ts +13 -0
- package/dist/bug-investigation/emit.d.ts.map +1 -0
- package/dist/bug-investigation/emit.js +35 -0
- package/dist/bug-investigation/events.d.ts +2 -0
- package/dist/bug-investigation/events.d.ts.map +1 -0
- package/dist/bug-investigation/events.js +6 -0
- package/dist/bug-investigation/failure-parse.d.ts +4 -0
- package/dist/bug-investigation/failure-parse.d.ts.map +1 -0
- package/dist/bug-investigation/failure-parse.js +154 -0
- package/dist/bug-investigation/guard.d.ts +3 -0
- package/dist/bug-investigation/guard.d.ts.map +1 -0
- package/dist/bug-investigation/guard.js +69 -0
- package/dist/bug-investigation/index.d.ts +8 -0
- package/dist/bug-investigation/index.d.ts.map +1 -0
- package/dist/bug-investigation/index.js +13 -0
- package/dist/bug-investigation/internal.d.ts +39 -0
- package/dist/bug-investigation/internal.d.ts.map +1 -0
- package/dist/bug-investigation/internal.js +65 -0
- package/dist/bug-investigation/memory.d.ts +5 -0
- package/dist/bug-investigation/memory.d.ts.map +1 -0
- package/dist/bug-investigation/memory.js +91 -0
- package/dist/bug-investigation/model-loop.d.ts +5 -0
- package/dist/bug-investigation/model-loop.d.ts.map +1 -0
- package/dist/bug-investigation/model-loop.js +225 -0
- package/dist/bug-investigation/parse.d.ts +4 -0
- package/dist/bug-investigation/parse.d.ts.map +1 -0
- package/dist/bug-investigation/parse.js +125 -0
- package/dist/bug-investigation/prompt.d.ts +5 -0
- package/dist/bug-investigation/prompt.d.ts.map +1 -0
- package/dist/bug-investigation/prompt.js +122 -0
- package/dist/bug-investigation/report.d.ts +24 -0
- package/dist/bug-investigation/report.d.ts.map +1 -0
- package/dist/bug-investigation/report.js +151 -0
- package/dist/bug-investigation/stages.d.ts +14 -0
- package/dist/bug-investigation/stages.d.ts.map +1 -0
- package/dist/bug-investigation/stages.js +247 -0
- package/dist/bug-investigation/types.d.ts +88 -0
- package/dist/bug-investigation/types.d.ts.map +1 -0
- package/dist/bug-investigation/types.js +6 -0
- package/dist/bug-investigation/verify-stage.d.ts +11 -0
- package/dist/bug-investigation/verify-stage.d.ts.map +1 -0
- package/dist/bug-investigation/verify-stage.js +91 -0
- package/dist/bug-investigation/workflow.d.ts +3 -0
- package/dist/bug-investigation/workflow.d.ts.map +1 -0
- package/dist/bug-investigation/workflow.js +85 -0
- package/dist/contextpack/assemble.d.ts +35 -0
- package/dist/contextpack/assemble.d.ts.map +1 -0
- package/dist/contextpack/assemble.js +431 -0
- package/dist/contextpack/compaction.d.ts +23 -0
- package/dist/contextpack/compaction.d.ts.map +1 -0
- package/dist/contextpack/compaction.js +68 -0
- package/dist/contextpack/index.d.ts +9 -0
- package/dist/contextpack/index.d.ts.map +1 -0
- package/dist/contextpack/index.js +8 -0
- package/dist/contextpack/microIndex.d.ts +29 -0
- package/dist/contextpack/microIndex.d.ts.map +1 -0
- package/dist/contextpack/microIndex.js +98 -0
- package/dist/contextpack/reranker.d.ts +15 -0
- package/dist/contextpack/reranker.d.ts.map +1 -0
- package/dist/contextpack/reranker.js +31 -0
- package/dist/descriptor.d.ts +2 -0
- package/dist/descriptor.d.ts.map +1 -0
- package/dist/descriptor.js +1 -0
- package/dist/governed-handoff.d.ts +6 -0
- package/dist/governed-handoff.d.ts.map +1 -0
- package/dist/governed-handoff.js +86 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/planner/anchors.d.ts +17 -0
- package/dist/planner/anchors.d.ts.map +1 -0
- package/dist/planner/anchors.js +291 -0
- package/dist/planner/explorationPlanner.d.ts +9 -0
- package/dist/planner/explorationPlanner.d.ts.map +1 -0
- package/dist/planner/explorationPlanner.js +15 -0
- package/dist/planner/governor.d.ts +16 -0
- package/dist/planner/governor.d.ts.map +1 -0
- package/dist/planner/governor.js +106 -0
- package/dist/planner/index.d.ts +11 -0
- package/dist/planner/index.d.ts.map +1 -0
- package/dist/planner/index.js +8 -0
- package/dist/planner/intent.d.ts +8 -0
- package/dist/planner/intent.d.ts.map +1 -0
- package/dist/planner/intent.js +140 -0
- package/dist/planner/plan.d.ts +43 -0
- package/dist/planner/plan.d.ts.map +1 -0
- package/dist/planner/plan.js +237 -0
- package/dist/promptEnhancer/index.d.ts +23 -0
- package/dist/promptEnhancer/index.d.ts.map +1 -0
- package/dist/promptEnhancer/index.js +282 -0
- package/dist/qualityIntelligence/__tests__/fixtures/runEntryFixtures.d.ts +30 -0
- package/dist/qualityIntelligence/__tests__/fixtures/runEntryFixtures.d.ts.map +1 -0
- package/dist/qualityIntelligence/__tests__/fixtures/runEntryFixtures.js +114 -0
- package/dist/qualityIntelligence/cancellation.d.ts +20 -0
- package/dist/qualityIntelligence/cancellation.d.ts.map +1 -0
- package/dist/qualityIntelligence/cancellation.js +55 -0
- package/dist/qualityIntelligence/descriptors.d.ts +41 -0
- package/dist/qualityIntelligence/descriptors.d.ts.map +1 -0
- package/dist/qualityIntelligence/descriptors.js +105 -0
- package/dist/qualityIntelligence/index.d.ts +11 -0
- package/dist/qualityIntelligence/index.d.ts.map +1 -0
- package/dist/qualityIntelligence/index.js +11 -0
- package/dist/qualityIntelligence/modelRoutedTestDesign.d.ts +100 -0
- package/dist/qualityIntelligence/modelRoutedTestDesign.d.ts.map +1 -0
- package/dist/qualityIntelligence/modelRoutedTestDesign.js +620 -0
- package/dist/qualityIntelligence/runEntries.d.ts +60 -0
- package/dist/qualityIntelligence/runEntries.d.ts.map +1 -0
- package/dist/qualityIntelligence/runEntries.js +243 -0
- package/dist/qualityIntelligence/runtimeCommon.d.ts +106 -0
- package/dist/qualityIntelligence/runtimeCommon.d.ts.map +1 -0
- package/dist/qualityIntelligence/runtimeCommon.js +258 -0
- package/dist/qualityIntelligence/scopedRegeneration.d.ts +26 -0
- package/dist/qualityIntelligence/scopedRegeneration.d.ts.map +1 -0
- package/dist/qualityIntelligence/scopedRegeneration.js +35 -0
- package/dist/ranking/filter.d.ts +20 -0
- package/dist/ranking/filter.d.ts.map +1 -0
- package/dist/ranking/filter.js +99 -0
- package/dist/ranking/index.d.ts +9 -0
- package/dist/ranking/index.d.ts.map +1 -0
- package/dist/ranking/index.js +8 -0
- package/dist/ranking/rank.d.ts +21 -0
- package/dist/ranking/rank.d.ts.map +1 -0
- package/dist/ranking/rank.js +160 -0
- package/dist/ranking/scoring.d.ts +13 -0
- package/dist/ranking/scoring.d.ts.map +1 -0
- package/dist/ranking/scoring.js +39 -0
- package/dist/ranking/signals.d.ts +20 -0
- package/dist/ranking/signals.d.ts.map +1 -0
- package/dist/ranking/signals.js +145 -0
- package/dist/unit-tests/context.d.ts +7 -0
- package/dist/unit-tests/context.d.ts.map +1 -0
- package/dist/unit-tests/context.js +129 -0
- package/dist/unit-tests/conventions.d.ts +5 -0
- package/dist/unit-tests/conventions.d.ts.map +1 -0
- package/dist/unit-tests/conventions.js +87 -0
- package/dist/unit-tests/descriptor.d.ts +5 -0
- package/dist/unit-tests/descriptor.d.ts.map +1 -0
- package/dist/unit-tests/descriptor.js +43 -0
- package/dist/unit-tests/emit.d.ts +13 -0
- package/dist/unit-tests/emit.d.ts.map +1 -0
- package/dist/unit-tests/emit.js +35 -0
- package/dist/unit-tests/events.d.ts +2 -0
- package/dist/unit-tests/events.d.ts.map +1 -0
- package/dist/unit-tests/events.js +6 -0
- package/dist/unit-tests/frontend.d.ts +42 -0
- package/dist/unit-tests/frontend.d.ts.map +1 -0
- package/dist/unit-tests/frontend.js +281 -0
- package/dist/unit-tests/index.d.ts +9 -0
- package/dist/unit-tests/index.d.ts.map +1 -0
- package/dist/unit-tests/index.js +15 -0
- package/dist/unit-tests/internal.d.ts +36 -0
- package/dist/unit-tests/internal.d.ts.map +1 -0
- package/dist/unit-tests/internal.js +43 -0
- package/dist/unit-tests/model-loop.d.ts +6 -0
- package/dist/unit-tests/model-loop.d.ts.map +1 -0
- package/dist/unit-tests/model-loop.js +98 -0
- package/dist/unit-tests/parse.d.ts +7 -0
- package/dist/unit-tests/parse.d.ts.map +1 -0
- package/dist/unit-tests/parse.js +68 -0
- package/dist/unit-tests/prompt.d.ts +6 -0
- package/dist/unit-tests/prompt.d.ts.map +1 -0
- package/dist/unit-tests/prompt.js +139 -0
- package/dist/unit-tests/report.d.ts +26 -0
- package/dist/unit-tests/report.d.ts.map +1 -0
- package/dist/unit-tests/report.js +104 -0
- package/dist/unit-tests/stages.d.ts +12 -0
- package/dist/unit-tests/stages.d.ts.map +1 -0
- package/dist/unit-tests/stages.js +202 -0
- package/dist/unit-tests/strategy.d.ts +6 -0
- package/dist/unit-tests/strategy.d.ts.map +1 -0
- package/dist/unit-tests/strategy.js +36 -0
- package/dist/unit-tests/target-guard.d.ts +5 -0
- package/dist/unit-tests/target-guard.d.ts.map +1 -0
- package/dist/unit-tests/target-guard.js +29 -0
- package/dist/unit-tests/types.d.ts +74 -0
- package/dist/unit-tests/types.d.ts.map +1 -0
- package/dist/unit-tests/types.js +6 -0
- package/dist/unit-tests/verify-stage.d.ts +10 -0
- package/dist/unit-tests/verify-stage.d.ts.map +1 -0
- package/dist/unit-tests/verify-stage.js +56 -0
- package/dist/unit-tests/workflow.d.ts +3 -0
- package/dist/unit-tests/workflow.d.ts.map +1 -0
- package/dist/unit-tests/workflow.js +69 -0
- package/package.json +38 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// Failure-output parsing (ADR-0009 D7, NEW seam). Extracts candidate source frames and short
|
|
2
|
+
// error/assertion messages from a bug report's failingOutput + stackTrace, and merges the
|
|
3
|
+
// developer-provided targetFiles as line-less seed frames. The extracted frames are VERIFIED FACTS
|
|
4
|
+
// (what the tool parsed, not a model claim) and seed both context selection (D8) and the report.
|
|
5
|
+
//
|
|
6
|
+
// SECURITY (CodeQL js/polynomial-redos, steering note F): failure output is attacker-influenceable
|
|
7
|
+
// (a failing test can print arbitrary text), so this parser uses ONLY bounded, line-oriented string
|
|
8
|
+
// ops — split('\n'), indexOf/lastIndexOf, slice, a right-split on ':', and an all-digit check. The
|
|
9
|
+
// single regex used (ALL_DIGITS) is a bounded character class with NO nested quantifiers and NO
|
|
10
|
+
// `.*` alternation, so there is no super-linear backtracking surface. Line count and per-line work
|
|
11
|
+
// are both capped. Pure: no IO, no clock, no RNG.
|
|
12
|
+
// Caps that bound total work regardless of input size.
|
|
13
|
+
const MAX_LINES_SCANNED = 2_000;
|
|
14
|
+
export const MAX_FRAMES = 25;
|
|
15
|
+
const MAX_MESSAGES = 10;
|
|
16
|
+
const MAX_MESSAGE_LENGTH = 200;
|
|
17
|
+
const ALL_DIGITS = /^[0-9]+$/;
|
|
18
|
+
const FILE_URL_PREFIX = "file://";
|
|
19
|
+
const MESSAGE_MARKERS = [
|
|
20
|
+
"assertionerror",
|
|
21
|
+
"error:",
|
|
22
|
+
"expected",
|
|
23
|
+
"typeerror",
|
|
24
|
+
"referenceerror",
|
|
25
|
+
"✕",
|
|
26
|
+
"×",
|
|
27
|
+
"fail",
|
|
28
|
+
"●",
|
|
29
|
+
];
|
|
30
|
+
function toPosix(value) {
|
|
31
|
+
return value.split("\\").join("/");
|
|
32
|
+
}
|
|
33
|
+
// Parses a numeric line number from a token, or undefined when the token is not all-digits.
|
|
34
|
+
function toLine(token) {
|
|
35
|
+
if (token === undefined || token.length === 0 || !ALL_DIGITS.test(token)) {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
return Number(token);
|
|
39
|
+
}
|
|
40
|
+
// Strips a leading `file://` URL prefix from a location token. `file:///repo/x.ts` -> `/repo/x.ts`.
|
|
41
|
+
function stripFileUrl(location) {
|
|
42
|
+
if (!location.startsWith(FILE_URL_PREFIX)) {
|
|
43
|
+
return location;
|
|
44
|
+
}
|
|
45
|
+
const afterScheme = location.slice(FILE_URL_PREFIX.length);
|
|
46
|
+
// file:///path keeps the leading slash of the absolute path; file://host/path is not expected
|
|
47
|
+
// from runtimes here, so we keep everything after the scheme verbatim.
|
|
48
|
+
return afterScheme;
|
|
49
|
+
}
|
|
50
|
+
// Peels `:line:col` off the END of a location token using a right-split, returning the file path
|
|
51
|
+
// and the numeric line (when present). `src/x.ts:3:10` -> { file: "src/x.ts", line: 3 }. A token
|
|
52
|
+
// with no numeric `:line` segment yields no frame.
|
|
53
|
+
function peelLocation(rawLocation) {
|
|
54
|
+
const location = stripFileUrl(rawLocation.trim());
|
|
55
|
+
const lastColon = location.lastIndexOf(":");
|
|
56
|
+
if (lastColon <= 0) {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
const beforeCol = location.slice(0, lastColon);
|
|
60
|
+
const lineColon = beforeCol.lastIndexOf(":");
|
|
61
|
+
// Case `file:line:col`: peel col then line.
|
|
62
|
+
const lineToken = lineColon <= 0 ? undefined : beforeCol.slice(lineColon + 1);
|
|
63
|
+
const line = toLine(lineToken);
|
|
64
|
+
if (line !== undefined) {
|
|
65
|
+
const file = toPosix(beforeCol.slice(0, lineColon));
|
|
66
|
+
return file.length === 0 ? undefined : { file, line };
|
|
67
|
+
}
|
|
68
|
+
// Case `file:line` (no col): the token after the last colon is the line.
|
|
69
|
+
const lineOnly = toLine(location.slice(lastColon + 1));
|
|
70
|
+
if (lineOnly !== undefined) {
|
|
71
|
+
const file = toPosix(beforeCol);
|
|
72
|
+
return file.length === 0 ? undefined : { file, line: lineOnly };
|
|
73
|
+
}
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
// Extracts the location token from a stack-frame line. Handles `at fn (loc)`, `at loc`, and a bare
|
|
77
|
+
// `loc` line, all via plain indexOf/slice (no regex).
|
|
78
|
+
function locationToken(line) {
|
|
79
|
+
const trimmed = line.trim();
|
|
80
|
+
const open = trimmed.lastIndexOf("(");
|
|
81
|
+
if (open !== -1) {
|
|
82
|
+
const close = trimmed.indexOf(")", open + 1);
|
|
83
|
+
if (close !== -1) {
|
|
84
|
+
return trimmed.slice(open + 1, close);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const at = "at ";
|
|
88
|
+
if (trimmed.startsWith(at)) {
|
|
89
|
+
return trimmed.slice(at.length).trim();
|
|
90
|
+
}
|
|
91
|
+
return trimmed;
|
|
92
|
+
}
|
|
93
|
+
function isMessageLine(lower) {
|
|
94
|
+
return MESSAGE_MARKERS.some((marker) => lower.includes(marker));
|
|
95
|
+
}
|
|
96
|
+
function pushFrame(acc, frame) {
|
|
97
|
+
const key = `${frame.file}:${frame.line === undefined ? "" : String(frame.line)}`;
|
|
98
|
+
if (acc.seen.has(key) || acc.frames.length >= MAX_FRAMES) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
acc.seen.add(key);
|
|
102
|
+
acc.frames.push(frame);
|
|
103
|
+
}
|
|
104
|
+
function pushMessage(acc, line) {
|
|
105
|
+
if (acc.messages.length >= MAX_MESSAGES) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
acc.messages.push(line.trim().slice(0, MAX_MESSAGE_LENGTH));
|
|
109
|
+
}
|
|
110
|
+
function scanLine(acc, line) {
|
|
111
|
+
const token = locationToken(line);
|
|
112
|
+
const frame = token === undefined ? undefined : peelLocation(token);
|
|
113
|
+
if (frame !== undefined) {
|
|
114
|
+
pushFrame(acc, frame);
|
|
115
|
+
}
|
|
116
|
+
if (isMessageLine(line.toLowerCase())) {
|
|
117
|
+
pushMessage(acc, line);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function scanText(acc, text) {
|
|
121
|
+
if (text === undefined) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
let start = 0;
|
|
125
|
+
let scanned = 0;
|
|
126
|
+
while (scanned < MAX_LINES_SCANNED && start <= text.length) {
|
|
127
|
+
const newline = text.indexOf("\n", start);
|
|
128
|
+
const end = newline === -1 ? text.length : newline;
|
|
129
|
+
scanLine(acc, text.slice(start, end));
|
|
130
|
+
scanned += 1;
|
|
131
|
+
if (newline === -1) {
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
start = newline + 1;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function mergeTargetFiles(acc, targetFiles) {
|
|
138
|
+
if (targetFiles === undefined) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
for (const raw of targetFiles) {
|
|
142
|
+
const file = toPosix(raw.trim());
|
|
143
|
+
if (file.length > 0) {
|
|
144
|
+
pushFrame(acc, { file, line: undefined });
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
export function parseFailureEvidence(report) {
|
|
149
|
+
const acc = { frames: [], messages: [], seen: new Set() };
|
|
150
|
+
scanText(acc, report.failingOutput);
|
|
151
|
+
scanText(acc, report.stackTrace);
|
|
152
|
+
mergeTargetFiles(acc, report.targetFiles);
|
|
153
|
+
return { frames: acc.frames, messages: acc.messages };
|
|
154
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../../src/bug-investigation/guard.ts"],"names":[],"mappings":"AAwDA,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAUxD;AAKD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAM7D"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// The bug-fix scope guard's path predicates (ADR-0009 D6). A bug fix legitimately edits production
|
|
2
|
+
// source, so #8's test-files-only guard does NOT apply. Instead this module provides two pure
|
|
3
|
+
// predicates that bound prompt-injection blast radius WITHOUT modifying #6:
|
|
4
|
+
// - isSensitivePath: reject traversal/absolute (fail-closed), .github/, .husky/, and lockfiles —
|
|
5
|
+
// paths #6's deny-list does NOT cover but that a prompt-injected "fix" must never touch.
|
|
6
|
+
// - isElevatedReviewPath: manifest/config edits are ALLOWED but surfaced for elevated review.
|
|
7
|
+
// The change-budget half of D6 is enforced via the #6 PatchLimits override seam (in model-loop.ts).
|
|
8
|
+
//
|
|
9
|
+
// SECURITY (CodeQL js/polynomial-redos): ALL checks use plain string ops (split, startsWith,
|
|
10
|
+
// equality, toLowerCase) — ZERO regex — so there is no ReDoS surface. Checks 2-4 are case-
|
|
11
|
+
// insensitive (matching #6 isDenied) so a case-only variant cannot bypass the guard on
|
|
12
|
+
// case-insensitive filesystems (macOS/Windows); the traversal check is case-invariant by nature.
|
|
13
|
+
const LOCKFILE_BASENAMES = [
|
|
14
|
+
"package-lock.json",
|
|
15
|
+
"npm-shrinkwrap.json",
|
|
16
|
+
"yarn.lock",
|
|
17
|
+
"pnpm-lock.yaml",
|
|
18
|
+
];
|
|
19
|
+
const SENSITIVE_DIRS = [".github", ".husky"];
|
|
20
|
+
function toPosix(relPath) {
|
|
21
|
+
return relPath.split("\\").join("/");
|
|
22
|
+
}
|
|
23
|
+
// Copies #8's isTraversal logic EXACTLY: an absolute leading slash or any `..` segment can resolve
|
|
24
|
+
// to a file OUTSIDE the apparent location after #6 resolveWithinWorkspace collapses it. Rejected
|
|
25
|
+
// fail-closed BEFORE the case-folded checks so the guarded path matches what #6 would write.
|
|
26
|
+
function isTraversal(posixPath) {
|
|
27
|
+
return posixPath.startsWith("/") || posixPath.split("/").includes("..");
|
|
28
|
+
}
|
|
29
|
+
function basename(posixPath) {
|
|
30
|
+
const slash = posixPath.lastIndexOf("/");
|
|
31
|
+
return slash === -1 ? posixPath : posixPath.slice(slash + 1);
|
|
32
|
+
}
|
|
33
|
+
function underSensitiveDir(lower) {
|
|
34
|
+
return SENSITIVE_DIRS.some((dir) => lower === dir || lower.startsWith(`${dir}/`));
|
|
35
|
+
}
|
|
36
|
+
// Drops `.` and empty ("//") segments so the guard sees the SAME form #6 resolveWithinWorkspace
|
|
37
|
+
// collapses to. Without this, `./.husky/pre-commit` and `.//.github/x` slip past the dir/basename
|
|
38
|
+
// checks (they don't literally start with `.github/`/`.husky/`) yet #6 writes the real protected
|
|
39
|
+
// file (security fix C1). Run only AFTER isTraversal has fail-closed `..`/leading-`/` on the raw
|
|
40
|
+
// path. Pure string ops — no regex.
|
|
41
|
+
function normalizePosix(posixPath) {
|
|
42
|
+
return posixPath
|
|
43
|
+
.split("/")
|
|
44
|
+
.filter((segment) => segment !== "" && segment !== ".")
|
|
45
|
+
.join("/");
|
|
46
|
+
}
|
|
47
|
+
// The sensitive-path guard (D6 bound 2). Returns true when the path must be rejected as
|
|
48
|
+
// out-of-scope. Manifest/config edits are NOT sensitive (see isElevatedReviewPath).
|
|
49
|
+
export function isSensitivePath(relPath) {
|
|
50
|
+
const posixPath = toPosix(relPath);
|
|
51
|
+
if (isTraversal(posixPath)) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
const lower = normalizePosix(posixPath).toLowerCase();
|
|
55
|
+
if (underSensitiveDir(lower)) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
return LOCKFILE_BASENAMES.includes(basename(lower));
|
|
59
|
+
}
|
|
60
|
+
// Manifest/config edits a fix may legitimately need. ALLOWED, but flagged so the report surfaces
|
|
61
|
+
// them as an elevated-review item. A pure basename predicate (case-insensitive). Normalizes `./`
|
|
62
|
+
// and `//` segments first so a `./package.json` form is flagged identically to `package.json`.
|
|
63
|
+
export function isElevatedReviewPath(relPath) {
|
|
64
|
+
const base = basename(normalizePosix(toPosix(relPath)).toLowerCase());
|
|
65
|
+
if (base === "package.json") {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
return base.startsWith("tsconfig") && base.endsWith(".json");
|
|
69
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { investigateBug } from "./workflow.js";
|
|
2
|
+
export { assembleBugReport, renderBugMarkdownReport, type BugReportParts } from "./report.js";
|
|
3
|
+
export { BUG_INVESTIGATION_WORKFLOW_DESCRIPTOR } from "./descriptor.js";
|
|
4
|
+
export { isSensitivePath, isElevatedReviewPath } from "./guard.js";
|
|
5
|
+
export { parseFailureEvidence, MAX_FRAMES } from "./failure-parse.js";
|
|
6
|
+
export { DEFAULT_BUG_WORKFLOW_LIMITS, type BugInvestigationInput, type BugInvestigationDeps, type BugInvestigationReport, type BugReportInput, type BugWorkflowLimits, type BugWorkflowStatus, type ChangedFile, type FailureEvidence, type FailureFrame, type Hypothesis, type ParsedBugOutput, type VerifiedFindings, } from "./types.js";
|
|
7
|
+
export type { BugContextSelectedEvent, BugInvestigationCompletedEvent, BugInvestigationEvent, BugInvestigationFailedEvent, BugInvestigationStartedEvent, BugModelCallCompletedEvent, BugModelCallStartedEvent, BugPatchAppliedEvent, BugPatchValidatedEvent, BugVerificationResultEvent, BugWorkflowEventSink, FailureParsedEvent, RootCauseProposedEvent, } from "./events.js";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bug-investigation/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAE9F,OAAO,EAAE,qCAAqC,EAAE,MAAM,iBAAiB,CAAC;AAExE,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEnE,OAAO,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEtE,OAAO,EACL,2BAA2B,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,gBAAgB,GACtB,MAAM,YAAY,CAAC;AAEpB,YAAY,EACV,uBAAuB,EACvB,8BAA8B,EAC9B,qBAAqB,EACrB,2BAA2B,EAC3B,4BAA4B,EAC5B,0BAA0B,EAC1B,wBAAwB,EACxB,oBAAoB,EACpB,sBAAsB,EACtB,0BAA0B,EAC1B,oBAAoB,EACpB,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Public barrel for the bug-investigation workflow (ADR-0009 D1). Re-exports the single entry
|
|
2
|
+
// (investigateBug), the static UI descriptor, the Markdown renderer, the BugInvestigationEvent
|
|
3
|
+
// family, and all public types. Internal pipeline modules (internal, model-loop, verify-stage,
|
|
4
|
+
// stages, emit, parse, context, prompt) are NOT re-exported — they are implementation detail. The
|
|
5
|
+
// shared WorkflowDescriptor/WorkflowInputSpec types are intentionally NOT re-exported here (the top
|
|
6
|
+
// workflows barrel exposes them exactly once from ./descriptor.js, ADR-0009 D12). Explicit named
|
|
7
|
+
// re-exports, `type` keyword for type-only, double quotes, `.js`.
|
|
8
|
+
export { investigateBug } from "./workflow.js";
|
|
9
|
+
export { assembleBugReport, renderBugMarkdownReport } from "./report.js";
|
|
10
|
+
export { BUG_INVESTIGATION_WORKFLOW_DESCRIPTOR } from "./descriptor.js";
|
|
11
|
+
export { isSensitivePath, isElevatedReviewPath } from "./guard.js";
|
|
12
|
+
export { parseFailureEvidence, MAX_FRAMES } from "./failure-parse.js";
|
|
13
|
+
export { DEFAULT_BUG_WORKFLOW_LIMITS, } from "./types.js";
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { PatchLimits, PatchValidation } from "@oscharko-dev/keiko-tools";
|
|
2
|
+
import { type BugEventEmitter } from "./emit.js";
|
|
3
|
+
import { type BugInvestigationDeps, type BugInvestigationInput, type BugWorkflowLimits, type Hypothesis } from "./types.js";
|
|
4
|
+
import type { BugWorkflowEventSink } from "./events.js";
|
|
5
|
+
export declare const NO_OP_SINK: BugWorkflowEventSink;
|
|
6
|
+
export interface BugWorkflowProgress {
|
|
7
|
+
modelCallCount: number;
|
|
8
|
+
patchRetryCount: number;
|
|
9
|
+
}
|
|
10
|
+
export interface BugRunState {
|
|
11
|
+
readonly input: BugInvestigationInput;
|
|
12
|
+
readonly deps: BugInvestigationDeps;
|
|
13
|
+
readonly limits: BugWorkflowLimits;
|
|
14
|
+
readonly signal: AbortSignal;
|
|
15
|
+
readonly now: () => number;
|
|
16
|
+
readonly emitter: BugEventEmitter;
|
|
17
|
+
readonly startedAt: number;
|
|
18
|
+
readonly progress: BugWorkflowProgress;
|
|
19
|
+
memoryPromptText: string | undefined;
|
|
20
|
+
}
|
|
21
|
+
export interface AcceptedBugPatch {
|
|
22
|
+
readonly diff: string;
|
|
23
|
+
readonly validation: PatchValidation;
|
|
24
|
+
readonly hypothesis: Hypothesis;
|
|
25
|
+
}
|
|
26
|
+
export interface BugModelLoopResult {
|
|
27
|
+
readonly accepted: AcceptedBugPatch | undefined;
|
|
28
|
+
readonly investigationOnly: Hypothesis | undefined;
|
|
29
|
+
readonly modelCallCount: number;
|
|
30
|
+
readonly patchRetryCount: number;
|
|
31
|
+
readonly lastRejectionCode: string | undefined;
|
|
32
|
+
}
|
|
33
|
+
export declare const EMPTY_BUG_LOOP: BugModelLoopResult;
|
|
34
|
+
export declare function resolveBugLimits(input: BugInvestigationInput): BugWorkflowLimits;
|
|
35
|
+
export declare function patchLimitsFrom(limits: BugWorkflowLimits): PatchLimits;
|
|
36
|
+
export declare function buildBugRunState(input: BugInvestigationInput, deps: BugInvestigationDeps, fingerprint: string): BugRunState;
|
|
37
|
+
export declare function nextActionsFor(applied: boolean, files: readonly string[], elevated: readonly string[]): readonly string[];
|
|
38
|
+
export declare function investigationNextActions(): readonly string[];
|
|
39
|
+
//# sourceMappingURL=internal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../src/bug-investigation/internal.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC9E,OAAO,EAAyB,KAAK,eAAe,EAAE,MAAM,WAAW,CAAC;AACxE,OAAO,EAEL,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,UAAU,EAChB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGxD,eAAO,MAAM,UAAU,EAAE,oBAAsD,CAAC;AAEhF,MAAM,WAAW,mBAAmB;IAClC,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;CACzB;AAMD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,qBAAqB,CAAC;IACtC,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC;IACvC,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC;AAGD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC;IACrC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;CACjC;AAED,MAAM,WAAW,kBAAkB;IAEjC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,GAAG,SAAS,CAAC;IAEhD,QAAQ,CAAC,iBAAiB,EAAE,UAAU,GAAG,SAAS,CAAC;IACnD,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC;CAChD;AAGD,eAAO,MAAM,cAAc,EAAE,kBAM5B,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,iBAAiB,CAEhF;AAID,wBAAgB,eAAe,CAAC,MAAM,EAAE,iBAAiB,GAAG,WAAW,CAMtE;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,qBAAqB,EAC5B,IAAI,EAAE,oBAAoB,EAC1B,WAAW,EAAE,MAAM,GAClB,WAAW,CAcb;AAID,wBAAgB,cAAc,CAC5B,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,SAAS,MAAM,EAAE,CAYnB;AAGD,wBAAgB,wBAAwB,IAAI,SAAS,MAAM,EAAE,CAK5D"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Shared internal types and small pure helpers used across the bug-investigation pipeline stages
|
|
2
|
+
// (the model loop, the verify stage, the report stages). Kept private to the module — none of these
|
|
3
|
+
// are re-exported from index.ts. Splitting them out keeps each pipeline file under the LOC limit
|
|
4
|
+
// while leaving a single source of truth for the resolved BugRunState and the loop result shape.
|
|
5
|
+
import { createBugEventEmitter } from "./emit.js";
|
|
6
|
+
import { DEFAULT_BUG_WORKFLOW_LIMITS, } from "./types.js";
|
|
7
|
+
// A no-op sink used when the caller injects none. emit is synchronous (ADR-0004 EventSink contract).
|
|
8
|
+
export const NO_OP_SINK = { emit: () => undefined };
|
|
9
|
+
// The zero-progress loop used to assemble a cancelled/failed report before the model loop ran.
|
|
10
|
+
export const EMPTY_BUG_LOOP = {
|
|
11
|
+
accepted: undefined,
|
|
12
|
+
investigationOnly: undefined,
|
|
13
|
+
modelCallCount: 0,
|
|
14
|
+
patchRetryCount: 0,
|
|
15
|
+
lastRejectionCode: undefined,
|
|
16
|
+
};
|
|
17
|
+
export function resolveBugLimits(input) {
|
|
18
|
+
return { ...DEFAULT_BUG_WORKFLOW_LIMITS, ...input.limits };
|
|
19
|
+
}
|
|
20
|
+
// The #6 PatchLimits view derived from the resolved workflow limits (D6 bound 1). Passed into
|
|
21
|
+
// validatePatch/applyPatch via their `limits` override seam — #6's defaults stay untouched.
|
|
22
|
+
export function patchLimitsFrom(limits) {
|
|
23
|
+
return {
|
|
24
|
+
maxFilesChanged: limits.maxFilesChanged,
|
|
25
|
+
maxChangedLines: limits.maxChangedLines,
|
|
26
|
+
maxPatchBytes: limits.maxPatchBytes,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export function buildBugRunState(input, deps, fingerprint) {
|
|
30
|
+
const now = deps.now ?? Date.now;
|
|
31
|
+
const idSource = deps.idSource ?? (() => crypto.randomUUID());
|
|
32
|
+
return {
|
|
33
|
+
input,
|
|
34
|
+
deps,
|
|
35
|
+
limits: resolveBugLimits(input),
|
|
36
|
+
signal: deps.signal ?? new AbortController().signal,
|
|
37
|
+
now,
|
|
38
|
+
emitter: createBugEventEmitter(deps.sink ?? NO_OP_SINK, idSource(), fingerprint, now),
|
|
39
|
+
startedAt: now(),
|
|
40
|
+
progress: { modelCallCount: 0, patchRetryCount: 0 },
|
|
41
|
+
memoryPromptText: undefined,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
// UI-renderable next actions for the report. Pure. `elevated` lists changed manifest/config paths
|
|
45
|
+
// that warrant elevated review (D6).
|
|
46
|
+
export function nextActionsFor(applied, files, elevated) {
|
|
47
|
+
const first = files[0] ?? "the proposed fix";
|
|
48
|
+
const base = applied
|
|
49
|
+
? [`Review the applied fix in ${first}`, "Run `keiko verify` to confirm the suite is green"]
|
|
50
|
+
: [`Review the proposed fix for ${first}`, "Re-run with --apply to write the fix and verify"];
|
|
51
|
+
if (elevated.length > 0) {
|
|
52
|
+
return [
|
|
53
|
+
...base,
|
|
54
|
+
`This fix modifies build/manifest configuration (${elevated.join(", ")}) — review with elevated scrutiny before applying`,
|
|
55
|
+
];
|
|
56
|
+
}
|
|
57
|
+
return base;
|
|
58
|
+
}
|
|
59
|
+
// The next-actions list for the investigation-only outcome (no patch produced).
|
|
60
|
+
export function investigationNextActions() {
|
|
61
|
+
return [
|
|
62
|
+
"No safe fix was proposed; review the root-cause hypothesis and uncertainty",
|
|
63
|
+
"Provide more evidence (full failing output, stack trace, or suspected files) and re-run",
|
|
64
|
+
];
|
|
65
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { MemoryWorkflowContext, MemoryWorkflowPort } from "@oscharko-dev/keiko-contracts";
|
|
2
|
+
import type { BugInvestigationReport, BugReportInput } from "./types.js";
|
|
3
|
+
export declare function acquireMemoryContext(port: MemoryWorkflowPort | undefined, report: BugReportInput, workspaceRoot: string): Promise<MemoryWorkflowContext | undefined>;
|
|
4
|
+
export declare function emitMemoryWriteCandidate(port: MemoryWorkflowPort | undefined, report: BugInvestigationReport, workspaceRoot: string): void;
|
|
5
|
+
//# sourceMappingURL=memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/bug-investigation/memory.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAEV,qBAAqB,EACrB,kBAAkB,EAEnB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EACV,sBAAsB,EACtB,cAAc,EAGf,MAAM,YAAY,CAAC;AAgCpB,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,kBAAkB,GAAG,SAAS,EACpC,MAAM,EAAE,cAAc,EACtB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,qBAAqB,GAAG,SAAS,CAAC,CAuB5C;AAeD,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,kBAAkB,GAAG,SAAS,EACpC,MAAM,EAAE,sBAAsB,EAC9B,aAAa,EAAE,MAAM,GACpB,IAAI,CAiBN"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// Memory integration for the bug-investigation workflow (Issue #213 / Epic #204).
|
|
2
|
+
// Composes the optional MemoryWorkflowPort to fetch a scoped, prompt-ready memory context
|
|
3
|
+
// before model invocation and to emit a one-line write-candidate after a terminal success.
|
|
4
|
+
// READ-ONLY by design: memory cannot bypass the existing apply gates (#6 applyEnabled),
|
|
5
|
+
// scope guard (D6 bound 2), or patch limits (D6 bound 1) — those remain the sole write
|
|
6
|
+
// surface (epic §Architecture Invariants 1+2). Defence-in-depth: callers prepend the
|
|
7
|
+
// returned text to the user message via prompt.ts which already redacts + byte-caps every
|
|
8
|
+
// free-text field through safePromptText.
|
|
9
|
+
//
|
|
10
|
+
// Scope strategy: bug-investigation runs inside one repository, so workflow memory is
|
|
11
|
+
// bounded to the current project path. This prevents lessons from one regulated repository
|
|
12
|
+
// from being recalled in another while still letting the memory proposal provenance carry
|
|
13
|
+
// `workflow-outcome` / `sourceWorkflowRunId` through the capture pipeline.
|
|
14
|
+
// Default token budget passed to the port. The port may ignore it; the workflow does not
|
|
15
|
+
// enforce it (the prompt boundary clamp in safePromptText is the authoritative byte cap).
|
|
16
|
+
const DEFAULT_MEMORY_TOKEN_BUDGET = 2_048;
|
|
17
|
+
// The subset of statuses that should trigger a memory write-candidate. Aligned with the
|
|
18
|
+
// epic's "workflow-success" source kind. Cancelled / failed / rejected do NOT emit.
|
|
19
|
+
const SUCCESS_STATUSES = new Set([
|
|
20
|
+
"fix-applied",
|
|
21
|
+
"fix-proposed",
|
|
22
|
+
"investigation-only",
|
|
23
|
+
]);
|
|
24
|
+
// Build the lexical query passed to the memory retriever. Prefers the bug description; falls
|
|
25
|
+
// back to a generic label so the port always has a non-empty query to score against.
|
|
26
|
+
function memoryQueryText(report) {
|
|
27
|
+
const desc = report.description?.trim();
|
|
28
|
+
return desc !== undefined && desc.length > 0 ? desc : "bug investigation";
|
|
29
|
+
}
|
|
30
|
+
function bugInvestigationMemoryScope(workspaceRoot) {
|
|
31
|
+
return {
|
|
32
|
+
kind: "project",
|
|
33
|
+
projectId: workspaceRoot,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
// Fetches the assembled memory context. Returns undefined when no port was injected OR when
|
|
37
|
+
// the port returned an empty block — both cases are treated identically by the prompt
|
|
38
|
+
// builder so retrieval failures degrade gracefully (text === "" is indistinguishable from
|
|
39
|
+
// "no port").
|
|
40
|
+
export async function acquireMemoryContext(port, report, workspaceRoot) {
|
|
41
|
+
if (port === undefined) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
const scope = bugInvestigationMemoryScope(workspaceRoot);
|
|
45
|
+
try {
|
|
46
|
+
const context = await port.getContextForWorkflow([scope], memoryQueryText(report), DEFAULT_MEMORY_TOKEN_BUDGET);
|
|
47
|
+
if (context.text.length === 0 || context.includedMemoryIds.length === 0) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
port.onMemoryUsed?.({
|
|
51
|
+
memoryIds: context.includedMemoryIds,
|
|
52
|
+
scopes: [scope],
|
|
53
|
+
reason: "bug-investigation:pre-prompt",
|
|
54
|
+
});
|
|
55
|
+
return context;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Compose the one-line proposal summary. PURE: no IO, no clock, no randomness.
|
|
62
|
+
function buildProposalSummary(status, hypothesis) {
|
|
63
|
+
const root = hypothesis.rootCause?.trim();
|
|
64
|
+
if (root !== undefined && root.length > 0) {
|
|
65
|
+
return `[${status}] ${root}`;
|
|
66
|
+
}
|
|
67
|
+
return `[${status}] bug investigation completed without a recorded root cause`;
|
|
68
|
+
}
|
|
69
|
+
// Emits a write-candidate when the run reached a terminal success state. Caller decides
|
|
70
|
+
// whether to convert the candidate into a #207 capture proposal. NO-OP when the port is
|
|
71
|
+
// absent OR when the run was cancelled / failed / rejected (the latter mirrors the spec's
|
|
72
|
+
// "do NOT emit write-candidate on failure" rule).
|
|
73
|
+
export function emitMemoryWriteCandidate(port, report, workspaceRoot) {
|
|
74
|
+
if (port?.onMemoryWriteCandidate === undefined) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (!SUCCESS_STATUSES.has(report.status)) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const event = {
|
|
81
|
+
proposalSummary: buildProposalSummary(report.status, report.hypothesis),
|
|
82
|
+
scope: bugInvestigationMemoryScope(workspaceRoot),
|
|
83
|
+
source: "workflow-success",
|
|
84
|
+
};
|
|
85
|
+
try {
|
|
86
|
+
port.onMemoryWriteCandidate(event);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// defensive: callback exceptions must not propagate into runPipeline
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ContextPack, WorkspaceInfo } from "@oscharko-dev/keiko-workspace";
|
|
2
|
+
import { type BugModelLoopResult, type BugRunState } from "./internal.js";
|
|
3
|
+
import type { BugReportInput, FailureEvidence } from "./types.js";
|
|
4
|
+
export declare function runBugModelLoop(state: BugRunState, workspace: WorkspaceInfo, report: BugReportInput, evidence: FailureEvidence, pack: ContextPack): Promise<BugModelLoopResult>;
|
|
5
|
+
//# sourceMappingURL=model-loop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-loop.d.ts","sourceRoot":"","sources":["../../src/bug-investigation/model-loop.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAOhF,OAAO,EAGL,KAAK,kBAAkB,EACvB,KAAK,WAAW,EACjB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAA+B,MAAM,YAAY,CAAC;AA6Q/F,wBAAsB,eAAe,CACnC,KAAK,EAAE,WAAW,EAClB,SAAS,EAAE,aAAa,EACxB,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,eAAe,EACzB,IAAI,EAAE,WAAW,GAChB,OAAO,CAAC,kBAAkB,CAAC,CAwC7B"}
|