@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,11 @@
1
+ export type { AnchorExtractionInput, AnchorExtractionResult, SearchAnchor, SearchAnchorKind, } from "./anchors.js";
2
+ export { extractAnchors } from "./anchors.js";
3
+ export type { RetrievalIntent, RetrievalIntentClassification } from "./intent.js";
4
+ export { classifyRetrievalIntent } from "./intent.js";
5
+ export type { ClarificationPrompt, ClarificationReason, CreatePlanDeps, CreatePlanInput, ExplorationPlan, ExplorationPlanState, RetrievalRing, RetrievalRingKind, } from "./plan.js";
6
+ export { createExplorationPlan } from "./plan.js";
7
+ export type { GovernorState, GovernorStatus } from "./governor.js";
8
+ export { advanceRing, applyUsage, canContinue, complete, createGovernor } from "./governor.js";
9
+ export type { PlanAndGovernResult } from "./explorationPlanner.js";
10
+ export { planAndGovern, planExploration } from "./explorationPlanner.js";
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/planner/index.ts"],"names":[],"mappings":"AAIA,YAAY,EACV,qBAAqB,EACrB,sBAAsB,EACtB,YAAY,EACZ,gBAAgB,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,YAAY,EAAE,eAAe,EAAE,6BAA6B,EAAE,MAAM,aAAa,CAAC;AAClF,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAEtD,YAAY,EACV,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,EACd,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,aAAa,EACb,iBAAiB,GAClB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAElD,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/F,YAAY,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC"}
@@ -0,0 +1,8 @@
1
+ // Public sub-barrel for the exploration planner and budget governor (Epic #177, Issue #181).
2
+ // External consumers import every planner symbol through this module; internal modules
3
+ // (anchors.ts, plan.ts, governor.ts, explorationPlanner.ts) are implementation detail.
4
+ export { extractAnchors } from "./anchors.js";
5
+ export { classifyRetrievalIntent } from "./intent.js";
6
+ export { createExplorationPlan } from "./plan.js";
7
+ export { advanceRing, applyUsage, canContinue, complete, createGovernor } from "./governor.js";
8
+ export { planAndGovern, planExploration } from "./explorationPlanner.js";
@@ -0,0 +1,8 @@
1
+ import type { SelectedScope } from "@oscharko-dev/keiko-contracts/connected-context";
2
+ export type RetrievalIntent = "project-metadata" | "repository-overview" | "targeted-code-search" | "diagnostic-search" | "clarification-needed";
3
+ export interface RetrievalIntentClassification {
4
+ readonly intent: RetrievalIntent;
5
+ readonly normalizedTerms: readonly string[];
6
+ }
7
+ export declare function classifyRetrievalIntent(queryText: string, _scope?: SelectedScope): RetrievalIntentClassification;
8
+ //# sourceMappingURL=intent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"intent.d.ts","sourceRoot":"","sources":["../../src/planner/intent.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iDAAiD,CAAC;AAErF,MAAM,MAAM,eAAe,GACvB,kBAAkB,GAClB,qBAAqB,GACrB,sBAAsB,GACtB,mBAAmB,GACnB,sBAAsB,CAAC;AAE3B,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7C;AAuJD,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,aAAa,GACrB,6BAA6B,CAqB/B"}
@@ -0,0 +1,140 @@
1
+ // Deterministic retrieval-intent classification for connected-context planning.
2
+ // This module is intentionally pure: no IO, no clock, no model calls.
3
+ const BASIC_STOP_WORDS = new Set([
4
+ "the",
5
+ "and",
6
+ "for",
7
+ "of",
8
+ "in",
9
+ "on",
10
+ "at",
11
+ "to",
12
+ "a",
13
+ "an",
14
+ "is",
15
+ "are",
16
+ "was",
17
+ "were",
18
+ "be",
19
+ "been",
20
+ "being",
21
+ "do",
22
+ "does",
23
+ "did",
24
+ "how",
25
+ "why",
26
+ "what",
27
+ "which",
28
+ "where",
29
+ "when",
30
+ "who",
31
+ "das",
32
+ "dass",
33
+ "der",
34
+ "die",
35
+ "ein",
36
+ "eine",
37
+ "einer",
38
+ "einem",
39
+ "einen",
40
+ "ist",
41
+ "sind",
42
+ "und",
43
+ "oder",
44
+ "welche",
45
+ "welcher",
46
+ "welches",
47
+ "welchen",
48
+ "wie",
49
+ "wo",
50
+ "wird",
51
+ "werden",
52
+ "zu",
53
+ ]);
54
+ const PROJECT_METADATA_PATTERNS = [
55
+ { term: "typescript", pattern: /\btype[\s_-]?script\b/iu },
56
+ { term: "javascript", pattern: /\bjava[\s_-]?script\b/iu },
57
+ { term: "node", pattern: /\bnode(?:\.js)?\b/iu },
58
+ { term: "package-json", pattern: /\bpackage\.json\b/iu },
59
+ { term: "package-manager", pattern: /\bpackage[\s_-]?manager\b/iu },
60
+ { term: "package-manager", pattern: /\bpaket[\s_-]?manager\b/iu },
61
+ { term: "tsconfig", pattern: /\btsconfig(?:\.[a-z0-9]+)?\b/iu },
62
+ { term: "dependency", pattern: /\bdevdependencies\b|\bdependencies\b|\bdependency\b/iu },
63
+ { term: "dependency", pattern: /\babhaengigkeit(?:en)?\b|\babhängigkeit(?:en)?\b/iu },
64
+ { term: "script", pattern: /\bscripts?\b|\bskripte?\b/iu },
65
+ { term: "version", pattern: /\bversion(?:en)?\b/iu },
66
+ { term: "framework", pattern: /\bframeworks?\b/iu },
67
+ { term: "test-runner", pattern: /\btest[\s_-]?runner\b|\btestumgebung\b/iu },
68
+ { term: "build", pattern: /\bbuild\b|\bgebaut\b|\bbauen\b/iu },
69
+ { term: "npm", pattern: /\bnpm\b/iu },
70
+ { term: "pnpm", pattern: /\bpnpm\b/iu },
71
+ { term: "yarn", pattern: /\byarn\b/iu },
72
+ { term: "vite", pattern: /\bvite\b/iu },
73
+ { term: "vitest", pattern: /\bvitest\b/iu },
74
+ { term: "jest", pattern: /\bjest\b/iu },
75
+ { term: "playwright", pattern: /\bplaywright\b/iu },
76
+ { term: "cypress", pattern: /\bcypress\b/iu },
77
+ { term: "nextjs", pattern: /\bnext(?:\.js)?\b/iu },
78
+ { term: "react", pattern: /\breact\b/iu },
79
+ { term: "eslint", pattern: /\beslint\b/iu },
80
+ ];
81
+ const REPOSITORY_OVERVIEW_PATTERNS = [
82
+ { term: "architecture", pattern: /\barchitecture\b|\barchitektur\b/iu },
83
+ { term: "overview", pattern: /\boverview\b|\bueberblick\b|\büberblick\b/iu },
84
+ { term: "structure", pattern: /\bstructure\b|\bstruktur\b|\baufbau\b/iu },
85
+ { term: "repository", pattern: /\brepository\b|\brepo\b|\bcodebase\b/iu },
86
+ { term: "modules", pattern: /\bmodules?\b|\bmodule\b|\bpakete\b|\bpackages\b/iu },
87
+ { term: "components", pattern: /\bcomponents?\b|\bkomponenten\b/iu },
88
+ ];
89
+ const DIAGNOSTIC_PATTERNS = [
90
+ { term: "error", pattern: /\berror\b|\bfehler\b|\bexception\b|\btraceback\b/iu },
91
+ { term: "stacktrace", pattern: /\bstack[\s_-]?trace\b|\bstacktrace\b/iu },
92
+ { term: "failure", pattern: /\bfail(?:ed|ing|ure)?\b|\bscheitert\b|\bkaputt\b/iu },
93
+ { term: "bug", pattern: /\bbug\b|\bdefect\b|\bregression\b/iu },
94
+ { term: "http-status", pattern: /\b[45]\d{2}\b|\bhttp\b/iu },
95
+ ];
96
+ const TARGETED_CODE_PATTERNS = [
97
+ { term: "path", pattern: /(?:[\w.-]+\/)+[\w.-]+/u },
98
+ { term: "quoted", pattern: /"[^"\n]+"|'[^'\n]+'|`[^`\n]+`/u },
99
+ { term: "identifier", pattern: /\b[A-Za-z_$][A-Za-z0-9_$]*[A-Z][A-Za-z0-9_$]*\b/u },
100
+ { term: "symbol", pattern: /\b(function|class|interface|type|const|let|var)\s+[A-Za-z_]/iu },
101
+ ];
102
+ function normalizeQueryText(queryText) {
103
+ return queryText.normalize("NFKD").replace(/\p{M}/gu, "").toLowerCase();
104
+ }
105
+ function searchableTokens(normalized) {
106
+ return (normalized
107
+ .split(/[^a-z0-9_.-]+/u)
108
+ .filter((token) => token.length >= 3 && !BASIC_STOP_WORDS.has(token))
109
+ // `.`, `-` and `_` are kept inside tokens (so `package.json`/`tsconfig.base` survive), but a
110
+ // token built only from those separators (e.g. `...`, `--`, `__`) is not searchable. Require at
111
+ // least one alphanumeric character so a pure-punctuation prompt resolves to clarification-needed.
112
+ .filter((token) => /[a-z0-9]/u.test(token)));
113
+ }
114
+ function matchedTerms(queryText, normalized, patterns) {
115
+ const terms = new Set();
116
+ for (const entry of patterns) {
117
+ if (entry.pattern.test(queryText) || entry.pattern.test(normalized)) {
118
+ terms.add(entry.term);
119
+ }
120
+ }
121
+ return [...terms].sort();
122
+ }
123
+ function classifyByPatterns(queryText, normalized, patterns, intent) {
124
+ const terms = matchedTerms(queryText, normalized, patterns);
125
+ return terms.length === 0 ? undefined : { intent, normalizedTerms: terms };
126
+ }
127
+ export function classifyRetrievalIntent(queryText, _scope) {
128
+ const trimmed = queryText.trim();
129
+ const normalized = normalizeQueryText(trimmed);
130
+ if (trimmed.length === 0 || searchableTokens(normalized).length === 0) {
131
+ return { intent: "clarification-needed", normalizedTerms: [] };
132
+ }
133
+ return (classifyByPatterns(trimmed, normalized, PROJECT_METADATA_PATTERNS, "project-metadata") ??
134
+ classifyByPatterns(trimmed, normalized, DIAGNOSTIC_PATTERNS, "diagnostic-search") ??
135
+ classifyByPatterns(trimmed, normalized, TARGETED_CODE_PATTERNS, "targeted-code-search") ??
136
+ classifyByPatterns(trimmed, normalized, REPOSITORY_OVERVIEW_PATTERNS, "repository-overview") ?? {
137
+ intent: "targeted-code-search",
138
+ normalizedTerms: searchableTokens(normalized).slice(0, 8),
139
+ });
140
+ }
@@ -0,0 +1,43 @@
1
+ import { CONNECTED_CONTEXT_SCHEMA_VERSION, type ExplorationBudget, type RetrievalQuery, type SelectedScope } from "@oscharko-dev/keiko-contracts/connected-context";
2
+ import type { SearchLimits } from "@oscharko-dev/keiko-workspace";
3
+ import { type SearchAnchor } from "./anchors.js";
4
+ import { type RetrievalIntent } from "./intent.js";
5
+ export type ExplorationPlanState = "ready" | "completed" | "budget-exhausted" | "clarification-needed" | "scope-invalid";
6
+ export type RetrievalRingKind = "lexical" | "structural" | "git-history";
7
+ export interface RetrievalRing {
8
+ readonly kind: RetrievalRingKind;
9
+ readonly label: string;
10
+ readonly anchorTerms: readonly string[];
11
+ readonly searchLimits: SearchLimits;
12
+ readonly rationale: string;
13
+ }
14
+ export type ClarificationReason = "no-anchors" | "too-generic" | "scope-empty" | "scope-invalid";
15
+ export interface ClarificationPrompt {
16
+ readonly reason: ClarificationReason;
17
+ readonly suggestedQuestions: readonly string[];
18
+ readonly minimumAnchorCount: number;
19
+ }
20
+ export interface ExplorationPlan {
21
+ readonly schemaVersion: typeof CONNECTED_CONTEXT_SCHEMA_VERSION;
22
+ readonly planId: string;
23
+ readonly state: ExplorationPlanState;
24
+ readonly retrievalIntent: RetrievalIntent;
25
+ readonly scope: SelectedScope;
26
+ readonly query: RetrievalQuery;
27
+ readonly anchors: readonly SearchAnchor[];
28
+ readonly rings: readonly RetrievalRing[];
29
+ readonly budget: ExplorationBudget;
30
+ readonly clarification: ClarificationPrompt | undefined;
31
+ readonly createdAtMs: number;
32
+ }
33
+ export interface CreatePlanInput {
34
+ readonly scope: SelectedScope;
35
+ readonly query: RetrievalQuery;
36
+ readonly budget?: ExplorationBudget;
37
+ readonly maxAnchors?: number;
38
+ }
39
+ export interface CreatePlanDeps {
40
+ readonly nowMs?: () => number;
41
+ }
42
+ export declare function createExplorationPlan(input: CreatePlanInput, deps?: CreatePlanDeps): ExplorationPlan;
43
+ //# sourceMappingURL=plan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../src/planner/plan.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,gCAAgC,EAGhC,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,iDAAiD,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAElE,OAAO,EAAkB,KAAK,YAAY,EAAyB,MAAM,cAAc,CAAC;AACxF,OAAO,EAEL,KAAK,eAAe,EAErB,MAAM,aAAa,CAAC;AAQrB,MAAM,MAAM,oBAAoB,GAC5B,OAAO,GACP,WAAW,GACX,kBAAkB,GAClB,sBAAsB,GACtB,eAAe,CAAC;AAEpB,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,YAAY,GAAG,aAAa,CAAC;AAEzE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,MAAM,mBAAmB,GAAG,YAAY,GAAG,aAAa,GAAG,aAAa,GAAG,eAAe,CAAC;AAEjG,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;IACrC,QAAQ,CAAC,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/C,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;CACrC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,aAAa,EAAE,OAAO,gCAAgC,CAAC;IAChE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,oBAAoB,CAAC;IACrC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1C,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,CAAC;IAC1C,QAAQ,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,CAAC;IACzC,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,aAAa,EAAE,mBAAmB,GAAG,SAAS,CAAC;IACxD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC;IACpC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;CAC/B;AA2QD,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,eAAe,EACtB,IAAI,CAAC,EAAE,cAAc,GACpB,eAAe,CAqCjB"}
@@ -0,0 +1,237 @@
1
+ // Exploration plan factory and retrieval-ring composition (Epic #177, Issue #181).
2
+ // Consumes #178 contracts and #179 search-limits surface. Produces a JSON-safe ExplorationPlan
3
+ // BEFORE any retrieval work runs. Deterministic planId via node:crypto SHA-256. No IO, no
4
+ // network. Execution and persistence of plans land in #182/#183/#187.
5
+ import { createHash } from "node:crypto";
6
+ import { CONNECTED_CONTEXT_SCHEMA_VERSION, DEFAULT_EXPLORATION_BUDGET, validateSelectedScope, } from "@oscharko-dev/keiko-contracts/connected-context";
7
+ import { extractAnchors } from "./anchors.js";
8
+ import { classifyRetrievalIntent, } from "./intent.js";
9
+ // ─── Constants ────────────────────────────────────────────────────────────────
10
+ const DEFAULT_MAX_ANCHORS = 8;
11
+ const RING_WEIGHTS = {
12
+ lexical: 0.55,
13
+ structural: 0.3,
14
+ "git-history": 0.15,
15
+ };
16
+ // Lexical/structural scanning is transient — each candidate file is read to match lines, then
17
+ // discarded — so its breadth is bounded by elapsedMsMax, NOT by the excerpt-byte budget the model
18
+ // context is built from. Deriving maxFilesScanned from the excerpt slice capped the scan at ~4
19
+ // files and starved multi-file connected scopes (Epic #177 retrieval defect): the search could
20
+ // never reach the file a question was actually about. These ceilings let a ring examine the
21
+ // connected scope broadly while the excerpt READ phase keeps enforcing filesReadMax/excerptBytesMax.
22
+ const SCAN_FILE_CEILING = 2048;
23
+ // Evidence atoms returned for ranking. With the search facade's per-file match cap this represents
24
+ // many candidate files (well beyond filesReadMax) so the ranker has real choice before the excerpt
25
+ // phase reads the top files.
26
+ const MATCH_RETURN_CEILING = 256;
27
+ // Per-file scan read cap (2 MiB). A connected file up to this size is fully read and matched so it
28
+ // is never skipped as size-exceeded regardless of format; only files larger than this are omitted.
29
+ // This bounds the transient per-file read during line matching, NOT the excerpt content that enters
30
+ // the pack (Epic #177 retrieval fix — the prior excerpt-byte-derived cap of ~18 KiB silently dropped
31
+ // larger files from the search entirely).
32
+ const SCAN_BYTES_PER_FILE = 2_097_152;
33
+ const RING_LABELS = {
34
+ lexical: "Lexical scan across the selected scope",
35
+ structural: "Structural lookups around identifier and path anchors",
36
+ "git-history": "Recent git-history signal across the workspace",
37
+ };
38
+ const RING_RATIONALES = {
39
+ lexical: "Lexical anchors are always cheap to scan first and bound the working set.",
40
+ structural: "Identifier or path anchors warrant structural lookups so callers are reached without a full text scan.",
41
+ "git-history": "Workspace-level queries benefit from recency signal because no sub-scope was preselected.",
42
+ };
43
+ const NO_ANCHOR_QUESTIONS = [
44
+ "Which file or symbol should I focus on?",
45
+ "What error message did you see?",
46
+ "Name a function or class to start from.",
47
+ ];
48
+ const TOO_GENERIC_QUESTIONS = [
49
+ "Can you name the file, class, or function this should touch?",
50
+ "Is there a recent error message or log line that anchors the question?",
51
+ ];
52
+ const SCOPE_EMPTY_QUESTIONS = [
53
+ "Which folder or files within the workspace should I look at?",
54
+ "Is this question about the whole workspace, or a specific module?",
55
+ ];
56
+ const SCOPE_INVALID_QUESTIONS = [
57
+ "The selected scope did not validate; please reselect files or a directory.",
58
+ ];
59
+ // ─── Budget slicing ───────────────────────────────────────────────────────────
60
+ function atLeastOne(value) {
61
+ return Math.max(1, Math.floor(value));
62
+ }
63
+ function sliceLimits(budget, weight) {
64
+ // Scanning is transient — each file is read to match lines, then discarded — and is bounded by
65
+ // elapsedMsMax, NOT by the excerpt-byte budget the model context is built from. Both the per-file
66
+ // read cap and the scan breadth are therefore decoupled from excerptBytesMax (Epic #177 retrieval
67
+ // fix); deriving them from the excerpt slice capped scanning at ~4 files of ~18 KiB and silently
68
+ // skipped any larger or later-sorted file. The excerpt READ phase still enforces filesReadMax /
69
+ // excerptBytesMax when it incorporates file content into the pack.
70
+ return {
71
+ maxFilesScanned: atLeastOne(SCAN_FILE_CEILING * weight),
72
+ maxMatchesReturned: atLeastOne(MATCH_RETURN_CEILING * weight),
73
+ maxBytesPerFileScanned: SCAN_BYTES_PER_FILE,
74
+ elapsedMsMax: atLeastOne(budget.elapsedMsMax * weight),
75
+ };
76
+ }
77
+ // ─── Ring composition ─────────────────────────────────────────────────────────
78
+ function anchorTerms(anchors) {
79
+ return anchors.map((a) => a.term);
80
+ }
81
+ function hasKind(anchors, kind) {
82
+ return anchors.some((a) => a.kind === kind);
83
+ }
84
+ function buildRing(kind, anchors, budget) {
85
+ return {
86
+ kind,
87
+ label: RING_LABELS[kind],
88
+ anchorTerms: anchorTerms(anchors),
89
+ searchLimits: sliceLimits(budget, RING_WEIGHTS[kind]),
90
+ rationale: RING_RATIONALES[kind],
91
+ };
92
+ }
93
+ function composeRings(anchors, scope, budget) {
94
+ const rings = [buildRing("lexical", anchors, budget)];
95
+ if (hasKind(anchors, "identifier") || hasKind(anchors, "path")) {
96
+ rings.push(buildRing("structural", anchors, budget));
97
+ }
98
+ if (scope.relativePaths.length === 0) {
99
+ rings.push(buildRing("git-history", anchors, budget));
100
+ }
101
+ return rings;
102
+ }
103
+ // ─── Clarification helpers ────────────────────────────────────────────────────
104
+ function maxAnchorWeight(anchors) {
105
+ let max = 0;
106
+ for (const a of anchors) {
107
+ if (a.weight > max) {
108
+ max = a.weight;
109
+ }
110
+ }
111
+ return max;
112
+ }
113
+ function buildClarification(reason, suggestedQuestions, minimumAnchorCount) {
114
+ return { reason, suggestedQuestions, minimumAnchorCount };
115
+ }
116
+ function explicitConnectionIsReady(scope, intent) {
117
+ if (scope.explicitConnection !== true) {
118
+ return false;
119
+ }
120
+ if (scope.kind !== "workspace-root") {
121
+ return true;
122
+ }
123
+ return intent === "project-metadata" || intent === "repository-overview";
124
+ }
125
+ function decideClarification(anchors, scope, intent) {
126
+ if (anchors.length === 0) {
127
+ return {
128
+ state: "clarification-needed",
129
+ clarification: buildClarification("no-anchors", NO_ANCHOR_QUESTIONS, 1),
130
+ };
131
+ }
132
+ // When the user EXPLICITLY connected a folder/files to the chat (a Files↔Chat edge or a scope
133
+ // pill), they have already narrowed the search to a bounded area. The "too-generic" and
134
+ // "scope-empty" gates exist to stop vague questions burning budget over the broad workspace;
135
+ // keep those gates for workspace-root connections even when they were explicitly selected.
136
+ if (explicitConnectionIsReady(scope, intent)) {
137
+ return { state: "ready", clarification: undefined };
138
+ }
139
+ // Threshold is <= literal weight so a prompt yielding only `literal` anchors (weight 0.5,
140
+ // i.e. no quoted/path/identifier signal) requests clarification before any retrieval runs.
141
+ if (maxAnchorWeight(anchors) <= 0.5) {
142
+ return {
143
+ state: "clarification-needed",
144
+ clarification: buildClarification("too-generic", TOO_GENERIC_QUESTIONS, 1),
145
+ };
146
+ }
147
+ if (scope.relativePaths.length === 0 && anchors.length < 2) {
148
+ return {
149
+ state: "clarification-needed",
150
+ clarification: buildClarification("scope-empty", SCOPE_EMPTY_QUESTIONS, 2),
151
+ };
152
+ }
153
+ return { state: "ready", clarification: undefined };
154
+ }
155
+ function canonicalize(seed) {
156
+ // JSON.stringify with sorted keys via explicit ordering — never relies on object key order.
157
+ return JSON.stringify([
158
+ seed.scopeId,
159
+ seed.queryKind,
160
+ seed.queryText,
161
+ seed.retrievalIntent,
162
+ [...seed.anchorTerms].sort(),
163
+ [...seed.ringKinds].sort(),
164
+ ]);
165
+ }
166
+ function derivePlanId(seed) {
167
+ const hash = createHash("sha256").update(canonicalize(seed)).digest("hex");
168
+ return `pl-${hash.slice(0, 16)}`;
169
+ }
170
+ function resolveInputs(input, deps) {
171
+ return {
172
+ budget: input.budget ?? DEFAULT_EXPLORATION_BUDGET,
173
+ maxAnchors: input.maxAnchors ?? DEFAULT_MAX_ANCHORS,
174
+ nowMs: deps?.nowMs ?? Date.now,
175
+ };
176
+ }
177
+ function buildScopeInvalidPlan(input, resolved, classification) {
178
+ const clarification = buildClarification("scope-invalid", SCOPE_INVALID_QUESTIONS, 0);
179
+ const seed = {
180
+ scopeId: input.scope.scopeId,
181
+ queryKind: input.query.kind,
182
+ queryText: input.query.text,
183
+ retrievalIntent: classification.intent,
184
+ anchorTerms: [],
185
+ ringKinds: [],
186
+ };
187
+ return {
188
+ schemaVersion: CONNECTED_CONTEXT_SCHEMA_VERSION,
189
+ planId: derivePlanId(seed),
190
+ state: "scope-invalid",
191
+ retrievalIntent: classification.intent,
192
+ scope: input.scope,
193
+ query: input.query,
194
+ anchors: [],
195
+ rings: [],
196
+ budget: resolved.budget,
197
+ clarification,
198
+ createdAtMs: resolved.nowMs(),
199
+ };
200
+ }
201
+ export function createExplorationPlan(input, deps) {
202
+ const resolved = resolveInputs(input, deps);
203
+ const classification = classifyRetrievalIntent(input.query.text, input.scope);
204
+ const scopeResult = validateSelectedScope(input.scope);
205
+ if (!scopeResult.ok) {
206
+ return buildScopeInvalidPlan(input, resolved, classification);
207
+ }
208
+ const extraction = extractAnchors({
209
+ text: input.query.text,
210
+ maxAnchors: resolved.maxAnchors,
211
+ });
212
+ const decision = decideClarification(extraction.anchors, input.scope, classification.intent);
213
+ const rings = decision.state === "ready"
214
+ ? composeRings(extraction.anchors, input.scope, resolved.budget)
215
+ : [];
216
+ const seed = {
217
+ scopeId: input.scope.scopeId,
218
+ queryKind: input.query.kind,
219
+ queryText: input.query.text,
220
+ retrievalIntent: classification.intent,
221
+ anchorTerms: extraction.anchors.map((a) => a.term),
222
+ ringKinds: rings.map((r) => r.kind),
223
+ };
224
+ return {
225
+ schemaVersion: CONNECTED_CONTEXT_SCHEMA_VERSION,
226
+ planId: derivePlanId(seed),
227
+ state: decision.state,
228
+ retrievalIntent: classification.intent,
229
+ scope: input.scope,
230
+ query: input.query,
231
+ anchors: extraction.anchors,
232
+ rings,
233
+ budget: resolved.budget,
234
+ clarification: decision.clarification,
235
+ createdAtMs: resolved.nowMs(),
236
+ };
237
+ }
@@ -0,0 +1,23 @@
1
+ import { type PromptEnhancementWireRequest, type PromptEnhancementWireResponse } from "@oscharko-dev/keiko-contracts";
2
+ import { type ConfiguredCapabilitySource, type GatewayConfig } from "@oscharko-dev/keiko-model-gateway";
3
+ import type { PromptEnhancementRecordInput } from "@oscharko-dev/keiko-evidence";
4
+ export declare class PromptEnhancementInputError extends Error {
5
+ readonly errors: readonly string[];
6
+ constructor(errors: readonly string[]);
7
+ }
8
+ export declare class PromptEnhancementCancelledError extends Error {
9
+ constructor();
10
+ }
11
+ export interface RunPromptEnhancementDeps {
12
+ readonly gatewayRoutingConfig: ConfiguredCapabilitySource | undefined;
13
+ readonly signal?: AbortSignal | undefined;
14
+ }
15
+ export type PromptEnhancementGatewayRoutingConfig = ConfiguredCapabilitySource;
16
+ export declare function promptEnhancementGatewayRoutingConfig(config: GatewayConfig | undefined): PromptEnhancementGatewayRoutingConfig | undefined;
17
+ export declare function runPromptEnhancement(request: PromptEnhancementWireRequest, deps: RunPromptEnhancementDeps): PromptEnhancementWireResponse;
18
+ export declare function buildPromptEnhancementRecordInput(options: {
19
+ readonly rawInput: string;
20
+ readonly result: PromptEnhancementWireResponse;
21
+ readonly recordedAt: string;
22
+ }): PromptEnhancementRecordInput;
23
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/promptEnhancer/index.ts"],"names":[],"mappings":"AAcA,OAAO,EAYL,KAAK,4BAA4B,EACjC,KAAK,6BAA6B,EAEnC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAGL,KAAK,0BAA0B,EAC/B,KAAK,aAAa,EACnB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,8BAA8B,CAAC;AAMjF,qBAAa,2BAA4B,SAAQ,KAAK;IACpD,SAAgB,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;gBACvB,MAAM,EAAE,SAAS,MAAM,EAAE;CAK7C;AAKD,qBAAa,+BAAgC,SAAQ,KAAK;;CAKzD;AAED,MAAM,WAAW,wBAAwB;IAGvC,QAAQ,CAAC,oBAAoB,EAAE,0BAA0B,GAAG,SAAS,CAAC;IAEtE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAC3C;AAED,MAAM,MAAM,qCAAqC,GAAG,0BAA0B,CAAC;AAE/E,wBAAgB,qCAAqC,CACnD,MAAM,EAAE,aAAa,GAAG,SAAS,GAChC,qCAAqC,GAAG,SAAS,CAQnD;AA8ND,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,4BAA4B,EACrC,IAAI,EAAE,wBAAwB,GAC7B,6BAA6B,CA6B/B;AAyCD,wBAAgB,iCAAiC,CAAC,OAAO,EAAE;IACzD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,6BAA6B,CAAC;IAC/C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B,GAAG,4BAA4B,CA4B/B"}