@agile-vibe-coding/avc 0.2.3 → 0.3.1

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 (261) hide show
  1. package/cli/agents/agent-selector.md +23 -0
  2. package/cli/agents/code-implementer.md +117 -0
  3. package/cli/agents/code-validator.md +80 -0
  4. package/cli/agents/context-reviewer-epic.md +101 -0
  5. package/cli/agents/context-reviewer-story.md +92 -0
  6. package/cli/agents/context-writer-epic.md +145 -0
  7. package/cli/agents/context-writer-story.md +111 -0
  8. package/cli/agents/doc-writer-epic.md +42 -0
  9. package/cli/agents/doc-writer-story.md +43 -0
  10. package/cli/agents/duplicate-detector.md +110 -0
  11. package/cli/agents/epic-story-decomposer.md +318 -39
  12. package/cli/agents/mission-scope-generator.md +68 -4
  13. package/cli/agents/mission-scope-validator.md +40 -6
  14. package/cli/agents/project-context-extractor.md +21 -6
  15. package/cli/agents/scaffolding-generator.md +99 -0
  16. package/cli/agents/seed-validator.md +71 -0
  17. package/cli/agents/story-scope-reviewer.md +147 -0
  18. package/cli/agents/story-splitter.md +83 -0
  19. package/cli/agents/validator-documentation.json +31 -0
  20. package/cli/agents/validator-documentation.md +3 -1
  21. package/cli/api-reference-tool.js +368 -0
  22. package/cli/checks/catalog.json +76 -0
  23. package/cli/checks/code/quality.json +26 -0
  24. package/cli/checks/code/testing.json +14 -0
  25. package/cli/checks/code/traceability.json +26 -0
  26. package/cli/checks/cross-refs/epic.json +171 -0
  27. package/cli/checks/cross-refs/story.json +149 -0
  28. package/cli/checks/epic/api.json +114 -0
  29. package/cli/checks/epic/backend.json +126 -0
  30. package/cli/checks/epic/cloud.json +126 -0
  31. package/cli/checks/epic/data.json +102 -0
  32. package/cli/checks/epic/database.json +114 -0
  33. package/cli/checks/epic/developer.json +182 -0
  34. package/cli/checks/epic/devops.json +174 -0
  35. package/cli/checks/epic/frontend.json +162 -0
  36. package/cli/checks/epic/mobile.json +102 -0
  37. package/cli/checks/epic/qa.json +90 -0
  38. package/cli/checks/epic/security.json +184 -0
  39. package/cli/checks/epic/solution-architect.json +192 -0
  40. package/cli/checks/epic/test-architect.json +90 -0
  41. package/cli/checks/epic/ui.json +102 -0
  42. package/cli/checks/epic/ux.json +90 -0
  43. package/cli/checks/fixes/epic-fix-template.md +10 -0
  44. package/cli/checks/fixes/story-fix-template.md +10 -0
  45. package/cli/checks/story/api.json +186 -0
  46. package/cli/checks/story/backend.json +102 -0
  47. package/cli/checks/story/cloud.json +102 -0
  48. package/cli/checks/story/data.json +210 -0
  49. package/cli/checks/story/database.json +102 -0
  50. package/cli/checks/story/developer.json +168 -0
  51. package/cli/checks/story/devops.json +102 -0
  52. package/cli/checks/story/frontend.json +174 -0
  53. package/cli/checks/story/mobile.json +102 -0
  54. package/cli/checks/story/qa.json +210 -0
  55. package/cli/checks/story/security.json +198 -0
  56. package/cli/checks/story/solution-architect.json +230 -0
  57. package/cli/checks/story/test-architect.json +210 -0
  58. package/cli/checks/story/ui.json +102 -0
  59. package/cli/checks/story/ux.json +102 -0
  60. package/cli/coding-order.js +401 -0
  61. package/cli/dependency-checker.js +72 -0
  62. package/cli/epic-story-validator.js +284 -799
  63. package/cli/index.js +0 -0
  64. package/cli/init-model-config.js +17 -10
  65. package/cli/init.js +514 -92
  66. package/cli/kanban-server-manager.js +1 -2
  67. package/cli/llm-claude.js +98 -31
  68. package/cli/llm-gemini.js +29 -5
  69. package/cli/llm-local.js +493 -0
  70. package/cli/llm-openai.js +262 -41
  71. package/cli/llm-provider.js +147 -8
  72. package/cli/llm-token-limits.js +113 -4
  73. package/cli/llm-verifier.js +209 -1
  74. package/cli/llm-xiaomi.js +143 -0
  75. package/cli/message-constants.js +3 -12
  76. package/cli/messaging-api.js +6 -12
  77. package/cli/micro-check-fixer.js +335 -0
  78. package/cli/micro-check-runner.js +449 -0
  79. package/cli/micro-check-scorer.js +148 -0
  80. package/cli/micro-check-validator.js +538 -0
  81. package/cli/model-pricing.js +23 -0
  82. package/cli/model-selector.js +3 -2
  83. package/cli/prompt-logger.js +57 -0
  84. package/cli/repl-ink.js +106 -346
  85. package/cli/repl-old.js +1 -2
  86. package/cli/seed-processor.js +194 -24
  87. package/cli/sprint-planning-processor.js +2638 -289
  88. package/cli/template-processor.js +50 -3
  89. package/cli/token-tracker.js +50 -23
  90. package/cli/tools/generate-story-validators.js +1 -1
  91. package/cli/validation-router.js +70 -8
  92. package/cli/worktree-runner.js +654 -0
  93. package/kanban/client/dist/assets/index-D_KC5EQT.css +1 -0
  94. package/kanban/client/dist/assets/index-DjY5zqW7.js +351 -0
  95. package/kanban/client/dist/index.html +2 -2
  96. package/kanban/client/src/App.jsx +43 -14
  97. package/kanban/client/src/components/ceremony/AskArchPopup.jsx +7 -3
  98. package/kanban/client/src/components/ceremony/AskModelPopup.jsx +23 -10
  99. package/kanban/client/src/components/ceremony/CeremonyWorkflowModal.jsx +320 -133
  100. package/kanban/client/src/components/ceremony/ProviderSwitcherButton.jsx +290 -0
  101. package/kanban/client/src/components/ceremony/SponsorCallModal.jsx +80 -13
  102. package/kanban/client/src/components/ceremony/SprintPlanningModal.jsx +156 -22
  103. package/kanban/client/src/components/ceremony/steps/ArchitectureStep.jsx +11 -11
  104. package/kanban/client/src/components/ceremony/steps/CompleteStep.jsx +3 -21
  105. package/kanban/client/src/components/ceremony/steps/ReviewAnswersStep.jsx +214 -10
  106. package/kanban/client/src/components/ceremony/steps/RunningStep.jsx +23 -2
  107. package/kanban/client/src/components/kanban/CardDetailModal.jsx +97 -10
  108. package/kanban/client/src/components/kanban/GroupingSelector.jsx +7 -1
  109. package/kanban/client/src/components/kanban/KanbanCard.jsx +23 -14
  110. package/kanban/client/src/components/kanban/RefineWorkItemPopup.jsx +9 -14
  111. package/kanban/client/src/components/kanban/RunButton.jsx +162 -0
  112. package/kanban/client/src/components/kanban/SeedButton.jsx +176 -0
  113. package/kanban/client/src/components/settings/AgentsTab.jsx +103 -75
  114. package/kanban/client/src/components/settings/ApiKeysTab.jsx +31 -2
  115. package/kanban/client/src/components/settings/CeremonyModelsTab.jsx +9 -2
  116. package/kanban/client/src/components/settings/CheckEditorPopup.jsx +507 -0
  117. package/kanban/client/src/components/settings/CostThresholdsTab.jsx +3 -2
  118. package/kanban/client/src/components/settings/ModelPricingTab.jsx +72 -7
  119. package/kanban/client/src/components/settings/OpenAIAuthSection.jsx +412 -0
  120. package/kanban/client/src/components/settings/SettingsModal.jsx +4 -4
  121. package/kanban/client/src/components/stats/CostModal.jsx +34 -3
  122. package/kanban/client/src/hooks/useGrouping.js +59 -0
  123. package/kanban/client/src/lib/api.js +118 -4
  124. package/kanban/client/src/lib/status-grouping.js +10 -0
  125. package/kanban/client/src/store/kanbanStore.js +8 -0
  126. package/kanban/server/index.js +23 -2
  127. package/kanban/server/routes/ceremony.js +153 -4
  128. package/kanban/server/routes/costs.js +9 -3
  129. package/kanban/server/routes/openai-oauth.js +366 -0
  130. package/kanban/server/routes/settings.js +447 -14
  131. package/kanban/server/routes/websocket.js +7 -2
  132. package/kanban/server/routes/work-items.js +141 -1
  133. package/kanban/server/services/CeremonyService.js +275 -24
  134. package/kanban/server/services/TaskRunnerService.js +261 -0
  135. package/kanban/server/workers/run-task-worker.js +121 -0
  136. package/kanban/server/workers/seed-worker.js +94 -0
  137. package/kanban/server/workers/sponsor-call-worker.js +14 -6
  138. package/kanban/server/workers/sprint-planning-worker.js +94 -12
  139. package/package.json +2 -3
  140. package/cli/agents/solver-epic-api.json +0 -15
  141. package/cli/agents/solver-epic-api.md +0 -39
  142. package/cli/agents/solver-epic-backend.json +0 -15
  143. package/cli/agents/solver-epic-backend.md +0 -39
  144. package/cli/agents/solver-epic-cloud.json +0 -15
  145. package/cli/agents/solver-epic-cloud.md +0 -39
  146. package/cli/agents/solver-epic-data.json +0 -15
  147. package/cli/agents/solver-epic-data.md +0 -39
  148. package/cli/agents/solver-epic-database.json +0 -15
  149. package/cli/agents/solver-epic-database.md +0 -39
  150. package/cli/agents/solver-epic-developer.json +0 -15
  151. package/cli/agents/solver-epic-developer.md +0 -39
  152. package/cli/agents/solver-epic-devops.json +0 -15
  153. package/cli/agents/solver-epic-devops.md +0 -39
  154. package/cli/agents/solver-epic-frontend.json +0 -15
  155. package/cli/agents/solver-epic-frontend.md +0 -39
  156. package/cli/agents/solver-epic-mobile.json +0 -15
  157. package/cli/agents/solver-epic-mobile.md +0 -39
  158. package/cli/agents/solver-epic-qa.json +0 -15
  159. package/cli/agents/solver-epic-qa.md +0 -39
  160. package/cli/agents/solver-epic-security.json +0 -15
  161. package/cli/agents/solver-epic-security.md +0 -39
  162. package/cli/agents/solver-epic-solution-architect.json +0 -15
  163. package/cli/agents/solver-epic-solution-architect.md +0 -39
  164. package/cli/agents/solver-epic-test-architect.json +0 -15
  165. package/cli/agents/solver-epic-test-architect.md +0 -39
  166. package/cli/agents/solver-epic-ui.json +0 -15
  167. package/cli/agents/solver-epic-ui.md +0 -39
  168. package/cli/agents/solver-epic-ux.json +0 -15
  169. package/cli/agents/solver-epic-ux.md +0 -39
  170. package/cli/agents/solver-story-api.json +0 -15
  171. package/cli/agents/solver-story-api.md +0 -39
  172. package/cli/agents/solver-story-backend.json +0 -15
  173. package/cli/agents/solver-story-backend.md +0 -39
  174. package/cli/agents/solver-story-cloud.json +0 -15
  175. package/cli/agents/solver-story-cloud.md +0 -39
  176. package/cli/agents/solver-story-data.json +0 -15
  177. package/cli/agents/solver-story-data.md +0 -39
  178. package/cli/agents/solver-story-database.json +0 -15
  179. package/cli/agents/solver-story-database.md +0 -39
  180. package/cli/agents/solver-story-developer.json +0 -15
  181. package/cli/agents/solver-story-developer.md +0 -39
  182. package/cli/agents/solver-story-devops.json +0 -15
  183. package/cli/agents/solver-story-devops.md +0 -39
  184. package/cli/agents/solver-story-frontend.json +0 -15
  185. package/cli/agents/solver-story-frontend.md +0 -39
  186. package/cli/agents/solver-story-mobile.json +0 -15
  187. package/cli/agents/solver-story-mobile.md +0 -39
  188. package/cli/agents/solver-story-qa.json +0 -15
  189. package/cli/agents/solver-story-qa.md +0 -39
  190. package/cli/agents/solver-story-security.json +0 -15
  191. package/cli/agents/solver-story-security.md +0 -39
  192. package/cli/agents/solver-story-solution-architect.json +0 -15
  193. package/cli/agents/solver-story-solution-architect.md +0 -39
  194. package/cli/agents/solver-story-test-architect.json +0 -15
  195. package/cli/agents/solver-story-test-architect.md +0 -39
  196. package/cli/agents/solver-story-ui.json +0 -15
  197. package/cli/agents/solver-story-ui.md +0 -39
  198. package/cli/agents/solver-story-ux.json +0 -15
  199. package/cli/agents/solver-story-ux.md +0 -39
  200. package/cli/agents/validator-epic-api.json +0 -93
  201. package/cli/agents/validator-epic-api.md +0 -137
  202. package/cli/agents/validator-epic-backend.json +0 -93
  203. package/cli/agents/validator-epic-backend.md +0 -130
  204. package/cli/agents/validator-epic-cloud.json +0 -93
  205. package/cli/agents/validator-epic-cloud.md +0 -137
  206. package/cli/agents/validator-epic-data.json +0 -93
  207. package/cli/agents/validator-epic-data.md +0 -130
  208. package/cli/agents/validator-epic-database.json +0 -93
  209. package/cli/agents/validator-epic-database.md +0 -137
  210. package/cli/agents/validator-epic-developer.json +0 -74
  211. package/cli/agents/validator-epic-developer.md +0 -153
  212. package/cli/agents/validator-epic-devops.json +0 -74
  213. package/cli/agents/validator-epic-devops.md +0 -153
  214. package/cli/agents/validator-epic-frontend.json +0 -74
  215. package/cli/agents/validator-epic-frontend.md +0 -153
  216. package/cli/agents/validator-epic-mobile.json +0 -93
  217. package/cli/agents/validator-epic-mobile.md +0 -130
  218. package/cli/agents/validator-epic-qa.json +0 -93
  219. package/cli/agents/validator-epic-qa.md +0 -130
  220. package/cli/agents/validator-epic-security.json +0 -74
  221. package/cli/agents/validator-epic-security.md +0 -154
  222. package/cli/agents/validator-epic-solution-architect.json +0 -74
  223. package/cli/agents/validator-epic-solution-architect.md +0 -156
  224. package/cli/agents/validator-epic-test-architect.json +0 -93
  225. package/cli/agents/validator-epic-test-architect.md +0 -130
  226. package/cli/agents/validator-epic-ui.json +0 -93
  227. package/cli/agents/validator-epic-ui.md +0 -130
  228. package/cli/agents/validator-epic-ux.json +0 -93
  229. package/cli/agents/validator-epic-ux.md +0 -130
  230. package/cli/agents/validator-story-api.json +0 -104
  231. package/cli/agents/validator-story-api.md +0 -152
  232. package/cli/agents/validator-story-backend.json +0 -104
  233. package/cli/agents/validator-story-backend.md +0 -152
  234. package/cli/agents/validator-story-cloud.json +0 -104
  235. package/cli/agents/validator-story-cloud.md +0 -152
  236. package/cli/agents/validator-story-data.json +0 -104
  237. package/cli/agents/validator-story-data.md +0 -152
  238. package/cli/agents/validator-story-database.json +0 -104
  239. package/cli/agents/validator-story-database.md +0 -152
  240. package/cli/agents/validator-story-developer.json +0 -104
  241. package/cli/agents/validator-story-developer.md +0 -152
  242. package/cli/agents/validator-story-devops.json +0 -104
  243. package/cli/agents/validator-story-devops.md +0 -152
  244. package/cli/agents/validator-story-frontend.json +0 -104
  245. package/cli/agents/validator-story-frontend.md +0 -152
  246. package/cli/agents/validator-story-mobile.json +0 -104
  247. package/cli/agents/validator-story-mobile.md +0 -152
  248. package/cli/agents/validator-story-qa.json +0 -104
  249. package/cli/agents/validator-story-qa.md +0 -152
  250. package/cli/agents/validator-story-security.json +0 -104
  251. package/cli/agents/validator-story-security.md +0 -152
  252. package/cli/agents/validator-story-solution-architect.json +0 -104
  253. package/cli/agents/validator-story-solution-architect.md +0 -152
  254. package/cli/agents/validator-story-test-architect.json +0 -104
  255. package/cli/agents/validator-story-test-architect.md +0 -152
  256. package/cli/agents/validator-story-ui.json +0 -104
  257. package/cli/agents/validator-story-ui.md +0 -152
  258. package/cli/agents/validator-story-ux.json +0 -104
  259. package/cli/agents/validator-story-ux.md +0 -152
  260. package/kanban/client/dist/assets/index-CiD8PS2e.js +0 -306
  261. package/kanban/client/dist/assets/index-nLh0m82Q.css +0 -1
