@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.
Files changed (191) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/bug-investigation/context.d.ts +7 -0
  3. package/dist/bug-investigation/context.d.ts.map +1 -0
  4. package/dist/bug-investigation/context.js +119 -0
  5. package/dist/bug-investigation/descriptor.d.ts +4 -0
  6. package/dist/bug-investigation/descriptor.d.ts.map +1 -0
  7. package/dist/bug-investigation/descriptor.js +46 -0
  8. package/dist/bug-investigation/emit.d.ts +13 -0
  9. package/dist/bug-investigation/emit.d.ts.map +1 -0
  10. package/dist/bug-investigation/emit.js +35 -0
  11. package/dist/bug-investigation/events.d.ts +2 -0
  12. package/dist/bug-investigation/events.d.ts.map +1 -0
  13. package/dist/bug-investigation/events.js +6 -0
  14. package/dist/bug-investigation/failure-parse.d.ts +4 -0
  15. package/dist/bug-investigation/failure-parse.d.ts.map +1 -0
  16. package/dist/bug-investigation/failure-parse.js +154 -0
  17. package/dist/bug-investigation/guard.d.ts +3 -0
  18. package/dist/bug-investigation/guard.d.ts.map +1 -0
  19. package/dist/bug-investigation/guard.js +69 -0
  20. package/dist/bug-investigation/index.d.ts +8 -0
  21. package/dist/bug-investigation/index.d.ts.map +1 -0
  22. package/dist/bug-investigation/index.js +13 -0
  23. package/dist/bug-investigation/internal.d.ts +39 -0
  24. package/dist/bug-investigation/internal.d.ts.map +1 -0
  25. package/dist/bug-investigation/internal.js +65 -0
  26. package/dist/bug-investigation/memory.d.ts +5 -0
  27. package/dist/bug-investigation/memory.d.ts.map +1 -0
  28. package/dist/bug-investigation/memory.js +91 -0
  29. package/dist/bug-investigation/model-loop.d.ts +5 -0
  30. package/dist/bug-investigation/model-loop.d.ts.map +1 -0
  31. package/dist/bug-investigation/model-loop.js +225 -0
  32. package/dist/bug-investigation/parse.d.ts +4 -0
  33. package/dist/bug-investigation/parse.d.ts.map +1 -0
  34. package/dist/bug-investigation/parse.js +125 -0
  35. package/dist/bug-investigation/prompt.d.ts +5 -0
  36. package/dist/bug-investigation/prompt.d.ts.map +1 -0
  37. package/dist/bug-investigation/prompt.js +122 -0
  38. package/dist/bug-investigation/report.d.ts +24 -0
  39. package/dist/bug-investigation/report.d.ts.map +1 -0
  40. package/dist/bug-investigation/report.js +151 -0
  41. package/dist/bug-investigation/stages.d.ts +14 -0
  42. package/dist/bug-investigation/stages.d.ts.map +1 -0
  43. package/dist/bug-investigation/stages.js +247 -0
  44. package/dist/bug-investigation/types.d.ts +88 -0
  45. package/dist/bug-investigation/types.d.ts.map +1 -0
  46. package/dist/bug-investigation/types.js +6 -0
  47. package/dist/bug-investigation/verify-stage.d.ts +11 -0
  48. package/dist/bug-investigation/verify-stage.d.ts.map +1 -0
  49. package/dist/bug-investigation/verify-stage.js +91 -0
  50. package/dist/bug-investigation/workflow.d.ts +3 -0
  51. package/dist/bug-investigation/workflow.d.ts.map +1 -0
  52. package/dist/bug-investigation/workflow.js +85 -0
  53. package/dist/contextpack/assemble.d.ts +35 -0
  54. package/dist/contextpack/assemble.d.ts.map +1 -0
  55. package/dist/contextpack/assemble.js +431 -0
  56. package/dist/contextpack/compaction.d.ts +23 -0
  57. package/dist/contextpack/compaction.d.ts.map +1 -0
  58. package/dist/contextpack/compaction.js +68 -0
  59. package/dist/contextpack/index.d.ts +9 -0
  60. package/dist/contextpack/index.d.ts.map +1 -0
  61. package/dist/contextpack/index.js +8 -0
  62. package/dist/contextpack/microIndex.d.ts +29 -0
  63. package/dist/contextpack/microIndex.d.ts.map +1 -0
  64. package/dist/contextpack/microIndex.js +98 -0
  65. package/dist/contextpack/reranker.d.ts +15 -0
  66. package/dist/contextpack/reranker.d.ts.map +1 -0
  67. package/dist/contextpack/reranker.js +31 -0
  68. package/dist/descriptor.d.ts +2 -0
  69. package/dist/descriptor.d.ts.map +1 -0
  70. package/dist/descriptor.js +1 -0
  71. package/dist/governed-handoff.d.ts +6 -0
  72. package/dist/governed-handoff.d.ts.map +1 -0
  73. package/dist/governed-handoff.js +86 -0
  74. package/dist/index.d.ts +9 -0
  75. package/dist/index.d.ts.map +1 -0
  76. package/dist/index.js +13 -0
  77. package/dist/planner/anchors.d.ts +17 -0
  78. package/dist/planner/anchors.d.ts.map +1 -0
  79. package/dist/planner/anchors.js +291 -0
  80. package/dist/planner/explorationPlanner.d.ts +9 -0
  81. package/dist/planner/explorationPlanner.d.ts.map +1 -0
  82. package/dist/planner/explorationPlanner.js +15 -0
  83. package/dist/planner/governor.d.ts +16 -0
  84. package/dist/planner/governor.d.ts.map +1 -0
  85. package/dist/planner/governor.js +106 -0
  86. package/dist/planner/index.d.ts +11 -0
  87. package/dist/planner/index.d.ts.map +1 -0
  88. package/dist/planner/index.js +8 -0
  89. package/dist/planner/intent.d.ts +8 -0
  90. package/dist/planner/intent.d.ts.map +1 -0
  91. package/dist/planner/intent.js +140 -0
  92. package/dist/planner/plan.d.ts +43 -0
  93. package/dist/planner/plan.d.ts.map +1 -0
  94. package/dist/planner/plan.js +237 -0
  95. package/dist/promptEnhancer/index.d.ts +23 -0
  96. package/dist/promptEnhancer/index.d.ts.map +1 -0
  97. package/dist/promptEnhancer/index.js +282 -0
  98. package/dist/qualityIntelligence/__tests__/fixtures/runEntryFixtures.d.ts +30 -0
  99. package/dist/qualityIntelligence/__tests__/fixtures/runEntryFixtures.d.ts.map +1 -0
  100. package/dist/qualityIntelligence/__tests__/fixtures/runEntryFixtures.js +114 -0
  101. package/dist/qualityIntelligence/cancellation.d.ts +20 -0
  102. package/dist/qualityIntelligence/cancellation.d.ts.map +1 -0
  103. package/dist/qualityIntelligence/cancellation.js +55 -0
  104. package/dist/qualityIntelligence/descriptors.d.ts +41 -0
  105. package/dist/qualityIntelligence/descriptors.d.ts.map +1 -0
  106. package/dist/qualityIntelligence/descriptors.js +105 -0
  107. package/dist/qualityIntelligence/index.d.ts +11 -0
  108. package/dist/qualityIntelligence/index.d.ts.map +1 -0
  109. package/dist/qualityIntelligence/index.js +11 -0
  110. package/dist/qualityIntelligence/modelRoutedTestDesign.d.ts +100 -0
  111. package/dist/qualityIntelligence/modelRoutedTestDesign.d.ts.map +1 -0
  112. package/dist/qualityIntelligence/modelRoutedTestDesign.js +620 -0
  113. package/dist/qualityIntelligence/runEntries.d.ts +60 -0
  114. package/dist/qualityIntelligence/runEntries.d.ts.map +1 -0
  115. package/dist/qualityIntelligence/runEntries.js +243 -0
  116. package/dist/qualityIntelligence/runtimeCommon.d.ts +106 -0
  117. package/dist/qualityIntelligence/runtimeCommon.d.ts.map +1 -0
  118. package/dist/qualityIntelligence/runtimeCommon.js +258 -0
  119. package/dist/qualityIntelligence/scopedRegeneration.d.ts +26 -0
  120. package/dist/qualityIntelligence/scopedRegeneration.d.ts.map +1 -0
  121. package/dist/qualityIntelligence/scopedRegeneration.js +35 -0
  122. package/dist/ranking/filter.d.ts +20 -0
  123. package/dist/ranking/filter.d.ts.map +1 -0
  124. package/dist/ranking/filter.js +99 -0
  125. package/dist/ranking/index.d.ts +9 -0
  126. package/dist/ranking/index.d.ts.map +1 -0
  127. package/dist/ranking/index.js +8 -0
  128. package/dist/ranking/rank.d.ts +21 -0
  129. package/dist/ranking/rank.d.ts.map +1 -0
  130. package/dist/ranking/rank.js +160 -0
  131. package/dist/ranking/scoring.d.ts +13 -0
  132. package/dist/ranking/scoring.d.ts.map +1 -0
  133. package/dist/ranking/scoring.js +39 -0
  134. package/dist/ranking/signals.d.ts +20 -0
  135. package/dist/ranking/signals.d.ts.map +1 -0
  136. package/dist/ranking/signals.js +145 -0
  137. package/dist/unit-tests/context.d.ts +7 -0
  138. package/dist/unit-tests/context.d.ts.map +1 -0
  139. package/dist/unit-tests/context.js +129 -0
  140. package/dist/unit-tests/conventions.d.ts +5 -0
  141. package/dist/unit-tests/conventions.d.ts.map +1 -0
  142. package/dist/unit-tests/conventions.js +87 -0
  143. package/dist/unit-tests/descriptor.d.ts +5 -0
  144. package/dist/unit-tests/descriptor.d.ts.map +1 -0
  145. package/dist/unit-tests/descriptor.js +43 -0
  146. package/dist/unit-tests/emit.d.ts +13 -0
  147. package/dist/unit-tests/emit.d.ts.map +1 -0
  148. package/dist/unit-tests/emit.js +35 -0
  149. package/dist/unit-tests/events.d.ts +2 -0
  150. package/dist/unit-tests/events.d.ts.map +1 -0
  151. package/dist/unit-tests/events.js +6 -0
  152. package/dist/unit-tests/frontend.d.ts +42 -0
  153. package/dist/unit-tests/frontend.d.ts.map +1 -0
  154. package/dist/unit-tests/frontend.js +281 -0
  155. package/dist/unit-tests/index.d.ts +9 -0
  156. package/dist/unit-tests/index.d.ts.map +1 -0
  157. package/dist/unit-tests/index.js +15 -0
  158. package/dist/unit-tests/internal.d.ts +36 -0
  159. package/dist/unit-tests/internal.d.ts.map +1 -0
  160. package/dist/unit-tests/internal.js +43 -0
  161. package/dist/unit-tests/model-loop.d.ts +6 -0
  162. package/dist/unit-tests/model-loop.d.ts.map +1 -0
  163. package/dist/unit-tests/model-loop.js +98 -0
  164. package/dist/unit-tests/parse.d.ts +7 -0
  165. package/dist/unit-tests/parse.d.ts.map +1 -0
  166. package/dist/unit-tests/parse.js +68 -0
  167. package/dist/unit-tests/prompt.d.ts +6 -0
  168. package/dist/unit-tests/prompt.d.ts.map +1 -0
  169. package/dist/unit-tests/prompt.js +139 -0
  170. package/dist/unit-tests/report.d.ts +26 -0
  171. package/dist/unit-tests/report.d.ts.map +1 -0
  172. package/dist/unit-tests/report.js +104 -0
  173. package/dist/unit-tests/stages.d.ts +12 -0
  174. package/dist/unit-tests/stages.d.ts.map +1 -0
  175. package/dist/unit-tests/stages.js +202 -0
  176. package/dist/unit-tests/strategy.d.ts +6 -0
  177. package/dist/unit-tests/strategy.d.ts.map +1 -0
  178. package/dist/unit-tests/strategy.js +36 -0
  179. package/dist/unit-tests/target-guard.d.ts +5 -0
  180. package/dist/unit-tests/target-guard.d.ts.map +1 -0
  181. package/dist/unit-tests/target-guard.js +29 -0
  182. package/dist/unit-tests/types.d.ts +74 -0
  183. package/dist/unit-tests/types.d.ts.map +1 -0
  184. package/dist/unit-tests/types.js +6 -0
  185. package/dist/unit-tests/verify-stage.d.ts +10 -0
  186. package/dist/unit-tests/verify-stage.d.ts.map +1 -0
  187. package/dist/unit-tests/verify-stage.js +56 -0
  188. package/dist/unit-tests/workflow.d.ts +3 -0
  189. package/dist/unit-tests/workflow.d.ts.map +1 -0
  190. package/dist/unit-tests/workflow.js +69 -0
  191. package/package.json +38 -0
