noterai 0.1.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/README.md +368 -0
  2. package/bin/noter.js +218 -0
  3. package/bin/noter.js.map +1 -0
  4. package/package.json +73 -0
  5. package/packages/client/dist/assets/geist-mono-latin-400-normal-CoULgQGM.woff +0 -0
  6. package/packages/client/dist/assets/geist-mono-latin-400-normal-LC9RFr9I.woff2 +0 -0
  7. package/packages/client/dist/assets/index-CBiNAMaA.js +264 -0
  8. package/packages/client/dist/assets/index-u7i5Fle2.css +1 -0
  9. package/packages/client/dist/assets/space-grotesk-latin-500-normal-CNSSEhBt.woff +0 -0
  10. package/packages/client/dist/assets/space-grotesk-latin-500-normal-lFbtlQH6.woff2 +0 -0
  11. package/packages/client/dist/assets/space-grotesk-latin-600-normal-BflQw4A9.woff +0 -0
  12. package/packages/client/dist/assets/space-grotesk-latin-600-normal-DjKNqYRj.woff2 +0 -0
  13. package/packages/client/dist/assets/vendor-react-DHeZC_T5.js +17 -0
  14. package/packages/client/dist/index.html +14 -0
  15. package/packages/server/dist/adapters/claudeAdapter.d.ts +34 -0
  16. package/packages/server/dist/adapters/claudeAdapter.d.ts.map +1 -0
  17. package/packages/server/dist/adapters/claudeAdapter.js +281 -0
  18. package/packages/server/dist/adapters/claudeAdapter.js.map +1 -0
  19. package/packages/server/dist/adapters/codexAdapter.d.ts +39 -0
  20. package/packages/server/dist/adapters/codexAdapter.d.ts.map +1 -0
  21. package/packages/server/dist/adapters/codexAdapter.js +347 -0
  22. package/packages/server/dist/adapters/codexAdapter.js.map +1 -0
  23. package/packages/server/dist/adapters/droidAdapter.d.ts +34 -0
  24. package/packages/server/dist/adapters/droidAdapter.d.ts.map +1 -0
  25. package/packages/server/dist/adapters/droidAdapter.js +109 -0
  26. package/packages/server/dist/adapters/droidAdapter.js.map +1 -0
  27. package/packages/server/dist/adapters/genericAdapter.d.ts +50 -0
  28. package/packages/server/dist/adapters/genericAdapter.d.ts.map +1 -0
  29. package/packages/server/dist/adapters/genericAdapter.js +203 -0
  30. package/packages/server/dist/adapters/genericAdapter.js.map +1 -0
  31. package/packages/server/dist/adapters/index.d.ts +7 -0
  32. package/packages/server/dist/adapters/index.d.ts.map +1 -0
  33. package/packages/server/dist/adapters/index.js +7 -0
  34. package/packages/server/dist/adapters/index.js.map +1 -0
  35. package/packages/server/dist/adapters/opencodeAdapter.d.ts +28 -0
  36. package/packages/server/dist/adapters/opencodeAdapter.d.ts.map +1 -0
  37. package/packages/server/dist/adapters/opencodeAdapter.js +265 -0
  38. package/packages/server/dist/adapters/opencodeAdapter.js.map +1 -0
  39. package/packages/server/dist/adapters/opencodeSessionManager.d.ts +13 -0
  40. package/packages/server/dist/adapters/opencodeSessionManager.d.ts.map +1 -0
  41. package/packages/server/dist/adapters/opencodeSessionManager.js +230 -0
  42. package/packages/server/dist/adapters/opencodeSessionManager.js.map +1 -0
  43. package/packages/server/dist/adapters/pathUtils.d.ts +54 -0
  44. package/packages/server/dist/adapters/pathUtils.d.ts.map +1 -0
  45. package/packages/server/dist/adapters/pathUtils.js +86 -0
  46. package/packages/server/dist/adapters/pathUtils.js.map +1 -0
  47. package/packages/server/dist/adapters/piAdapter.d.ts +34 -0
  48. package/packages/server/dist/adapters/piAdapter.d.ts.map +1 -0
  49. package/packages/server/dist/adapters/piAdapter.js +307 -0
  50. package/packages/server/dist/adapters/piAdapter.js.map +1 -0
  51. package/packages/server/dist/autoDetect.d.ts +15 -0
  52. package/packages/server/dist/autoDetect.d.ts.map +1 -0
  53. package/packages/server/dist/autoDetect.js +102 -0
  54. package/packages/server/dist/autoDetect.js.map +1 -0
  55. package/packages/server/dist/config.d.ts +29 -0
  56. package/packages/server/dist/config.d.ts.map +1 -0
  57. package/packages/server/dist/config.js +96 -0
  58. package/packages/server/dist/config.js.map +1 -0
  59. package/packages/server/dist/eventStore.d.ts +14 -0
  60. package/packages/server/dist/eventStore.d.ts.map +1 -0
  61. package/packages/server/dist/eventStore.js +35 -0
  62. package/packages/server/dist/eventStore.js.map +1 -0
  63. package/packages/server/dist/hookWatcher.d.ts +24 -0
  64. package/packages/server/dist/hookWatcher.d.ts.map +1 -0
  65. package/packages/server/dist/hookWatcher.js +152 -0
  66. package/packages/server/dist/hookWatcher.js.map +1 -0
  67. package/packages/server/dist/index.d.ts +58 -0
  68. package/packages/server/dist/index.d.ts.map +1 -0
  69. package/packages/server/dist/index.js +527 -0
  70. package/packages/server/dist/index.js.map +1 -0
  71. package/packages/server/dist/llm/jsonExtractor.d.ts +39 -0
  72. package/packages/server/dist/llm/jsonExtractor.d.ts.map +1 -0
  73. package/packages/server/dist/llm/jsonExtractor.js +83 -0
  74. package/packages/server/dist/llm/jsonExtractor.js.map +1 -0
  75. package/packages/server/dist/llm/ollamaCache.d.ts +19 -0
  76. package/packages/server/dist/llm/ollamaCache.d.ts.map +1 -0
  77. package/packages/server/dist/llm/ollamaCache.js +31 -0
  78. package/packages/server/dist/llm/ollamaCache.js.map +1 -0
  79. package/packages/server/dist/llm/ollamaClient.d.ts +29 -0
  80. package/packages/server/dist/llm/ollamaClient.d.ts.map +1 -0
  81. package/packages/server/dist/llm/ollamaClient.js +117 -0
  82. package/packages/server/dist/llm/ollamaClient.js.map +1 -0
  83. package/packages/server/dist/llm/ollamaQueue.d.ts +7 -0
  84. package/packages/server/dist/llm/ollamaQueue.d.ts.map +1 -0
  85. package/packages/server/dist/llm/ollamaQueue.js +28 -0
  86. package/packages/server/dist/llm/ollamaQueue.js.map +1 -0
  87. package/packages/server/dist/llm/promptBuilder.d.ts +8 -0
  88. package/packages/server/dist/llm/promptBuilder.d.ts.map +1 -0
  89. package/packages/server/dist/llm/promptBuilder.js +85 -0
  90. package/packages/server/dist/llm/promptBuilder.js.map +1 -0
  91. package/packages/server/dist/llm/promptSections.d.ts +64 -0
  92. package/packages/server/dist/llm/promptSections.d.ts.map +1 -0
  93. package/packages/server/dist/llm/promptSections.js +128 -0
  94. package/packages/server/dist/llm/promptSections.js.map +1 -0
  95. package/packages/server/dist/llm/providerModels.d.ts +14 -0
  96. package/packages/server/dist/llm/providerModels.d.ts.map +1 -0
  97. package/packages/server/dist/llm/providerModels.js +67 -0
  98. package/packages/server/dist/llm/providerModels.js.map +1 -0
  99. package/packages/server/dist/llm/suggester.d.ts +12 -0
  100. package/packages/server/dist/llm/suggester.d.ts.map +1 -0
  101. package/packages/server/dist/llm/suggester.js +263 -0
  102. package/packages/server/dist/llm/suggester.js.map +1 -0
  103. package/packages/server/dist/llm/summarizer.d.ts +53 -0
  104. package/packages/server/dist/llm/summarizer.d.ts.map +1 -0
  105. package/packages/server/dist/llm/summarizer.js +174 -0
  106. package/packages/server/dist/llm/summarizer.js.map +1 -0
  107. package/packages/server/dist/persistence.d.ts +42 -0
  108. package/packages/server/dist/persistence.d.ts.map +1 -0
  109. package/packages/server/dist/persistence.js +103 -0
  110. package/packages/server/dist/persistence.js.map +1 -0
  111. package/packages/server/dist/repoContext.d.ts +60 -0
  112. package/packages/server/dist/repoContext.d.ts.map +1 -0
  113. package/packages/server/dist/repoContext.js +197 -0
  114. package/packages/server/dist/repoContext.js.map +1 -0
  115. package/packages/server/dist/routes/blueprint.d.ts +7 -0
  116. package/packages/server/dist/routes/blueprint.d.ts.map +1 -0
  117. package/packages/server/dist/routes/blueprint.js +529 -0
  118. package/packages/server/dist/routes/blueprint.js.map +1 -0
  119. package/packages/server/dist/routes/config.d.ts +17 -0
  120. package/packages/server/dist/routes/config.d.ts.map +1 -0
  121. package/packages/server/dist/routes/config.js +282 -0
  122. package/packages/server/dist/routes/config.js.map +1 -0
  123. package/packages/server/dist/routes/lmstudio.d.ts +4 -0
  124. package/packages/server/dist/routes/lmstudio.d.ts.map +1 -0
  125. package/packages/server/dist/routes/lmstudio.js +67 -0
  126. package/packages/server/dist/routes/lmstudio.js.map +1 -0
  127. package/packages/server/dist/routes/notes.d.ts +5 -0
  128. package/packages/server/dist/routes/notes.d.ts.map +1 -0
  129. package/packages/server/dist/routes/notes.js +60 -0
  130. package/packages/server/dist/routes/notes.js.map +1 -0
  131. package/packages/server/dist/routes/ollama.d.ts +4 -0
  132. package/packages/server/dist/routes/ollama.d.ts.map +1 -0
  133. package/packages/server/dist/routes/ollama.js +207 -0
  134. package/packages/server/dist/routes/ollama.js.map +1 -0
  135. package/packages/server/dist/routes/prompt.d.ts +4 -0
  136. package/packages/server/dist/routes/prompt.d.ts.map +1 -0
  137. package/packages/server/dist/routes/prompt.js +75 -0
  138. package/packages/server/dist/routes/prompt.js.map +1 -0
  139. package/packages/server/dist/routes/refineNotes.d.ts +4 -0
  140. package/packages/server/dist/routes/refineNotes.d.ts.map +1 -0
  141. package/packages/server/dist/routes/refineNotes.js +87 -0
  142. package/packages/server/dist/routes/refineNotes.js.map +1 -0
  143. package/packages/server/dist/routes/repoContext.d.ts +3 -0
  144. package/packages/server/dist/routes/repoContext.d.ts.map +1 -0
  145. package/packages/server/dist/routes/repoContext.js +15 -0
  146. package/packages/server/dist/routes/repoContext.js.map +1 -0
  147. package/packages/server/dist/routes/sessions.d.ts +15 -0
  148. package/packages/server/dist/routes/sessions.d.ts.map +1 -0
  149. package/packages/server/dist/routes/sessions.js +420 -0
  150. package/packages/server/dist/routes/sessions.js.map +1 -0
  151. package/packages/server/dist/routes/summarize.d.ts +6 -0
  152. package/packages/server/dist/routes/summarize.d.ts.map +1 -0
  153. package/packages/server/dist/routes/summarize.js +85 -0
  154. package/packages/server/dist/routes/summarize.js.map +1 -0
  155. package/packages/server/dist/server.d.ts +2 -0
  156. package/packages/server/dist/server.d.ts.map +1 -0
  157. package/packages/server/dist/server.js +6 -0
  158. package/packages/server/dist/server.js.map +1 -0
  159. package/packages/server/dist/sessionManager.d.ts +41 -0
  160. package/packages/server/dist/sessionManager.d.ts.map +1 -0
  161. package/packages/server/dist/sessionManager.js +493 -0
  162. package/packages/server/dist/sessionManager.js.map +1 -0
  163. package/packages/server/dist/sessionScanner.d.ts +22 -0
  164. package/packages/server/dist/sessionScanner.d.ts.map +1 -0
  165. package/packages/server/dist/sessionScanner.js +165 -0
  166. package/packages/server/dist/sessionScanner.js.map +1 -0
  167. package/packages/server/dist/sessionTitle.d.ts +17 -0
  168. package/packages/server/dist/sessionTitle.d.ts.map +1 -0
  169. package/packages/server/dist/sessionTitle.js +321 -0
  170. package/packages/server/dist/sessionTitle.js.map +1 -0
  171. package/packages/server/dist/stateManager.d.ts +38 -0
  172. package/packages/server/dist/stateManager.d.ts.map +1 -0
  173. package/packages/server/dist/stateManager.js +83 -0
  174. package/packages/server/dist/stateManager.js.map +1 -0
  175. package/packages/server/dist/wsServer.d.ts +27 -0
  176. package/packages/server/dist/wsServer.d.ts.map +1 -0
  177. package/packages/server/dist/wsServer.js +144 -0
  178. package/packages/server/dist/wsServer.js.map +1 -0
  179. package/packages/shared/dist/index.d.ts +3 -0
  180. package/packages/shared/dist/index.d.ts.map +1 -0
  181. package/packages/shared/dist/index.js +3 -0
  182. package/packages/shared/dist/index.js.map +1 -0
  183. package/packages/shared/dist/llm/mambaDetect.d.ts +84 -0
  184. package/packages/shared/dist/llm/mambaDetect.d.ts.map +1 -0
  185. package/packages/shared/dist/llm/mambaDetect.js +205 -0
  186. package/packages/shared/dist/llm/mambaDetect.js.map +1 -0
  187. package/packages/shared/dist/types.d.ts +184 -0
  188. package/packages/shared/dist/types.d.ts.map +1 -0
  189. package/packages/shared/dist/types.js +2 -0
  190. package/packages/shared/dist/types.js.map +1 -0
  191. package/scripts/postbuild.js +70 -0
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Attempt to extract JSON from raw model output.
3
+ * Tries multiple strategies in order:
4
+ * 1. Direct JSON.parse
5
+ * 2. Strip markdown code fences (```json ... ```) and retry
6
+ * 3. Regex extraction of first JSON object or array
7
+ * Returns null if no JSON found.
8
+ */
9
+ export function extractJSON(raw) {
10
+ if (!raw || !raw.trim())
11
+ return null;
12
+ const trimmed = raw.trim();
13
+ // Attempt 1: direct parse
14
+ try {
15
+ return JSON.parse(trimmed);
16
+ }
17
+ catch { }
18
+ // Attempt 2: strip markdown code fences
19
+ const stripped = trimmed.replace(/^```(?:json)?\s*\n?/i, '').replace(/\n?```$/, '').trim();
20
+ try {
21
+ return JSON.parse(stripped);
22
+ }
23
+ catch { }
24
+ // Attempt 3: regex extraction of JSON object or array
25
+ const objectMatch = stripped.match(/\{[\s\S]*\}/);
26
+ if (objectMatch) {
27
+ try {
28
+ return JSON.parse(objectMatch[0]);
29
+ }
30
+ catch { }
31
+ }
32
+ const arrayMatch = stripped.match(/\[[\s\S]*\]/);
33
+ if (arrayMatch) {
34
+ try {
35
+ return JSON.parse(arrayMatch[0]);
36
+ }
37
+ catch { }
38
+ }
39
+ return null;
40
+ }
41
+ /**
42
+ * Validate extracted data against a Zod schema.
43
+ * Returns the parsed data if valid, null otherwise.
44
+ */
45
+ export function validateAgainstSchema(data, schema) {
46
+ const result = schema.safeParse(data);
47
+ if (result.success)
48
+ return result.data;
49
+ return null;
50
+ }
51
+ /**
52
+ * Enforce JSON response from a model that may produce non-JSON output.
53
+ *
54
+ * Calls modelFn up to maxRetries times. On each attempt:
55
+ * 1. Extracts JSON from the raw response using extractJSON
56
+ * 2. Validates against the provided Zod schema
57
+ * 3. If validation fails, retries with corrective feedback
58
+ *
59
+ * If all attempts fail, throws an error with details.
60
+ */
61
+ export async function enforceJSONResponse(opts) {
62
+ const { prompt, schema, modelFn, maxRetries = 1 } = opts;
63
+ let lastError = null;
64
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
65
+ const currentPrompt = attempt === 0
66
+ ? prompt
67
+ : `${prompt}\n\nYour previous response was not valid JSON. Respond ONLY with valid JSON matching the required schema. Do not include any text outside the JSON object.`;
68
+ const raw = await modelFn(currentPrompt);
69
+ const extracted = extractJSON(raw);
70
+ if (extracted !== null) {
71
+ const validated = validateAgainstSchema(extracted, schema);
72
+ if (validated !== null) {
73
+ return validated;
74
+ }
75
+ lastError = 'Extracted JSON does not match expected schema';
76
+ }
77
+ else {
78
+ lastError = 'Could not extract valid JSON from model output';
79
+ }
80
+ }
81
+ throw new Error(`enforceJSONResponse failed after ${1 + maxRetries} attempts: ${lastError}`);
82
+ }
83
+ //# sourceMappingURL=jsonExtractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonExtractor.js","sourceRoot":"","sources":["../../src/llm/jsonExtractor.ts"],"names":[],"mappings":"AASA;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE;QAAE,OAAO,IAAI,CAAC;IAErC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAE3B,0BAA0B;IAC1B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IAEV,wCAAwC;IACxC,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,sBAAsB,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3F,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IAEV,sDAAsD;IACtD,MAAM,WAAW,GAAG,QAAQ,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IAClD,IAAI,WAAW,EAAE,CAAC;QAChB,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;QACpC,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IACZ,CAAC;IAED,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IACjD,IAAI,UAAU,EAAE,CAAC;QACf,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;QACnC,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IACZ,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAI,IAAa,EAAE,MAAoB;IAC1E,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,MAAM,CAAC,OAAO;QAAE,OAAO,MAAM,CAAC,IAAI,CAAC;IACvC,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAI,IAK5C;IACC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC;IACzD,IAAI,SAAS,GAAkB,IAAI,CAAC;IAEpC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;QACvD,MAAM,aAAa,GAAG,OAAO,KAAK,CAAC;YACjC,CAAC,CAAC,MAAM;YACR,CAAC,CAAC,GAAG,MAAM,4JAA4J,CAAC;QAE1K,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC;QACzC,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QAEnC,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;YACvB,MAAM,SAAS,GAAG,qBAAqB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;YAC3D,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;gBACvB,OAAO,SAAS,CAAC;YACnB,CAAC;YACD,SAAS,GAAG,+CAA+C,CAAC;QAC9D,CAAC;aAAM,CAAC;YACN,SAAS,GAAG,gDAAgD,CAAC;QAC/D,CAAC;IACH,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,GAAG,UAAU,cAAc,SAAS,EAAE,CAAC,CAAC;AAC/F,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { type OllamaProvider } from 'ai-sdk-ollama';
2
+ interface OllamaConfig {
3
+ baseURL: string;
4
+ }
5
+ /**
6
+ * Get a cached Ollama provider instance by configuration.
7
+ * Same config returns the same instance; different configs create new instances.
8
+ */
9
+ export declare function getOllamaProvider(config: OllamaConfig): OllamaProvider;
10
+ /**
11
+ * Clear the Ollama cache (useful for testing).
12
+ */
13
+ export declare function clearOllamaCache(): void;
14
+ /**
15
+ * Get the current number of cached providers (useful for testing).
16
+ */
17
+ export declare function getCacheSize(): number;
18
+ export {};
19
+ //# sourceMappingURL=ollamaCache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ollamaCache.d.ts","sourceRoot":"","sources":["../../src/llm/ollamaCache.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAElE,UAAU,YAAY;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,GAAG,cAAc,CAStE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC"}
@@ -0,0 +1,31 @@
1
+ // Factory function that returns a memoized createOllama instance
2
+ // Used for caching Ollama providers by configuration
3
+ import { createOllama } from 'ai-sdk-ollama';
4
+ // Map to store cached providers by config
5
+ // Using a stringified config as the key for simplicity
6
+ const cache = new Map();
7
+ /**
8
+ * Get a cached Ollama provider instance by configuration.
9
+ * Same config returns the same instance; different configs create new instances.
10
+ */
11
+ export function getOllamaProvider(config) {
12
+ const cacheKey = JSON.stringify(config);
13
+ if (!cache.has(cacheKey)) {
14
+ const provider = createOllama(config);
15
+ cache.set(cacheKey, provider);
16
+ }
17
+ return cache.get(cacheKey);
18
+ }
19
+ /**
20
+ * Clear the Ollama cache (useful for testing).
21
+ */
22
+ export function clearOllamaCache() {
23
+ cache.clear();
24
+ }
25
+ /**
26
+ * Get the current number of cached providers (useful for testing).
27
+ */
28
+ export function getCacheSize() {
29
+ return cache.size;
30
+ }
31
+ //# sourceMappingURL=ollamaCache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ollamaCache.js","sourceRoot":"","sources":["../../src/llm/ollamaCache.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,qDAAqD;AACrD,OAAO,EAAE,YAAY,EAAuB,MAAM,eAAe,CAAC;AAMlE,0CAA0C;AAC1C,uDAAuD;AACvD,MAAM,KAAK,GAAG,IAAI,GAAG,EAA0B,CAAC;AAEhD;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAoB;IACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAExC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;QACtC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAE,CAAC;AAC9B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB;IAC9B,KAAK,CAAC,KAAK,EAAE,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,KAAK,CAAC,IAAI,CAAC;AACpB,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type { AppConfig } from '../config.js';
2
+ /** Default request timeout in milliseconds (60 seconds) */
3
+ export declare const OLLAMA_DEFAULT_TIMEOUT = 60000;
4
+ export declare class OllamaApiError extends Error {
5
+ readonly status: number;
6
+ readonly body: string;
7
+ constructor(status: number, body: string);
8
+ }
9
+ export declare class OllamaParseError extends Error {
10
+ readonly rawResponse: string;
11
+ constructor(message: string, rawResponse: string);
12
+ }
13
+ /** Options for the ollamaClient request */
14
+ export interface OllamaClientOptions {
15
+ /** Request timeout in milliseconds. Default: 60000 (60 seconds) */
16
+ timeout?: number;
17
+ }
18
+ /**
19
+ * Low-level Ollama client used for structured JSON output via /api/generate.
20
+ * Tracks token usage for context window auto-offload.
21
+ *
22
+ * @param prompt - The prompt to send to Ollama
23
+ * @param format - The format specification (string or JSON Schema object)
24
+ * @param config - Application configuration
25
+ * @param options - Optional request options including timeout
26
+ * @throws OllamaApiError on timeout or HTTP errors
27
+ */
28
+ export declare function ollamaClient<T>(prompt: string, format: string | object, config: AppConfig, options?: OllamaClientOptions): Promise<T>;
29
+ //# sourceMappingURL=ollamaClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ollamaClient.d.ts","sourceRoot":"","sources":["../../src/llm/ollamaClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAG9C,2DAA2D;AAC3D,eAAO,MAAM,sBAAsB,QAAS,CAAC;AAE7C,qBAAa,cAAe,SAAQ,KAAK;aAErB,MAAM,EAAE,MAAM;aACd,IAAI,EAAE,MAAM;gBADZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM;CAK/B;AAED,qBAAa,gBAAiB,SAAQ,KAAK;aAGvB,WAAW,EAAE,MAAM;gBADnC,OAAO,EAAE,MAAM,EACC,WAAW,EAAE,MAAM;CAKtC;AAWD,2CAA2C;AAC3C,MAAM,WAAW,mBAAmB;IAClC,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAClC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,MAAM,EAAE,SAAS,EACjB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,CAAC,CAAC,CAmGZ"}
@@ -0,0 +1,117 @@
1
+ import { TOKEN_BUDGETS } from './promptSections.js';
2
+ /** Default request timeout in milliseconds (60 seconds) */
3
+ export const OLLAMA_DEFAULT_TIMEOUT = 60_000;
4
+ export class OllamaApiError extends Error {
5
+ status;
6
+ body;
7
+ constructor(status, body) {
8
+ super(`Ollama request failed with status ${status}: ${body}`);
9
+ this.status = status;
10
+ this.body = body;
11
+ this.name = 'OllamaApiError';
12
+ }
13
+ }
14
+ export class OllamaParseError extends Error {
15
+ rawResponse;
16
+ constructor(message, rawResponse) {
17
+ super(message);
18
+ this.rawResponse = rawResponse;
19
+ this.name = 'OllamaParseError';
20
+ }
21
+ }
22
+ // Token tracking — scoped per model for logging only.
23
+ // Accumulated tokens are used for log messages about high usage;
24
+ // they are NOT used to trigger context offload (that proved unreliable).
25
+ const accumulatedTokensByModel = new Map();
26
+ function addAccumulatedTokens(modelName, tokens) {
27
+ accumulatedTokensByModel.set(modelName, (accumulatedTokensByModel.get(modelName) ?? 0) + tokens);
28
+ }
29
+ /**
30
+ * Low-level Ollama client used for structured JSON output via /api/generate.
31
+ * Tracks token usage for context window auto-offload.
32
+ *
33
+ * @param prompt - The prompt to send to Ollama
34
+ * @param format - The format specification (string or JSON Schema object)
35
+ * @param config - Application configuration
36
+ * @param options - Optional request options including timeout
37
+ * @throws OllamaApiError on timeout or HTTP errors
38
+ */
39
+ export async function ollamaClient(prompt, format, config, options) {
40
+ const timeoutMs = options?.timeout ?? OLLAMA_DEFAULT_TIMEOUT;
41
+ const controller = new AbortController();
42
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
43
+ // Token budget enforcement — refuse oversized prompts for local models
44
+ const maxPromptChars = TOKEN_BUDGETS.ollamaClient.maxPromptChars;
45
+ if (prompt.length > maxPromptChars) {
46
+ console.error(`[ollamaClient] Prompt ${prompt.length} chars exceeds budget ${maxPromptChars}. Truncating.`);
47
+ prompt = prompt.slice(0, maxPromptChars) + '\n\n[PROMPT TRUNCATED — exceeded token budget]';
48
+ }
49
+ const requestBody = {
50
+ model: config.ollamaModel,
51
+ prompt,
52
+ stream: false,
53
+ format,
54
+ };
55
+ let response;
56
+ try {
57
+ response = await fetch(`${config.ollamaBaseUrl}/api/generate`, {
58
+ method: 'POST',
59
+ headers: { 'Content-Type': 'application/json' },
60
+ body: JSON.stringify(requestBody),
61
+ signal: controller.signal,
62
+ });
63
+ }
64
+ catch (error) {
65
+ clearTimeout(timeoutId);
66
+ if (error instanceof DOMException && error.name === 'AbortError') {
67
+ throw new OllamaApiError(0, `Ollama request timed out after ${timeoutMs}ms`);
68
+ }
69
+ throw error;
70
+ }
71
+ clearTimeout(timeoutId);
72
+ if (!response.ok) {
73
+ let errorBody;
74
+ try {
75
+ const jsonBody = await response.json();
76
+ errorBody = JSON.stringify(jsonBody);
77
+ }
78
+ catch {
79
+ errorBody = await response.text();
80
+ }
81
+ throw new OllamaApiError(response.status, errorBody);
82
+ }
83
+ const data = await response.json();
84
+ // Track token usage for logging
85
+ const promptTokens = data.prompt_eval_count || 0;
86
+ const evalTokens = data.eval_count || 0;
87
+ const totalTokens = promptTokens + evalTokens;
88
+ const modelName = data.model || config.ollamaModel;
89
+ addAccumulatedTokens(modelName, totalTokens);
90
+ const accumulated = accumulatedTokensByModel.get(modelName) ?? 0;
91
+ if (totalTokens > 10000) {
92
+ console.error(`[ollamaClient] High token usage: ${totalTokens} (accumulated: ${accumulated})`);
93
+ }
94
+ // Some models return JSON in 'thinking' field instead of 'response'
95
+ let rawResponse = data.response || data.thinking || '';
96
+ // Strip markdown code fences (```json ... ```) that some cloud models wrap JSON in
97
+ rawResponse = rawResponse.replace(/^```(?:json)?\s*/, '').replace(/\s*```$/, '').trim();
98
+ // Try direct JSON parse first
99
+ try {
100
+ return JSON.parse(rawResponse);
101
+ }
102
+ catch {
103
+ // Fallback: some cloud models ignore the format parameter and return
104
+ // plain text with JSON embedded. Try to extract the first JSON object.
105
+ const jsonMatch = rawResponse.match(/\{[\s\S]*\}/);
106
+ if (jsonMatch) {
107
+ try {
108
+ return JSON.parse(jsonMatch[0]);
109
+ }
110
+ catch {
111
+ // Fall through to error
112
+ }
113
+ }
114
+ throw new OllamaParseError(`Failed to parse Ollama response as JSON`, rawResponse);
115
+ }
116
+ }
117
+ //# sourceMappingURL=ollamaClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ollamaClient.js","sourceRoot":"","sources":["../../src/llm/ollamaClient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export declare const SUGGESTER_QUEUE: {
2
+ enqueue: <T>(label: string, task: () => Promise<T>) => Promise<T>;
3
+ };
4
+ export declare const INFERENCE_QUEUE: {
5
+ enqueue: <T>(label: string, task: () => Promise<T>) => Promise<T>;
6
+ };
7
+ //# sourceMappingURL=ollamaQueue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ollamaQueue.d.ts","sourceRoot":"","sources":["../../src/llm/ollamaQueue.ts"],"names":[],"mappings":"AA4BA,eAAO,MAAM,eAAe;cAxBH,CAAC,SAAS,MAAM,QAAQ,MAAM,OAAO,CAAC,CAAC,CAAC,KAAG,OAAO,CAAC,CAAC,CAAC;CAwBvB,CAAC;AAGxD,eAAO,MAAM,eAAe;cA3BH,CAAC,SAAS,MAAM,QAAQ,MAAM,OAAO,CAAC,CAAC,CAAC,KAAG,OAAO,CAAC,CAAC,CAAC;CA2BvB,CAAC"}
@@ -0,0 +1,28 @@
1
+ function createQueue(queueName) {
2
+ let queueDepth = 0;
3
+ let queueTail = Promise.resolve();
4
+ async function enqueue(label, task) {
5
+ queueDepth++;
6
+ const result = queueTail.then(async () => {
7
+ const startTime = Date.now();
8
+ try {
9
+ return await task();
10
+ }
11
+ finally {
12
+ const duration = Date.now() - startTime;
13
+ queueDepth--;
14
+ if (duration > 5000) {
15
+ console.error(`[ollamaQueue:${queueName}] ${label} slow (${duration}ms)`);
16
+ }
17
+ }
18
+ });
19
+ queueTail = result.catch(() => { });
20
+ return result;
21
+ }
22
+ return { enqueue };
23
+ }
24
+ // FIX: Dedicated queue for suggester — runs independently of inference queue
25
+ export const SUGGESTER_QUEUE = createQueue('suggester');
26
+ // FIX: Shared queue for summarizer and prompt builder — serialized together
27
+ export const INFERENCE_QUEUE = createQueue('inference');
28
+ //# sourceMappingURL=ollamaQueue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ollamaQueue.js","sourceRoot":"","sources":["../../src/llm/ollamaQueue.ts"],"names":[],"mappings":"AAAA,SAAS,WAAW,CAAC,SAAiB;IACpC,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,SAAS,GAAqB,OAAO,CAAC,OAAO,EAAE,CAAC;IAEpD,KAAK,UAAU,OAAO,CAAI,KAAa,EAAE,IAAsB;QAC7D,UAAU,EAAE,CAAC;QAEb,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE;YACvC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC7B,IAAI,CAAC;gBACH,OAAO,MAAM,IAAI,EAAE,CAAC;YACtB,CAAC;oBAAS,CAAC;gBACT,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;gBACxC,UAAU,EAAE,CAAC;gBACb,IAAI,QAAQ,GAAG,IAAI,EAAE,CAAC;oBACpB,OAAO,CAAC,KAAK,CAAC,gBAAgB,SAAS,KAAK,KAAK,UAAU,QAAQ,KAAK,CAAC,CAAC;gBAC5E,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACnC,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,CAAC;AACrB,CAAC;AAED,6EAA6E;AAC7E,MAAM,CAAC,MAAM,eAAe,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;AAExD,4EAA4E;AAC5E,MAAM,CAAC,MAAM,eAAe,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { AppConfig } from '../config.js';
2
+ import type { ContextSummary, TaskSuggestion, GeneratedPrompt } from '../../../shared/dist/index.js';
3
+ export declare class MissingApiKeyError extends Error {
4
+ readonly provider: string;
5
+ constructor(provider: string);
6
+ }
7
+ export declare function buildPrompt(task: TaskSuggestion, summary: ContextSummary, config: AppConfig): Promise<GeneratedPrompt>;
8
+ //# sourceMappingURL=promptBuilder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promptBuilder.d.ts","sourceRoot":"","sources":["../../src/llm/promptBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAA0B,MAAM,eAAe,CAAC;AAO7G,qBAAa,kBAAmB,SAAQ,KAAK;aACf,QAAQ,EAAE,MAAM;gBAAhB,QAAQ,EAAE,MAAM;CAI7C;AAiED,wBAAsB,WAAW,CAC/B,IAAI,EAAE,cAAc,EACpB,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,SAAS,GAChB,OAAO,CAAC,eAAe,CAAC,CAmB1B"}
@@ -0,0 +1,85 @@
1
+ import { stateManager } from '../stateManager.js';
2
+ import { generateText } from 'ai';
3
+ import { eventStore } from '../eventStore.js';
4
+ import { buildRepoPromptSections, formatEventCompact, PLACEHOLDER_PATTERNS } from './promptSections.js';
5
+ import { getModel } from './providerModels.js';
6
+ export class MissingApiKeyError extends Error {
7
+ provider;
8
+ constructor(provider) {
9
+ super(`${provider} API key not configured`);
10
+ this.provider = provider;
11
+ this.name = 'MissingApiKeyError';
12
+ }
13
+ }
14
+ const MIN_PROMPT_LENGTH = 50;
15
+ function buildPromptText(task, summary, notes, recentEvents) {
16
+ const notesSection = notes?.content
17
+ ? `\n## Dev Notes\n${notes.content}\n`
18
+ : '';
19
+ const repo = buildRepoPromptSections();
20
+ const recentEventsText = recentEvents.length > 0
21
+ ? recentEvents.map(e => formatEventCompact(e)).join('\n')
22
+ : 'No recent events.';
23
+ const toolsUsed = summary.toolsUsed;
24
+ const errorCount = summary.errorCount;
25
+ const testStatus = summary.testStatus;
26
+ return `Generate a precise, imperative prompt for a coding agent to execute.
27
+ ${repo.instructions}
28
+ ## Task
29
+ Title: ${task.title} | Priority: ${task.priority} | Rationale: ${task.rationale}
30
+ ${task.affectedFiles ? `Files: ${task.affectedFiles.join(', ')}` : ''}
31
+ ${task.suggestedToolCalls ? `Tools: ${task.suggestedToolCalls.join(', ')}` : ''}
32
+ ${task.conflictsWithNotes ? `⚠ Conflicts with notes. ${task.conflictExplanation || ''}` : ''}
33
+ ${notesSection}
34
+ ## State
35
+ Doing: ${summary.whatIsHappening}
36
+ Changed: ${summary.filesChanged.join(', ') || 'None'}
37
+ Goal: ${summary.currentGoal}
38
+ Blockers: ${summary.blockers.join(', ') || 'None'}
39
+ Events: ${summary.rawEventCount}
40
+ ${repo.root}
41
+ ${toolsUsed ? `Session tools: ${toolsUsed.join(', ')}` : ''}
42
+ ${errorCount !== undefined ? `Errors: ${errorCount}` : ''}
43
+ ${testStatus ? `Tests: ${testStatus}` : ''}
44
+
45
+ ## Recent (${recentEvents.length} events)
46
+ ${recentEventsText}
47
+
48
+ ## Rules
49
+ 1. State exact goal in imperative form
50
+ 2. List specific file paths to modify
51
+ 3. Include verifiable acceptance criteria
52
+ 4. Suggest approach/pattern
53
+ 5. Reference relevant events (errors, diffs, outputs)
54
+ 6. If tests failing, include exact test names/error messages
55
+ 7. If blockers, explain resolution
56
+
57
+ Output only the prompt text.`;
58
+ }
59
+ function validatePrompt(prompt) {
60
+ if (!prompt || prompt.trim().length < MIN_PROMPT_LENGTH) {
61
+ throw new Error(`Prompt too short (${prompt?.length || 0} chars). Minimum ${MIN_PROMPT_LENGTH} characters required. Got: "${prompt?.substring(0, 50) || '(empty)'}"`);
62
+ }
63
+ const matchedPattern = PLACEHOLDER_PATTERNS.find(pattern => pattern.test(prompt.trim()));
64
+ if (matchedPattern) {
65
+ process.stderr.write(`[VALIDATION REJECT] Pattern: ${matchedPattern.source} | Content: "${prompt.substring(0, 100)}"\n`);
66
+ throw new Error(`Placeholder prompt detected: "${prompt.substring(0, 100)}". Please regenerate.`);
67
+ }
68
+ }
69
+ export async function buildPrompt(task, summary, config) {
70
+ const notes = stateManager.getNotes();
71
+ const provider = config.llmProvider || 'ollama';
72
+ const model = getModel(provider, config);
73
+ // Fetch recent events for grounding the prompt in current reality
74
+ const recentEvents = eventStore.getLast(10);
75
+ const promptText = buildPromptText(task, summary, notes, recentEvents);
76
+ const { text } = await generateText({ model, prompt: promptText });
77
+ validatePrompt(text);
78
+ return {
79
+ taskId: task.id,
80
+ provider: provider,
81
+ prompt: text,
82
+ generatedAt: Date.now(),
83
+ };
84
+ }
85
+ //# sourceMappingURL=promptBuilder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promptBuilder.js","sourceRoot":"","sources":["../../src/llm/promptBuilder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Shared prompt section builders — eliminates 4x duplication of
3
+ * repo instructions/root sections across promptBuilder, suggester,
4
+ * summarizer, and blueprint.
5
+ */
6
+ export interface RepoPromptSections {
7
+ instructions: string;
8
+ root: string;
9
+ }
10
+ export declare function buildRepoPromptSections(): RepoPromptSections;
11
+ /**
12
+ * Compact event formatter — reduces token waste from verbose field joining.
13
+ * ~40% fewer tokens vs original formatEvent() for typical events.
14
+ */
15
+ export declare function formatEventCompact(event: {
16
+ type: string;
17
+ tool?: string;
18
+ text?: string;
19
+ thinking?: string;
20
+ output?: string;
21
+ diff?: string;
22
+ status?: string;
23
+ args?: Record<string, unknown>;
24
+ sessionId?: string;
25
+ turnNumber?: number;
26
+ durationMs?: number;
27
+ }): string;
28
+ /**
29
+ * Estimate token count from character length.
30
+ * Conservative: uses chars/3.5 for code-heavy content (higher than prose /4).
31
+ */
32
+ export declare function estimateTokens(text: string): number;
33
+ /**
34
+ * Token budget configuration per feature path.
35
+ */
36
+ export declare const TOKEN_BUDGETS: {
37
+ readonly summarizer: {
38
+ readonly maxEvents: 30;
39
+ readonly maxEventChars: 400;
40
+ readonly maxTotalChars: 12000;
41
+ };
42
+ readonly suggester: {
43
+ readonly maxInstructionsChars: 600;
44
+ };
45
+ readonly promptBuilder: {
46
+ readonly maxEvents: 10;
47
+ readonly maxEventChars: 300;
48
+ };
49
+ readonly blueprint: {
50
+ readonly maxGroundingChars: 4000;
51
+ readonly maxAgentsMdChars: 6000;
52
+ };
53
+ readonly ollamaClient: {
54
+ readonly maxPromptChars: 50000;
55
+ };
56
+ };
57
+ export declare const PLACEHOLDER_PATTERNS: RegExp[];
58
+ export declare function hasMeaningfulSummaryContent(summary: {
59
+ whatIsHappening?: string;
60
+ currentGoal?: string;
61
+ blockers?: string[];
62
+ filesChanged?: string[];
63
+ } | null | undefined): boolean;
64
+ //# sourceMappingURL=promptSections.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promptSections.d.ts","sourceRoot":"","sources":["../../src/llm/promptSections.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,uBAAuB,IAAI,kBAAkB,CAU5D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,MAAM,CAiCT;AAqBD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;GAEG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;CAoBhB,CAAC;AAEX,eAAO,MAAM,oBAAoB,UAOhC,CAAC;AAEF,wBAAgB,2BAA2B,CAAC,OAAO,EAAE;IACnD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAQ7B"}
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Shared prompt section builders — eliminates 4x duplication of
3
+ * repo instructions/root sections across promptBuilder, suggester,
4
+ * summarizer, and blueprint.
5
+ */
6
+ import { stateManager } from '../stateManager.js';
7
+ export function buildRepoPromptSections() {
8
+ const repoCtx = stateManager.getRepoContext();
9
+ return {
10
+ instructions: repoCtx?.repoInstructions
11
+ ? `\n## Repo Instructions (${repoCtx.instructionsFile})\n${repoCtx.repoInstructions}\n`
12
+ : '',
13
+ root: repoCtx?.repoRoot
14
+ ? `\n- Repo root: ${repoCtx.repoRoot}`
15
+ : '',
16
+ };
17
+ }
18
+ /**
19
+ * Compact event formatter — reduces token waste from verbose field joining.
20
+ * ~40% fewer tokens vs original formatEvent() for typical events.
21
+ */
22
+ export function formatEventCompact(event) {
23
+ const parts = [`[${event.type}]`];
24
+ if (event.tool)
25
+ parts.push(`t=${event.tool}`);
26
+ if (event.status)
27
+ parts.push(`s=${event.status}`);
28
+ if (event.durationMs !== undefined)
29
+ parts.push(`${event.durationMs}ms`);
30
+ if (event.text)
31
+ parts.push(trunc(event.text, 400));
32
+ if (event.thinking)
33
+ parts.push(`(think: ${trunc(event.thinking, 300)})`);
34
+ if (event.args) {
35
+ const paths = extractFilePaths(event.args);
36
+ const argsStr = JSON.stringify(event.args);
37
+ if (argsStr.length > 300) {
38
+ parts.push(`args=${trunc(argsStr, 300)}`);
39
+ if (paths.length)
40
+ parts.push(`files=[${paths.join(',')}]`);
41
+ }
42
+ else {
43
+ parts.push(`args=${argsStr}`);
44
+ }
45
+ }
46
+ if (event.output) {
47
+ const outStr = typeof event.output === 'string' ? event.output : JSON.stringify(event.output);
48
+ parts.push(`out=${trunc(outStr, 500)}`);
49
+ }
50
+ if (event.diff) {
51
+ const hdr = event.diff.split('\n').slice(0, 3).join('\n');
52
+ const body = event.diff.split('\n').slice(3).join('\n');
53
+ parts.push(`diff=${hdr}\n${trunc(body, 300)}`);
54
+ }
55
+ return parts.join(' ');
56
+ }
57
+ function trunc(s, max) {
58
+ return s.length <= max ? s : s.substring(0, max) + '…';
59
+ }
60
+ function extractFilePaths(args) {
61
+ const paths = [];
62
+ const search = (obj) => {
63
+ if (typeof obj === 'string' && /^\/?[\w\-./]+\.[a-zA-Z0-9]+$/.test(obj) && obj.includes('/')) {
64
+ paths.push(obj);
65
+ }
66
+ else if (Array.isArray(obj)) {
67
+ obj.forEach(search);
68
+ }
69
+ else if (obj && typeof obj === 'object') {
70
+ Object.values(obj).forEach(search);
71
+ }
72
+ };
73
+ search(args);
74
+ return [...new Set(paths)];
75
+ }
76
+ /**
77
+ * Estimate token count from character length.
78
+ * Conservative: uses chars/3.5 for code-heavy content (higher than prose /4).
79
+ */
80
+ export function estimateTokens(text) {
81
+ return Math.ceil(text.length / 3.5);
82
+ }
83
+ /**
84
+ * Token budget configuration per feature path.
85
+ */
86
+ export const TOKEN_BUDGETS = {
87
+ summarizer: {
88
+ maxEvents: 30, // was 50 — reduce by 40%
89
+ maxEventChars: 400, // was 800 — halve per-event size
90
+ maxTotalChars: 12000, // hard cap on total event section
91
+ },
92
+ suggester: {
93
+ maxInstructionsChars: 600, // cap instruction text
94
+ },
95
+ promptBuilder: {
96
+ maxEvents: 10, // already 10 — keep but compact format
97
+ maxEventChars: 300,
98
+ },
99
+ blueprint: {
100
+ maxGroundingChars: 4000, // hard cap on grounding context
101
+ maxAgentsMdChars: 6000, // cap AGENTS.md when injected into phases
102
+ },
103
+ ollamaClient: {
104
+ maxPromptChars: 50000, // safety cap for local models
105
+ },
106
+ };
107
+ export const PLACEHOLDER_PATTERNS = [
108
+ /^\.+$/,
109
+ /^Implement Feature/i,
110
+ /^Task title$/i,
111
+ /^Feature [A-Z]$/i,
112
+ /^[A-Z_]+$/,
113
+ /^task[a-z0-9]{4,}$/i,
114
+ ];
115
+ export function hasMeaningfulSummaryContent(summary) {
116
+ if (!summary)
117
+ return false;
118
+ const what = (summary.whatIsHappening ?? '').trim();
119
+ const goal = (summary.currentGoal ?? '').trim();
120
+ if (what.length === 0 && goal.length === 0)
121
+ return false;
122
+ if (what && PLACEHOLDER_PATTERNS.some(p => p.test(what)))
123
+ return false;
124
+ if (goal && PLACEHOLDER_PATTERNS.some(p => p.test(goal)))
125
+ return false;
126
+ return true;
127
+ }
128
+ //# sourceMappingURL=promptSections.js.map