@@ -1,4 +1,4 @@
1
- import { exec } from 'child_process';
1
+ import { exec, execSync } from 'child_process';
2
2
  import { promisify } from 'util';
3
3
  import path from 'path';
4
4
  import fs from 'fs';
@@ -150,7 +150,6 @@ export class KanbanServerManager {
150
150
  if (pid && !isNaN(pid)) {
151
151
  // Try to get process name
152
152
  try {
153
- const { execSync } = require('child_process');
154
153
  const psOutput = execSync(`ps -p ${pid} -o comm=`, { encoding: 'utf8' });
155
154
  return { pid, command: psOutput.trim() };
156
155
  } catch {
package/cli/llm-claude.js CHANGED
@@ -30,43 +30,86 @@ export class ClaudeProvider extends LLMProvider {
30
30
  return response.content[0].text;
31
31
  }
32
32
 
33
- async generateJSON(prompt, agentInstructions = null) {
33
+ async generateJSON(prompt, agentInstructions = null, cachedContext = null) {
34
34
  if (!this._client) {
35
35
  this._client = this._createClient();
36
36
  }
37
37
 
38
- const fullPrompt = agentInstructions ? `${agentInstructions}\n\n${prompt}` : prompt;
39
-
40
38
  // Use model-specific maximum tokens
41
39
  const maxTokens = getMaxTokensForModel(this.model);
42
40
 
41
+ const JSON_SYSTEM = 'You are a helpful assistant that always returns valid JSON. Your response must be a valid JSON object or array, nothing else.';
42
+
43
+ let systemParam;
44
+ let userContent;
45
+
46
+ if (cachedContext) {
47
+ // Structured content blocks: cache_control on agentInstructions (system) and
48
+ // cachedContext (first user block) — both stay stable across multiple calls
49
+ // in the same ceremony, hitting the 5-min cache on subsequent validators.
50
+ systemParam = agentInstructions
51
+ ? [
52
+ { type: 'text', text: JSON_SYSTEM },
53
+ { type: 'text', text: agentInstructions, cache_control: { type: 'ephemeral' } },
54
+ ]
55
+ : [{ type: 'text', text: JSON_SYSTEM }];
56
+
57
+ userContent = [
58
+ { type: 'text', text: cachedContext, cache_control: { type: 'ephemeral' } },
59
+ { type: 'text', text: prompt },
60
+ ];
61
+ } else {
62
+ systemParam = JSON_SYSTEM;
63
+ userContent = agentInstructions ? `${agentInstructions}\n\n${prompt}` : prompt;
64
+ }
65
+
66
+ const requestParams = {
67
+ model: this.model,
68
+ max_tokens: maxTokens,
69
+ system: systemParam,
70
+ messages: [{ role: 'user', content: userContent }],
71
+ };
72
+
73
+ const fullPrompt = agentInstructions ? `${agentInstructions}\n\n${prompt}` : prompt;
74
+
75
+ const _t0Json = Date.now();
43
76
  const response = await this._withRetry(
44
- () => this._client.messages.create({
45
- model: this.model,
46
- max_tokens: maxTokens,
47
- messages: [{
48
- role: 'user',
49
- content: fullPrompt
50
- }],
51
- system: 'You are a helpful assistant that always returns valid JSON. Your response must be a valid JSON object or array, nothing else.'
52
- }),
77
+ () => this._client.messages.create(requestParams),
53
78
  'JSON generation (Claude)'
54
79
  );
55
80
 
56
- this._trackTokens(response.usage);
57
81
  const content = response.content[0].text;
58
-
59
- // Extract JSON from response (handle markdown code blocks)
60
- // Strip markdown code fences if present (more robust)
82
+ this._trackTokens(response.usage, {
83
+ prompt: fullPrompt,
84
+ agentInstructions: agentInstructions ?? null,
85
+ response: content,
86
+ elapsed: Date.now() - _t0Json,
87
+ });
88
+
89
+ // Extract JSON from response (handle markdown code blocks and preamble text)
61
90
  let jsonStr = content.trim();
91
+
92
+ // Strip markdown code fences if the response starts with one
62
93
  if (jsonStr.startsWith('```')) {
63
- // Remove opening fence (```json or ```)
64
94
  jsonStr = jsonStr.replace(/^```(?:json)?\s*\n?/, '');
65
- // Remove closing fence
66
95
  jsonStr = jsonStr.replace(/\n?\s*```\s*$/, '');
67
96
  jsonStr = jsonStr.trim();
68
97
  }
69
98
 
99
+ // If model added reasoning preamble before JSON, find the first { or [ and extract from there.
100
+ // This handles Claude responses like "I'll analyze...\n\n```json\n{...}\n```" or "Here is the JSON:\n{...}"
101
+ if (!jsonStr.startsWith('{') && !jsonStr.startsWith('[')) {
102
+ const firstBrace = jsonStr.indexOf('{');
103
+ const firstBracket = jsonStr.indexOf('[');
104
+ const jsonStart = firstBrace === -1 ? firstBracket
105
+ : firstBracket === -1 ? firstBrace
106
+ : Math.min(firstBrace, firstBracket);
107
+ if (jsonStart > 0) {
108
+ // Also strip trailing markdown fences that may follow the JSON block
109
+ jsonStr = jsonStr.slice(jsonStart).replace(/\n?\s*```\s*$/, '').trim();
110
+ }
111
+ }
112
+
70
113
  try {
71
114
  return JSON.parse(jsonStr);
72
115
  } catch (firstError) {
@@ -81,29 +124,53 @@ export class ClaudeProvider extends LLMProvider {
81
124
  }
82
125
  }
83
126
 
84
- async generateText(prompt, agentInstructions = null) {
127
+ async generateText(prompt, agentInstructions = null, cachedContext = null) {
85
128
  if (!this._client) {
86
129
  this._client = this._createClient();
87
130
  }
88
131
 
89
- const fullPrompt = agentInstructions ? `${agentInstructions}\n\n${prompt}` : prompt;
90
-
91
132
  // Use model-specific maximum tokens
92
133
  const maxTokens = getMaxTokensForModel(this.model);
93
134
 
135
+ let systemParam;
136
+ let userContent;
137
+
138
+ if (cachedContext) {
139
+ systemParam = agentInstructions
140
+ ? [
141
+ { type: 'text', text: agentInstructions, cache_control: { type: 'ephemeral' } },
142
+ ]
143
+ : undefined;
144
+ userContent = [
145
+ { type: 'text', text: cachedContext, cache_control: { type: 'ephemeral' } },
146
+ { type: 'text', text: prompt },
147
+ ];
148
+ } else {
149
+ userContent = agentInstructions ? `${agentInstructions}\n\n${prompt}` : prompt;
150
+ }
151
+
152
+ const requestParams = {
153
+ model: this.model,
154
+ max_tokens: maxTokens,
155
+ messages: [{ role: 'user', content: userContent }],
156
+ };
157
+ if (systemParam) requestParams.system = systemParam;
158
+
159
+ const fullPrompt = agentInstructions ? `${agentInstructions}\n\n${prompt}` : prompt;
160
+
161
+ const _t0Text = Date.now();
94
162
  const response = await this._withRetry(
95
- () => this._client.messages.create({
96
- model: this.model,
97
- max_tokens: maxTokens,
98
- messages: [{
99
- role: 'user',
100
- content: fullPrompt
101
- }]
102
- }),
163
+ () => this._client.messages.create(requestParams),
103
164
  'Text generation (Claude)'
104
165
  );
105
166
 
106
- this._trackTokens(response.usage);
107
- return response.content[0].text;
167
+ const text = response.content[0].text;
168
+ this._trackTokens(response.usage, {
169
+ prompt: fullPrompt,
170
+ agentInstructions: agentInstructions ?? null,
171
+ response: text,
172
+ elapsed: Date.now() - _t0Text,
173
+ });
174
+ return text;
108
175
  }
109
176
  }
package/cli/llm-gemini.js CHANGED
@@ -31,7 +31,7 @@ export class GeminiProvider extends LLMProvider {
31
31
  return response.text;
32
32
  }
33
33
 
34
- async generateJSON(prompt, agentInstructions = null) {
34
+ async generateJSON(prompt, agentInstructions = null, cachedContext = null) {
35
35
  if (!this._client) {
36
36
  this._client = this._createClient();
37
37
  }
@@ -50,6 +50,14 @@ export class GeminiProvider extends LLMProvider {
50
50
  }
51
51
  };
52
52
 
53
+ // When cachedContext is provided (e.g. project rootContextMd), set it as the
54
+ // systemInstruction — Gemini's implicit caching targets system instructions and
55
+ // stable prefix content, giving a best-effort discount with no extra setup.
56
+ if (cachedContext) {
57
+ params.systemInstruction = cachedContext;
58
+ }
59
+
60
+ const _t0Json = Date.now();
53
61
  const response = await this._withRetry(
54
62
  () => this._client.models.generateContent(params),
55
63
  'JSON generation (Gemini)'
@@ -58,8 +66,13 @@ export class GeminiProvider extends LLMProvider {
58
66
  throw new Error('Gemini returned no text (possible safety filter block).');
59
67
  }
60
68
 
61
- this._trackTokens(response.usageMetadata);
62
69
  const content = response.text;
70
+ this._trackTokens(response.usageMetadata, {
71
+ prompt: fullPrompt,
72
+ agentInstructions: agentInstructions ?? null,
73
+ response: content,
74
+ elapsed: Date.now() - _t0Json,
75
+ });
63
76
 
64
77
  // Strip markdown code fences if present (more robust)
65
78
  let jsonStr = content.trim();
@@ -83,7 +96,7 @@ export class GeminiProvider extends LLMProvider {
83
96
  }
84
97
  }
85
98
 
86
- async generateText(prompt, agentInstructions = null) {
99
+ async generateText(prompt, agentInstructions = null, cachedContext = null) {
87
100
  if (!this._client) {
88
101
  this._client = this._createClient();
89
102
  }
@@ -101,6 +114,11 @@ export class GeminiProvider extends LLMProvider {
101
114
  }
102
115
  };
103
116
 
117
+ if (cachedContext) {
118
+ params.systemInstruction = cachedContext;
119
+ }
120
+
121
+ const _t0Text = Date.now();
104
122
  const response = await this._withRetry(
105
123
  () => this._client.models.generateContent(params),
106
124
  'Text generation (Gemini)'
@@ -109,7 +127,13 @@ export class GeminiProvider extends LLMProvider {
109
127
  throw new Error('Gemini returned no text (possible safety filter block).');
110
128
  }
111
129
 
112
- this._trackTokens(response.usageMetadata);
113
- return response.text;
130
+ const text = response.text;
131
+ this._trackTokens(response.usageMetadata, {
132
+ prompt: fullPrompt,
133
+ agentInstructions: agentInstructions ?? null,
134
+ response: text,
135
+ elapsed: Date.now() - _t0Text,
136
+ });
137
+ return text;
114
138
  }
115
139
  }