@@ -0,0 +1,14 @@
1
+ import type { WorkspaceInfo } from "@oscharko-dev/keiko-workspace";
2
+ import { type AcceptedBugPatch, type BugModelLoopResult, type BugRunState } from "./internal.js";
3
+ import type { BugInvestigationReport, FailureEvidence, Hypothesis } from "./types.js";
4
+ export declare function rejectedReport(state: BugRunState, loop: BugModelLoopResult, evidence: FailureEvidence): BugInvestigationReport;
5
+ export declare function insufficientInputReport(state: BugRunState): BugInvestigationReport;
6
+ export declare function investigationOnlyReport(state: BugRunState, loop: BugModelLoopResult, hypothesis: Hypothesis, evidence: FailureEvidence): BugInvestigationReport;
7
+ export declare function dryRunReport(state: BugRunState, loop: BugModelLoopResult, accepted: AcceptedBugPatch, evidence: FailureEvidence): BugInvestigationReport;
8
+ export declare function cancelledReport(state: BugRunState, loop: BugModelLoopResult, accepted: AcceptedBugPatch | undefined, evidence: FailureEvidence, applied?: {
9
+ readonly changedFiles: readonly string[];
10
+ }): BugInvestigationReport;
11
+ export declare function failedReport(state: BugRunState, error: unknown): BugInvestigationReport;
12
+ export declare function emitCompleted(state: BugRunState, report: BugInvestigationReport): BugInvestigationReport;
13
+ export declare function finishPipeline(state: BugRunState, workspace: WorkspaceInfo, loop: BugModelLoopResult, evidence: FailureEvidence): Promise<BugInvestigationReport>;
14
+ //# sourceMappingURL=stages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stages.d.ts","sourceRoot":"","sources":["../../src/bug-investigation/stages.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAInE,OAAO,EAIL,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,WAAW,EACjB,MAAM,eAAe,CAAC;AAEvB,OAAO,KAAK,EAAE,sBAAsB,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAatF,wBAAgB,cAAc,CAC5B,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,kBAAkB,EACxB,QAAQ,EAAE,eAAe,GACxB,sBAAsB,CAqBxB;AAGD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,WAAW,GAAG,sBAAsB,CAqBlF;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,kBAAkB,EACxB,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,eAAe,GACxB,sBAAsB,CAmBxB;AAED,wBAAgB,YAAY,CAC1B,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,kBAAkB,EACxB,QAAQ,EAAE,gBAAgB,EAC1B,QAAQ,EAAE,eAAe,GACxB,sBAAsB,CAoBxB;AAKD,wBAAgB,eAAe,CAC7B,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,kBAAkB,EACxB,QAAQ,EAAE,gBAAgB,GAAG,SAAS,EACtC,QAAQ,EAAE,eAAe,EACzB,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GACrD,sBAAsB,CA0BxB;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,GAAG,sBAAsB,CAsBvF;AA6ED,wBAAgB,aAAa,CAC3B,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,sBAAsB,GAC7B,sBAAsB,CAOxB;AAKD,wBAAsB,cAAc,CAClC,KAAK,EAAE,WAAW,EAClB,SAAS,EAAE,aAAa,EACxB,IAAI,EAAE,kBAAkB,EACxB,QAAQ,EAAE,eAAe,GACxB,OAAO,CAAC,sBAAsB,CAAC,CAcjC"}
@@ -0,0 +1,247 @@
1
+ // Terminal-report stages (ADR-0009 D3/D4/D11). Each function maps a pipeline outcome —
2
+ // fix-proposed (dry-run), fix-applied, investigation-only, rejected, cancelled, or failed — to the
3
+ // redacted BugInvestigationReport via assembleBugReport. applyPatch (apply mode) is the one IO
4
+ // boundary here and is fail-closed in #6 (applyEnabled gates the write); it receives the SAME
5
+ // tighter PatchLimits as validatePatch (D6 bound 1, defence-in-depth re-validation). finishPipeline
6
+ // selects the branch; emitCompleted stamps the terminal event. All redaction is inside assembleBugReport.
7
+ import { redact } from "@oscharko-dev/keiko-security";
8
+ import { applyPatch, CommandCancelledError, renderDryRun, } from "@oscharko-dev/keiko-tools";
9
+ import { nodeWorkspaceWriter } from "@oscharko-dev/keiko-tools/internal/writer";
10
+ import { nodeWorkspaceFs } from "@oscharko-dev/keiko-workspace/internal/fs";
11
+ import { createScopedWriter } from "../governed-handoff.js";
12
+ import { assembleBugReport } from "./report.js";
13
+ import { runBugVerification } from "./verify-stage.js";
14
+ import { investigationNextActions, nextActionsFor, patchLimitsFrom, } from "./internal.js";
15
+ import { isElevatedReviewPath } from "./guard.js";
16
+ const EMPTY_HYPOTHESIS = {
17
+ rootCause: undefined,
18
+ regressionTestStrategy: undefined,
19
+ uncertainty: undefined,
20
+ confidence: undefined,
21
+ };
22
+ function elevatedPaths(accepted) {
23
+ return accepted.validation.files.map((f) => f.path).filter((p) => isElevatedReviewPath(p));
24
+ }
25
+ export function rejectedReport(state, loop, evidence) {
26
+ return assembleBugReport({
27
+ status: "rejected",
28
+ modelId: state.input.modelId,
29
+ durationMs: state.now() - state.startedAt,
30
+ patchFiles: [],
31
+ patchValidates: false,
32
+ patchApplied: false,
33
+ verification: undefined,
34
+ failureFrames: evidence.frames,
35
+ hypothesis: EMPTY_HYPOTHESIS,
36
+ proposedDiff: undefined,
37
+ dryRunPreview: undefined,
38
+ verificationSkipReason: undefined,
39
+ nextActions: [
40
+ `The model did not produce an in-scope fix (${loop.lastRejectionCode ?? "insufficient evidence"})`,
41
+ ],
42
+ failureReason: undefined,
43
+ modelCallCount: loop.modelCallCount,
44
+ patchRetryCount: loop.patchRetryCount,
45
+ });
46
+ }
47
+ // Insufficient-input rejection: returned by the intake precondition before any model call.
48
+ export function insufficientInputReport(state) {
49
+ return assembleBugReport({
50
+ status: "rejected",
51
+ modelId: state.input.modelId,
52
+ durationMs: state.now() - state.startedAt,
53
+ patchFiles: [],
54
+ patchValidates: false,
55
+ patchApplied: false,
56
+ verification: undefined,
57
+ failureFrames: [],
58
+ hypothesis: EMPTY_HYPOTHESIS,
59
+ proposedDiff: undefined,
60
+ dryRunPreview: undefined,
61
+ verificationSkipReason: undefined,
62
+ nextActions: [
63
+ "Provide at least one of: a description, failing output, a stack trace, or suspected target files",
64
+ ],
65
+ failureReason: undefined,
66
+ modelCallCount: 0,
67
+ patchRetryCount: 0,
68
+ });
69
+ }
70
+ export function investigationOnlyReport(state, loop, hypothesis, evidence) {
71
+ return assembleBugReport({
72
+ status: "investigation-only",
73
+ modelId: state.input.modelId,
74
+ durationMs: state.now() - state.startedAt,
75
+ patchFiles: [],
76
+ patchValidates: false,
77
+ patchApplied: false,
78
+ verification: undefined,
79
+ failureFrames: evidence.frames,
80
+ hypothesis,
81
+ proposedDiff: undefined,
82
+ dryRunPreview: undefined,
83
+ verificationSkipReason: "verification skipped: no patch produced (investigation-only)",
84
+ nextActions: investigationNextActions(),
85
+ failureReason: undefined,
86
+ modelCallCount: loop.modelCallCount,
87
+ patchRetryCount: loop.patchRetryCount,
88
+ });
89
+ }
90
+ export function dryRunReport(state, loop, accepted, evidence) {
91
+ const files = accepted.validation.files.map((f) => f.path);
92
+ return assembleBugReport({
93
+ status: "fix-proposed",
94
+ modelId: state.input.modelId,
95
+ durationMs: state.now() - state.startedAt,
96
+ patchFiles: accepted.validation.files,
97
+ patchValidates: true,
98
+ patchApplied: false,
99
+ verification: undefined,
100
+ failureFrames: evidence.frames,
101
+ hypothesis: accepted.hypothesis,
102
+ proposedDiff: accepted.diff,
103
+ dryRunPreview: renderDryRun(accepted.validation),
104
+ verificationSkipReason: "verification skipped: dry-run, no files written",
105
+ nextActions: nextActionsFor(false, files, elevatedPaths(accepted)),
106
+ failureReason: undefined,
107
+ modelCallCount: loop.modelCallCount,
108
+ patchRetryCount: loop.patchRetryCount,
109
+ });
110
+ }
111
+ // `applied` is set ONLY on a post-apply abort: the patch is already on disk, so the report (and the
112
+ // #10 ledger record) must reflect that (patchApplied: true) rather than hard-coding false. A
113
+ // pre-apply abort passes applied === undefined and stays patchApplied: false.
114
+ export function cancelledReport(state, loop, accepted, evidence, applied) {
115
+ const nextActions = applied === undefined
116
+ ? ["The workflow was cancelled before completion"]
117
+ : [
118
+ `The fix was applied to ${applied.changedFiles[0] ?? "disk"} but the workflow was cancelled before verification completed`,
119
+ "Run `keiko verify` to confirm the suite",
120
+ ];
121
+ return assembleBugReport({
122
+ status: "cancelled",
123
+ modelId: state.input.modelId,
124
+ durationMs: state.now() - state.startedAt,
125
+ patchFiles: accepted?.validation.files ?? [],
126
+ patchValidates: accepted !== undefined,
127
+ patchApplied: applied !== undefined,
128
+ verification: undefined,
129
+ failureFrames: evidence.frames,
130
+ hypothesis: accepted?.hypothesis ?? EMPTY_HYPOTHESIS,
131
+ proposedDiff: accepted?.diff,
132
+ dryRunPreview: accepted === undefined ? undefined : renderDryRun(accepted.validation),
133
+ verificationSkipReason: "verification skipped: cancelled",
134
+ nextActions,
135
+ failureReason: undefined,
136
+ modelCallCount: loop.modelCallCount,
137
+ patchRetryCount: loop.patchRetryCount,
138
+ });
139
+ }
140
+ export function failedReport(state, error) {
141
+ const message = redact(error instanceof Error ? error.message : "unexpected workflow failure");
142
+ const errorCode = error instanceof Error ? error.name : "UNKNOWN";
143
+ state.emitter.emit({ type: "bug:failed", errorCode, message });
144
+ return assembleBugReport({
145
+ status: "failed",
146
+ modelId: state.input.modelId,
147
+ durationMs: state.now() - state.startedAt,
148
+ patchFiles: [],
149
+ patchValidates: false,
150
+ patchApplied: false,
151
+ verification: undefined,
152
+ failureFrames: [],
153
+ hypothesis: EMPTY_HYPOTHESIS,
154
+ proposedDiff: undefined,
155
+ dryRunPreview: undefined,
156
+ verificationSkipReason: undefined,
157
+ nextActions: [`Inspect the error and retry: ${message}`],
158
+ failureReason: message,
159
+ modelCallCount: state.progress.modelCallCount,
160
+ patchRetryCount: state.progress.patchRetryCount,
161
+ });
162
+ }
163
+ function applyBugPatch(state, workspace, accepted) {
164
+ const fs = state.deps.fs ?? nodeWorkspaceFs;
165
+ const writer = state.deps.workflowHandoff === undefined
166
+ ? state.deps.writer
167
+ : createScopedWriter(state.deps.writer ?? nodeWorkspaceWriter, workspace.root, state.deps.workflowHandoff.patchScope.editablePaths);
168
+ const applyResult = applyPatch(workspace, accepted.diff, {
169
+ applyEnabled: true,
170
+ signal: state.signal,
171
+ fs,
172
+ limits: patchLimitsFrom(state.limits),
173
+ ...(writer === undefined ? {} : { writer }),
174
+ });
175
+ return { fs, applyResult };
176
+ }
177
+ async function applyAndVerify(state, workspace, loop, accepted, evidence) {
178
+ let applyResult;
179
+ let fs;
180
+ try {
181
+ ({ fs, applyResult } = applyBugPatch(state, workspace, accepted));
182
+ }
183
+ catch (error) {
184
+ if (error instanceof CommandCancelledError) {
185
+ return cancelledReport(state, loop, accepted, evidence);
186
+ }
187
+ throw error;
188
+ }
189
+ state.emitter.emit({
190
+ type: "bug:patch:applied",
191
+ changedFiles: applyResult.changedFiles.length,
192
+ created: applyResult.created.length,
193
+ deleted: applyResult.deleted.length,
194
+ });
195
+ if (state.signal.aborted) {
196
+ // Post-apply abort: the patch is already on disk, so the report must reflect patchApplied: true
197
+ // (M1) — the #10 ledger record must match the real filesystem state.
198
+ return cancelledReport(state, loop, accepted, evidence, {
199
+ changedFiles: applyResult.changedFiles,
200
+ });
201
+ }
202
+ const verification = await runBugVerification(state, workspace, accepted.validation.files, fs);
203
+ return assembleBugReport({
204
+ status: "fix-applied",
205
+ modelId: state.input.modelId,
206
+ durationMs: state.now() - state.startedAt,
207
+ patchFiles: accepted.validation.files,
208
+ patchValidates: true,
209
+ patchApplied: true,
210
+ verification: verification.summary,
211
+ failureFrames: evidence.frames,
212
+ hypothesis: accepted.hypothesis,
213
+ proposedDiff: accepted.diff,
214
+ dryRunPreview: renderDryRun(accepted.validation),
215
+ verificationSkipReason: verification.skipReason,
216
+ nextActions: nextActionsFor(true, applyResult.changedFiles, elevatedPaths(accepted)),
217
+ failureReason: undefined,
218
+ modelCallCount: loop.modelCallCount,
219
+ patchRetryCount: loop.patchRetryCount,
220
+ });
221
+ }
222
+ export function emitCompleted(state, report) {
223
+ state.emitter.emit({
224
+ type: "bug:completed",
225
+ status: report.status,
226
+ durationMs: report.durationMs,
227
+ });
228
+ return report;
229
+ }
230
+ // Selects the terminal branch from the model-loop result: investigation-only (hypothesis, no
231
+ // patch), rejected (nothing usable), cancelled (abort before apply), apply+verify (apply mode), or
232
+ // dry-run (default).
233
+ export async function finishPipeline(state, workspace, loop, evidence) {
234
+ if (loop.accepted === undefined) {
235
+ if (loop.investigationOnly !== undefined) {
236
+ return investigationOnlyReport(state, loop, loop.investigationOnly, evidence);
237
+ }
238
+ return rejectedReport(state, loop, evidence);
239
+ }
240
+ if (state.signal.aborted) {
241
+ return cancelledReport(state, loop, loop.accepted, evidence);
242
+ }
243
+ if (state.input.apply === true) {
244
+ return applyAndVerify(state, workspace, loop, loop.accepted, evidence);
245
+ }
246
+ return dryRunReport(state, loop, loop.accepted, evidence);
247
+ }
@@ -0,0 +1,88 @@
1
+ import type { MemoryWorkflowPort } from "@oscharko-dev/keiko-contracts";
2
+ import type { WorkflowHandoffRequest } from "@oscharko-dev/keiko-contracts/workflow-handoff";
3
+ import type { ModelPort } from "@oscharko-dev/keiko-harness";
4
+ import type { PatchChangeKind, SpawnFn, WorkspaceWriter } from "@oscharko-dev/keiko-tools";
5
+ import type { WorkspaceFs } from "@oscharko-dev/keiko-workspace";
6
+ import type { VerificationAuditSummary } from "@oscharko-dev/keiko-verification";
7
+ import type { BugWorkflowEventSink } from "./events.js";
8
+ import type { BugWorkflowLimits, BugWorkflowStatus } from "@oscharko-dev/keiko-contracts";
9
+ export type { BugWorkflowStatus, BugWorkflowLimits } from "@oscharko-dev/keiko-contracts";
10
+ export { DEFAULT_BUG_WORKFLOW_LIMITS } from "@oscharko-dev/keiko-contracts";
11
+ export interface FailureFrame {
12
+ readonly file: string;
13
+ readonly line?: number | undefined;
14
+ }
15
+ export interface FailureEvidence {
16
+ readonly frames: readonly FailureFrame[];
17
+ readonly messages: readonly string[];
18
+ }
19
+ export interface BugReportInput {
20
+ readonly description?: string | undefined;
21
+ readonly failingOutput?: string | undefined;
22
+ readonly stackTrace?: string | undefined;
23
+ readonly targetFiles?: readonly string[] | undefined;
24
+ }
25
+ export interface BugInvestigationInput {
26
+ readonly workspaceRoot: string;
27
+ readonly report: BugReportInput;
28
+ readonly apply?: boolean | undefined;
29
+ readonly modelId: string;
30
+ readonly limits?: Partial<BugWorkflowLimits> | undefined;
31
+ }
32
+ export interface BugInvestigationDeps {
33
+ readonly model: ModelPort;
34
+ readonly fs?: WorkspaceFs | undefined;
35
+ readonly writer?: WorkspaceWriter | undefined;
36
+ readonly spawn?: SpawnFn | undefined;
37
+ readonly now?: (() => number) | undefined;
38
+ readonly idSource?: (() => string) | undefined;
39
+ readonly sink?: BugWorkflowEventSink | undefined;
40
+ readonly processEnv?: NodeJS.ProcessEnv | undefined;
41
+ readonly signal?: AbortSignal | undefined;
42
+ readonly memoryPort?: MemoryWorkflowPort | undefined;
43
+ readonly workflowHandoff?: WorkflowHandoffRequest | undefined;
44
+ }
45
+ export interface VerifiedFindings {
46
+ readonly patchValidates: boolean;
47
+ readonly patchApplied: boolean;
48
+ readonly verification?: VerificationAuditSummary | undefined;
49
+ readonly failureFrames: readonly FailureFrame[];
50
+ }
51
+ export interface Hypothesis {
52
+ readonly rootCause?: string | undefined;
53
+ readonly regressionTestStrategy?: string | undefined;
54
+ readonly uncertainty?: string | undefined;
55
+ readonly confidence?: "low" | "medium" | "high" | undefined;
56
+ }
57
+ export interface ChangedFile {
58
+ readonly path: string;
59
+ readonly kind: PatchChangeKind;
60
+ readonly addedLines: number;
61
+ readonly removedLines: number;
62
+ readonly elevatedReview: boolean;
63
+ }
64
+ export interface BugInvestigationReport {
65
+ readonly workflowId: "bug-investigation";
66
+ readonly status: BugWorkflowStatus;
67
+ readonly modelId: string;
68
+ readonly durationMs: number;
69
+ readonly verified: VerifiedFindings;
70
+ readonly hypothesis: Hypothesis;
71
+ readonly proposedDiff?: string | undefined;
72
+ readonly dryRunPreview?: string | undefined;
73
+ readonly changedFiles: readonly ChangedFile[];
74
+ readonly regressionCoverage: number;
75
+ readonly verificationSkipReason?: string | undefined;
76
+ readonly nextActions: readonly string[];
77
+ readonly failureReason?: string | undefined;
78
+ readonly modelCallCount: number;
79
+ readonly patchRetryCount: number;
80
+ }
81
+ export interface ParsedBugOutput {
82
+ readonly diff: string;
83
+ readonly rootCause: string | undefined;
84
+ readonly regressionTestStrategy: string | undefined;
85
+ readonly uncertainty: string | undefined;
86
+ readonly confidence: "low" | "medium" | "high" | undefined;
87
+ }
88
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/bug-investigation/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ // All interfaces, type aliases, and frozen constant tables for the bug-investigation workflow
2
+ // (ADR-0009 D2/D3/D4/D7/D13). No runtime logic beyond the frozen tables. `readonly` everywhere;
3
+ // optional props are `| undefined` because exactOptionalPropertyTypes is on. Every report shape is
4
+ // plain JSON-serializable so the #10 audit ledger can persist it. Names are DISTINCT from the
5
+ // unit-test workflow's (ADR-0009 D5) because both barrels are re-exported from the package root.
6
+ export { DEFAULT_BUG_WORKFLOW_LIMITS } from "@oscharko-dev/keiko-contracts";
@@ -0,0 +1,11 @@
1
+ import type { PatchFileChange } from "@oscharko-dev/keiko-tools";
2
+ import { type WorkspaceFs, type WorkspaceInfo } from "@oscharko-dev/keiko-workspace";
3
+ import { type VerificationAuditSummary } from "@oscharko-dev/keiko-verification";
4
+ import type { BugRunState } from "./internal.js";
5
+ export declare const SKIP_UNRESOLVED = "verification skipped: framework unknown or no test files resolved";
6
+ export interface BugVerificationOutcome {
7
+ readonly summary: VerificationAuditSummary | undefined;
8
+ readonly skipReason: string | undefined;
9
+ }
10
+ export declare function runBugVerification(state: BugRunState, workspace: WorkspaceInfo, changedFiles: readonly PatchFileChange[], fs: WorkspaceFs): Promise<BugVerificationOutcome>;
11
+ //# sourceMappingURL=verify-stage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify-stage.d.ts","sourceRoot":"","sources":["../../src/bug-investigation/verify-stage.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAEjE,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACrF,OAAO,EAOL,KAAK,wBAAwB,EAG9B,MAAM,kCAAkC,CAAC;AAE1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,eAAO,MAAM,eAAe,sEAAsE,CAAC;AA4EnG,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,OAAO,EAAE,wBAAwB,GAAG,SAAS,CAAC;IACvD,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC;AAED,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,WAAW,EAClB,SAAS,EAAE,aAAa,EACxB,YAAY,EAAE,SAAS,eAAe,EAAE,EACxC,EAAE,EAAE,WAAW,GACd,OAAO,CAAC,sBAAsB,CAAC,CAsBjC"}
@@ -0,0 +1,91 @@
1
+ // The verification stage (ADR-0009 D11). Runs ONLY after a successful apply: it resolves a
2
+ // verification plan by deriving the just-fixed/added tests from the changed SOURCE files via #7
3
+ // resolveTargetedTests (so it finds the sibling/mirrored test incl. the just-added regression
4
+ // test), falling back to the full `test` script, and records an explicit skip reason when neither
5
+ // resolves or the framework is unknown. Verification reuses the #7 orchestrator unchanged; this
6
+ // stage only wires the plan and projects an output-text-free audit summary. DEFERRED (D11): a
7
+ // pre-patch reproduction baseline — Wave-1 verifies only the post-apply state.
8
+ import { nodeSpawnFn } from "@oscharko-dev/keiko-tools/internal/exec";
9
+ import {} from "@oscharko-dev/keiko-workspace";
10
+ import { buildVerificationPlan, detectScripts, resolveTargetedTests, runVerification, summarizeForAudit, DEFAULT_VERIFICATION_LIMITS, } from "@oscharko-dev/keiko-verification";
11
+ import { isSensitivePath } from "./guard.js";
12
+ export const SKIP_UNRESOLVED = "verification skipped: framework unknown or no test files resolved";
13
+ // The non-test source files the patch changed — passed to resolveTargetedTests so it can find the
14
+ // associated tests (incl. the just-added regression test). We approximate "source" as any changed
15
+ // path that is not itself a test file (basename marks .test/.spec) and not a sensitive path.
16
+ function changedSourceFiles(files) {
17
+ return files.map((f) => f.path).filter((path) => !isSensitivePath(path) && !isTestFile(path));
18
+ }
19
+ function changedTestFiles(files) {
20
+ return files.map((f) => f.path).filter((path) => !isSensitivePath(path) && isTestFile(path));
21
+ }
22
+ function isTestFile(path) {
23
+ const slash = path.lastIndexOf("/");
24
+ const base = slash === -1 ? path : path.slice(slash + 1);
25
+ const segments = base.split(".");
26
+ return segments.includes("test") || segments.includes("spec");
27
+ }
28
+ function buildPlanFallback(workspace, fs) {
29
+ const catalog = detectScripts(workspace, fs);
30
+ return buildVerificationPlan(workspace, catalog, { only: ["test"] }, fs);
31
+ }
32
+ function targetedChangedTests(workspace, testFiles) {
33
+ if (testFiles.length === 0) {
34
+ return undefined;
35
+ }
36
+ if (workspace.testFramework === "vitest") {
37
+ return {
38
+ kind: "targeted-test",
39
+ scriptName: undefined,
40
+ command: "npx",
41
+ args: ["vitest", "run", ...testFiles],
42
+ limits: DEFAULT_VERIFICATION_LIMITS,
43
+ };
44
+ }
45
+ if (workspace.testFramework === "jest") {
46
+ return {
47
+ kind: "targeted-test",
48
+ scriptName: undefined,
49
+ command: "npx",
50
+ args: ["jest", ...testFiles],
51
+ limits: DEFAULT_VERIFICATION_LIMITS,
52
+ };
53
+ }
54
+ return undefined;
55
+ }
56
+ function resolveVerificationPlan(workspace, changedFiles, fs) {
57
+ const directTests = targetedChangedTests(workspace, changedTestFiles(changedFiles));
58
+ if (directTests !== undefined) {
59
+ return { workspaceRoot: workspace.root, steps: [directTests] };
60
+ }
61
+ const targeted = resolveTargetedTests(workspace, changedSourceFiles(changedFiles), fs, DEFAULT_VERIFICATION_LIMITS);
62
+ if (targeted.length > 0) {
63
+ return { workspaceRoot: workspace.root, steps: targeted };
64
+ }
65
+ const fallback = buildPlanFallback(workspace, fs);
66
+ const runnable = fallback.steps.filter((step) => step.skipReason === undefined);
67
+ return runnable.length > 0 ? { workspaceRoot: workspace.root, steps: runnable } : undefined;
68
+ }
69
+ export async function runBugVerification(state, workspace, changedFiles, fs) {
70
+ const plan = resolveVerificationPlan(workspace, changedFiles, fs);
71
+ if (plan === undefined) {
72
+ return { summary: undefined, skipReason: SKIP_UNRESOLVED };
73
+ }
74
+ const report = await runVerification(plan, {
75
+ workspace,
76
+ signal: state.signal,
77
+ spawn: state.deps.spawn ?? nodeSpawnFn,
78
+ processEnv: state.deps.processEnv ?? process.env,
79
+ now: state.now,
80
+ fs,
81
+ });
82
+ const summary = summarizeForAudit(report);
83
+ state.emitter.emit({
84
+ type: "bug:verification:result",
85
+ overallStatus: summary.overallStatus,
86
+ stepCount: summary.results.length,
87
+ passedCount: summary.results.filter((r) => r.status === "passed").length,
88
+ durationMs: summary.durationMs,
89
+ });
90
+ return { summary, skipReason: undefined };
91
+ }
@@ -0,0 +1,3 @@
1
+ import type { BugInvestigationDeps, BugInvestigationInput, BugInvestigationReport } from "./types.js";
2
+ export declare function investigateBug(input: BugInvestigationInput, deps: BugInvestigationDeps): Promise<BugInvestigationReport>;
3
+ //# sourceMappingURL=workflow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow.d.ts","sourceRoot":"","sources":["../../src/bug-investigation/workflow.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EACV,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EAEvB,MAAM,YAAY,CAAC;AA0DpB,wBAAsB,cAAc,CAClC,KAAK,EAAE,qBAAqB,EAC5B,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,sBAAsB,CAAC,CAiBjC"}
@@ -0,0 +1,85 @@
1
+ // The single public entry: investigateBug (ADR-0009 D2/D6/D10/D11). A deterministic linear pipeline
2
+ // (NOT the harness loop): intake precondition -> parse failure evidence -> build context -> [prompt
3
+ // -> model -> parse -> validate -> scope-guard] (bounded retries) -> [investigation-only |
4
+ // rejected | dry-run | apply -> verify] -> report. It composes #3-#7 UNCHANGED and emits redacted
5
+ // progress events. The model loop, verify stage, and report stages live in sibling files to keep
6
+ // each under the LOC limit; this file owns the stage sequencing, the intake precondition (return
7
+ // `rejected` with no model call when no evidence is present), and the single top-level catch
8
+ // boundary that maps a CancelledError to a "cancelled" report and any other IO failure to a
9
+ // redacted "failed" report.
10
+ import { CancelledError } from "@oscharko-dev/keiko-model-gateway";
11
+ import { detectWorkspace } from "@oscharko-dev/keiko-workspace";
12
+ import { nodeWorkspaceFs } from "@oscharko-dev/keiko-workspace/internal/fs";
13
+ import { buildBugContext } from "./context.js";
14
+ import { computeBugFingerprint } from "./emit.js";
15
+ import { parseFailureEvidence } from "./failure-parse.js";
16
+ import { acquireMemoryContext, emitMemoryWriteCandidate } from "./memory.js";
17
+ import { runBugModelLoop } from "./model-loop.js";
18
+ import { cancelledReport, emitCompleted, failedReport, finishPipeline, insufficientInputReport, } from "./stages.js";
19
+ import { buildBugRunState, EMPTY_BUG_LOOP } from "./internal.js";
20
+ // Intake precondition (D2): at least one evidence field must be present, else there is nothing to
21
+ // investigate and we reject WITHOUT calling the model.
22
+ function hasEvidence(report) {
23
+ return (nonEmpty(report.description) ||
24
+ nonEmpty(report.failingOutput) ||
25
+ nonEmpty(report.stackTrace) ||
26
+ (report.targetFiles?.some((file) => nonEmpty(file)) ?? false));
27
+ }
28
+ function nonEmpty(value) {
29
+ return value !== undefined && value.trim().length > 0;
30
+ }
31
+ async function runPipeline(state) {
32
+ const report = state.input.report;
33
+ state.emitter.emit({
34
+ type: "bug:started",
35
+ workflowId: "bug-investigation",
36
+ modelId: state.input.modelId,
37
+ applyEnabled: state.input.apply === true,
38
+ limits: state.limits,
39
+ });
40
+ if (!hasEvidence(report)) {
41
+ return insufficientInputReport(state);
42
+ }
43
+ const fs = state.deps.fs ?? nodeWorkspaceFs;
44
+ const workspace = detectWorkspace(state.input.workspaceRoot, fs);
45
+ const evidence = parseFailureEvidence(report);
46
+ // Memory composition (Issue #213): fetch a scoped memory context before any model call so
47
+ // the model loop can prepend it to the user message. NO-OP when no port is injected; the
48
+ // returned text is redacted + byte-capped at the prompt boundary (defence-in-depth).
49
+ const memoryContext = await acquireMemoryContext(state.deps.memoryPort, report, state.input.workspaceRoot);
50
+ state.memoryPromptText = memoryContext?.text;
51
+ state.emitter.emit({
52
+ type: "bug:failure:parsed",
53
+ frameCount: evidence.frames.length,
54
+ messageCount: evidence.messages.length,
55
+ });
56
+ const pack = buildBugContext(workspace, report.description, evidence, state.limits, { fs });
57
+ state.emitter.emit({
58
+ type: "bug:context:selected",
59
+ entryCount: pack.selected.length,
60
+ usedBytes: pack.usedBytes,
61
+ budgetBytes: pack.budgetBytes,
62
+ droppedForBudget: pack.droppedForBudget,
63
+ });
64
+ const loop = await runBugModelLoop(state, workspace, report, evidence, pack);
65
+ return finishPipeline(state, workspace, loop, evidence);
66
+ }
67
+ export async function investigateBug(input, deps) {
68
+ const state = buildBugRunState(input, deps, computeBugFingerprint(input.report, input.modelId));
69
+ let report;
70
+ try {
71
+ report = await runPipeline(state);
72
+ }
73
+ catch (error) {
74
+ report =
75
+ error instanceof CancelledError
76
+ ? cancelledReport(state, EMPTY_BUG_LOOP, undefined, { frames: [], messages: [] })
77
+ : failedReport(state, error);
78
+ }
79
+ // Memory write-candidate (Issue #213): emit ONLY for terminal success outcomes
80
+ // (fix-applied / fix-proposed / investigation-only). NO-OP for cancelled / failed /
81
+ // rejected, and NO-OP when no port is injected. Emitted before emitCompleted so the audit
82
+ // ledger and MemoriaViva UI see the candidate alongside the run-completed event.
83
+ emitMemoryWriteCandidate(state.deps.memoryPort, report, state.input.workspaceRoot);
84
+ return emitCompleted(state, report);
85
+ }
@@ -0,0 +1,35 @@
1
+ import { type CandidateFile, type ConnectedContextPack, type EvidenceAtom, type ExplorationBudget, type ExplorationUsage, type OmittedContextEntry, type RetrievalQuery, type SelectedScope, type UncertaintyMarker } from "@oscharko-dev/keiko-contracts/connected-context";
2
+ import { type MicroIndex } from "./microIndex.js";
3
+ import { type RerankerSeam } from "./reranker.js";
4
+ export interface AssembleInput {
5
+ readonly scope: SelectedScope;
6
+ readonly query: RetrievalQuery;
7
+ readonly budget: ExplorationBudget;
8
+ readonly atoms: readonly EvidenceAtom[];
9
+ readonly ranked: readonly CandidateFile[];
10
+ readonly omittedFromRanking: readonly OmittedContextEntry[];
11
+ readonly excerpts: ReadonlyMap<string, ExcerptSource>;
12
+ readonly cacheIdentity?: readonly string[] | undefined;
13
+ readonly initialUsage?: ExplorationUsage;
14
+ readonly initialUncertainty?: readonly UncertaintyMarker[];
15
+ }
16
+ export interface ExcerptWindow {
17
+ readonly startLine: number;
18
+ readonly endLine: number;
19
+ readonly content: string;
20
+ }
21
+ export type ExcerptSource = string | ExcerptWindow | readonly ExcerptWindow[];
22
+ export interface AssembleOptions {
23
+ readonly maxBytesPerExcerpt?: number;
24
+ readonly editablePaths?: ReadonlySet<string>;
25
+ readonly reranker?: RerankerSeam;
26
+ readonly microIndex?: MicroIndex;
27
+ readonly nowMs?: () => number;
28
+ }
29
+ export interface AssembleResult {
30
+ readonly pack: ConnectedContextPack;
31
+ readonly fromIndex: boolean;
32
+ }
33
+ export declare function contextPackIndexKey(input: AssembleInput, options?: AssembleOptions): string;
34
+ export declare function assembleContextPack(input: AssembleInput, options?: AssembleOptions): Promise<AssembleResult>;
35
+ //# sourceMappingURL=assemble.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assemble.d.ts","sourceRoot":"","sources":["../../src/contextpack/assemble.ts"],"names":[],"mappings":"AAQA,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,oBAAoB,EAIzB,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACvB,MAAM,iDAAiD,CAAC;AAIzD,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,EAAoB,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAIpE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,CAAC;IAC1C,QAAQ,CAAC,kBAAkB,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAC5D,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACtD,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACvD,QAAQ,CAAC,YAAY,CAAC,EAAE,gBAAgB,CAAC;IACzC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;CAC5D;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,aAAa,GAAG,SAAS,aAAa,EAAE,CAAC;AAE9E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC7C,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAC;IACjC,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;IACjC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AA0fD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,MAAM,CAQ3F;AAED,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,aAAa,EACpB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,cAAc,CAAC,CAoCzB"}