@praneeth_54/agentdoctor 2.0.1 → 3.0.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 (192) hide show
  1. package/CHANGELOG.md +123 -1
  2. package/README.md +510 -260
  3. package/dist/agent/approvals.d.ts +24 -0
  4. package/dist/agent/approvals.js +64 -0
  5. package/dist/agent/chat/deterministic.d.ts +6 -0
  6. package/dist/agent/chat/deterministic.js +180 -0
  7. package/dist/agent/chat/index.d.ts +7 -0
  8. package/dist/agent/chat/index.js +5 -0
  9. package/dist/agent/chat/memory.d.ts +44 -0
  10. package/dist/agent/chat/memory.js +103 -0
  11. package/dist/agent/chat/project-summary.d.ts +16 -0
  12. package/dist/agent/chat/project-summary.js +70 -0
  13. package/dist/agent/chat/prompts.d.ts +6 -0
  14. package/dist/agent/chat/prompts.js +39 -0
  15. package/dist/agent/chat/response.d.ts +19 -0
  16. package/dist/agent/chat/response.js +109 -0
  17. package/dist/agent/chat/service.d.ts +42 -0
  18. package/dist/agent/chat/service.js +246 -0
  19. package/dist/agent/chat/types.d.ts +48 -0
  20. package/dist/agent/chat/types.js +1 -0
  21. package/dist/agent/context/retrieve.d.ts +21 -0
  22. package/dist/agent/context/retrieve.js +117 -0
  23. package/dist/agent/context/truth.d.ts +6 -0
  24. package/dist/agent/context/truth.js +19 -0
  25. package/dist/agent/context/types.d.ts +23 -0
  26. package/dist/agent/context/types.js +4 -0
  27. package/dist/agent/index.d.ts +28 -0
  28. package/dist/agent/index.js +15 -0
  29. package/dist/agent/loop.d.ts +53 -0
  30. package/dist/agent/loop.js +253 -0
  31. package/dist/agent/modes.d.ts +18 -0
  32. package/dist/agent/modes.js +102 -0
  33. package/dist/agent/plan.d.ts +30 -0
  34. package/dist/agent/plan.js +121 -0
  35. package/dist/agent/roles.d.ts +12 -0
  36. package/dist/agent/roles.js +138 -0
  37. package/dist/agent/runtime.d.ts +83 -0
  38. package/dist/agent/runtime.js +293 -0
  39. package/dist/agent/state.d.ts +30 -0
  40. package/dist/agent/state.js +95 -0
  41. package/dist/agent/student.d.ts +56 -0
  42. package/dist/agent/student.js +230 -0
  43. package/dist/agent/tools/execute.d.ts +20 -0
  44. package/dist/agent/tools/execute.js +365 -0
  45. package/dist/agent/tools/index.d.ts +6 -0
  46. package/dist/agent/tools/index.js +5 -0
  47. package/dist/agent/tools/registry.d.ts +7 -0
  48. package/dist/agent/tools/registry.js +212 -0
  49. package/dist/agent/tools/run.d.ts +24 -0
  50. package/dist/agent/tools/run.js +44 -0
  51. package/dist/agent/tools/types.d.ts +32 -0
  52. package/dist/agent/tools/types.js +10 -0
  53. package/dist/agent/tools/write.d.ts +24 -0
  54. package/dist/agent/tools/write.js +121 -0
  55. package/dist/agent/verify.d.ts +29 -0
  56. package/dist/agent/verify.js +210 -0
  57. package/dist/ai/config.d.ts +22 -0
  58. package/dist/ai/config.js +69 -0
  59. package/dist/ai/index.d.ts +17 -0
  60. package/dist/ai/index.js +52 -0
  61. package/dist/ai/providers/mock.d.ts +20 -0
  62. package/dist/ai/providers/mock.js +84 -0
  63. package/dist/ai/providers/none.d.ts +6 -0
  64. package/dist/ai/providers/none.js +23 -0
  65. package/dist/ai/providers/openai-compatible.d.ts +21 -0
  66. package/dist/ai/providers/openai-compatible.js +151 -0
  67. package/dist/ai/redact.d.ts +9 -0
  68. package/dist/ai/redact.js +61 -0
  69. package/dist/ai/types.d.ts +71 -0
  70. package/dist/ai/types.js +6 -0
  71. package/dist/cli/commands/agent.d.ts +29 -0
  72. package/dist/cli/commands/agent.js +164 -0
  73. package/dist/cli/commands/chat.d.ts +14 -0
  74. package/dist/cli/commands/chat.js +153 -0
  75. package/dist/cli/commands/learn.d.ts +12 -0
  76. package/dist/cli/commands/learn.js +107 -0
  77. package/dist/cli/commands/product.d.ts +19 -0
  78. package/dist/cli/commands/product.js +147 -0
  79. package/dist/cli/commands/start.d.ts +15 -0
  80. package/dist/cli/commands/start.js +80 -0
  81. package/dist/cli/program.js +233 -0
  82. package/dist/constants.d.ts +1 -1
  83. package/dist/constants.js +1 -1
  84. package/dist/dashboard/server.d.ts +6 -0
  85. package/dist/dashboard/server.js +333 -43
  86. package/dist/enforcement/runner.d.ts +5 -0
  87. package/dist/enforcement/runner.js +51 -4
  88. package/dist/index.d.ts +17 -0
  89. package/dist/index.js +10 -0
  90. package/dist/intelligence/graph/build.js +36 -8
  91. package/dist/intelligence/resolve/imports.js +1 -1
  92. package/dist/languages/dart.d.ts +10 -0
  93. package/dist/languages/dart.js +99 -0
  94. package/dist/languages/go.d.ts +13 -7
  95. package/dist/languages/go.js +91 -26
  96. package/dist/languages/index.d.ts +5 -1
  97. package/dist/languages/index.js +13 -36
  98. package/dist/languages/java.d.ts +10 -0
  99. package/dist/languages/java.js +80 -0
  100. package/dist/languages/kotlin.d.ts +10 -0
  101. package/dist/languages/kotlin.js +85 -0
  102. package/dist/languages/php.d.ts +1 -0
  103. package/dist/languages/php.js +11 -2
  104. package/dist/languages/python.d.ts +6 -2
  105. package/dist/languages/python.js +39 -9
  106. package/dist/languages/rust.d.ts +10 -0
  107. package/dist/languages/rust.js +93 -0
  108. package/dist/languages/types.d.ts +4 -3
  109. package/dist/mcp/agent/registry.d.ts +13 -0
  110. package/dist/mcp/agent/registry.js +320 -0
  111. package/dist/mcp/agentdoctor/server.js +8 -1
  112. package/dist/mcp/intelligence/handlers.d.ts +3 -0
  113. package/dist/mcp/intelligence/handlers.js +28 -0
  114. package/dist/mcp/intelligence/registry.d.ts +1 -1
  115. package/dist/mcp/intelligence/registry.js +30 -1
  116. package/dist/product/api/doctor.d.ts +14 -0
  117. package/dist/product/api/doctor.js +185 -0
  118. package/dist/product/api/openapi.d.ts +7 -0
  119. package/dist/product/api/openapi.js +122 -0
  120. package/dist/product/approval/model.d.ts +30 -0
  121. package/dist/product/approval/model.js +64 -0
  122. package/dist/product/approval/session.d.ts +49 -0
  123. package/dist/product/approval/session.js +134 -0
  124. package/dist/product/database/doctor.d.ts +30 -0
  125. package/dist/product/database/doctor.js +184 -0
  126. package/dist/product/decisions/ledger.d.ts +24 -0
  127. package/dist/product/decisions/ledger.js +110 -0
  128. package/dist/product/deps/analyze.d.ts +46 -0
  129. package/dist/product/deps/analyze.js +137 -0
  130. package/dist/product/deps/lockfiles.d.ts +25 -0
  131. package/dist/product/deps/lockfiles.js +200 -0
  132. package/dist/product/discovery/roots.d.ts +42 -0
  133. package/dist/product/discovery/roots.js +215 -0
  134. package/dist/product/dna/build.d.ts +50 -0
  135. package/dist/product/dna/build.js +255 -0
  136. package/dist/product/eval/lab.d.ts +17 -0
  137. package/dist/product/eval/lab.js +218 -0
  138. package/dist/product/events/doctor.d.ts +21 -0
  139. package/dist/product/events/doctor.js +147 -0
  140. package/dist/product/evidence-scan.d.ts +12 -0
  141. package/dist/product/evidence-scan.js +46 -0
  142. package/dist/product/evolution/timeline.d.ts +29 -0
  143. package/dist/product/evolution/timeline.js +123 -0
  144. package/dist/product/features/intelligence.d.ts +23 -0
  145. package/dist/product/features/intelligence.js +158 -0
  146. package/dist/product/forensic/mode.d.ts +25 -0
  147. package/dist/product/forensic/mode.js +70 -0
  148. package/dist/product/graph/enrich-languages.d.ts +20 -0
  149. package/dist/product/graph/enrich-languages.js +193 -0
  150. package/dist/product/health/code-health.d.ts +20 -0
  151. package/dist/product/health/code-health.js +149 -0
  152. package/dist/product/index.d.ts +69 -0
  153. package/dist/product/index.js +35 -0
  154. package/dist/product/ledger/change-ledger.d.ts +23 -0
  155. package/dist/product/ledger/change-ledger.js +64 -0
  156. package/dist/product/map/software-map.d.ts +17 -0
  157. package/dist/product/map/software-map.js +95 -0
  158. package/dist/product/memory/institutional.d.ts +16 -0
  159. package/dist/product/memory/institutional.js +87 -0
  160. package/dist/product/ops/incident.d.ts +20 -0
  161. package/dist/product/ops/incident.js +61 -0
  162. package/dist/product/ops/infra.d.ts +15 -0
  163. package/dist/product/ops/infra.js +112 -0
  164. package/dist/product/org/model.d.ts +34 -0
  165. package/dist/product/org/model.js +195 -0
  166. package/dist/product/privacy/doctor.d.ts +13 -0
  167. package/dist/product/privacy/doctor.js +90 -0
  168. package/dist/product/requirements/trace.d.ts +21 -0
  169. package/dist/product/requirements/trace.js +166 -0
  170. package/dist/product/search/index.d.ts +29 -0
  171. package/dist/product/search/index.js +116 -0
  172. package/dist/product/search/software-search.d.ts +19 -0
  173. package/dist/product/search/software-search.js +100 -0
  174. package/dist/product/security/doctor.d.ts +23 -0
  175. package/dist/product/security/doctor.js +124 -0
  176. package/dist/product/self/diagnose.d.ts +15 -0
  177. package/dist/product/self/diagnose.js +82 -0
  178. package/dist/product/techdebt/roadmap.d.ts +20 -0
  179. package/dist/product/techdebt/roadmap.js +118 -0
  180. package/dist/product/testbrain/analyze.d.ts +29 -0
  181. package/dist/product/testbrain/analyze.js +129 -0
  182. package/dist/product/truth.d.ts +12 -0
  183. package/dist/product/truth.js +30 -0
  184. package/dist/product/twin/digital-twin.d.ts +23 -0
  185. package/dist/product/twin/digital-twin.js +52 -0
  186. package/dist/product/twin/store.d.ts +21 -0
  187. package/dist/product/twin/store.js +70 -0
  188. package/dist/product/whatif/engine.d.ts +28 -0
  189. package/dist/product/whatif/engine.js +70 -0
  190. package/dist/security/paths.js +43 -15
  191. package/dist/utils/fs.js +10 -2
  192. package/package.json +1 -1
@@ -21,6 +21,28 @@ import { CONTRACTS_VERSION } from "../contracts/index.js";
21
21
  import { collectOpsHealth } from "../ops/health.js";
22
22
  import { listPolicyPacks } from "../policy/packs.js";
23
23
  import { sanitizeForOutput } from "../utils/path.js";
24
+ import { createModelProvider, loadAiConfig } from "../ai/index.js";
25
+ import { ChatService } from "../agent/chat/service.js";
26
+ import { formatChatResponseForCli } from "../agent/chat/response.js";
27
+ import { buildProjectDna } from "../product/dna/build.js";
28
+ import { buildSoftwareMap } from "../product/map/software-map.js";
29
+ import { buildSoftwareDigitalTwin } from "../product/twin/store.js";
30
+ import { analyzeCodeHealth } from "../product/health/code-health.js";
31
+ import { traceRequirements } from "../product/requirements/trace.js";
32
+ import { analyzeApiSurface } from "../product/api/doctor.js";
33
+ import { analyzeDatabaseSchema } from "../product/database/doctor.js";
34
+ import { analyzeEvents } from "../product/events/doctor.js";
35
+ import { analyzeDependencies } from "../product/deps/analyze.js";
36
+ import { analyzeSecuritySurface } from "../product/security/doctor.js";
37
+ import { searchSymbolsAndConcepts } from "../product/search/software-search.js";
38
+ import { analyzeWhatIf } from "../product/whatif/engine.js";
39
+ import { runForensicAnalysis } from "../product/forensic/mode.js";
40
+ import { buildIncidentHypotheses } from "../product/ops/incident.js";
41
+ import { analyzeInfra } from "../product/ops/infra.js";
42
+ import { analyzeFeatureIntelligence } from "../product/features/intelligence.js";
43
+ import { buildSoftwareEvolutionTimeline } from "../product/evolution/timeline.js";
44
+ import { queryMemory } from "../product/memory/institutional.js";
45
+ import { loadDecisionLedger } from "../product/decisions/ledger.js";
24
46
  function safeJsonError(error) {
25
47
  const raw = error instanceof Error ? error.message : String(error);
26
48
  const { text } = redactSecrets(sanitizeForOutput(raw));
@@ -96,65 +118,207 @@ function htmlPage() {
96
118
  </header>
97
119
  <main>
98
120
  <nav aria-label="Views" style="display:flex;flex-wrap:wrap;gap:0.75rem;font-size:0.9rem">
99
- <a href="#overview">Overview</a>
100
- <a href="#scan">Safety scan</a>
101
- <a href="#platform">Platform</a>
102
- <a href="#brain">Brain</a>
121
+ <a href="#home">Home</a>
122
+ <a href="#dna">DNA</a>
103
123
  <a href="#graph">Graph</a>
104
- <a href="#knowledge">Knowledge</a>
105
- <a href="#meta">Audit / baselines</a>
124
+ <a href="#chat">Chat</a>
125
+ <a href="#security">Security</a>
126
+ <a href="#twin">Twin</a>
127
+ <a href="#requirements">Requirements</a>
128
+ <a href="#map">Map</a>
129
+ <a href="#features">Features</a>
130
+ <a href="#deps">Deps</a>
131
+ <a href="#search">Search</a>
132
+ <a href="#whatif">What-if</a>
133
+ <a href="#forensic">Forensic</a>
134
+ <a href="#incident">Incident</a>
135
+ <a href="#infra">Infra</a>
136
+ <a href="#evolution">Evolution</a>
137
+ <a href="#memory">Memory</a>
138
+ <a href="#decisions">Decisions</a>
139
+ <a href="#health">Health</a>
140
+ <a href="#agent">Doctors</a>
106
141
  </nav>
107
- <section id="overview">
108
- <h2>Overview</h2>
142
+ <section id="home" data-route="home">
143
+ <h2>Home</h2>
109
144
  <pre id="status" class="muted">Loading…</pre>
110
145
  </section>
111
- <section id="scan">
112
- <h2>Safety scan</h2>
113
- <pre id="scanBody" class="muted">Loading…</pre>
146
+ <section id="dna" data-route="dna" hidden>
147
+ <h2>Project DNA</h2>
148
+ <pre id="dnaBody" class="muted">Loading…</pre>
114
149
  </section>
115
- <section id="platform">
116
- <h2>Platform snapshot (incl. test-impact)</h2>
117
- <pre id="platformBody" class="muted">Loading…</pre>
150
+ <section id="graph" data-route="graph" hidden>
151
+ <h2>Graph / Git / C4</h2>
152
+ <pre id="graphBody" class="muted">Loading…</pre>
118
153
  </section>
119
- <section id="brain">
120
- <h2>Project Brain</h2>
121
- <pre id="brainBody" class="muted">Loading…</pre>
154
+ <section id="security" data-route="security" hidden>
155
+ <h2>Security doctor</h2>
156
+ <pre id="securityBody" class="muted">Loading…</pre>
122
157
  </section>
123
- <section id="graph">
124
- <h2>Intelligence graph / git / C4</h2>
125
- <pre id="graphBody" class="muted">Loading…</pre>
158
+ <section id="twin" data-route="twin" hidden>
159
+ <h2>Digital twin</h2>
160
+ <pre id="twinBody" class="muted">Loading…</pre>
161
+ </section>
162
+ <section id="requirements" data-route="requirements" hidden>
163
+ <h2>Requirements trace</h2>
164
+ <pre id="requirementsBody" class="muted">Loading…</pre>
165
+ </section>
166
+ <section id="map" data-route="map" hidden>
167
+ <h2>Software map</h2>
168
+ <pre id="mapBody" class="muted">Loading…</pre>
169
+ </section>
170
+ <section id="features" data-route="features" hidden>
171
+ <h2>Feature intelligence</h2>
172
+ <pre id="featuresBody" class="muted">Loading…</pre>
173
+ </section>
174
+ <section id="deps" data-route="deps" hidden>
175
+ <h2>Dependencies</h2>
176
+ <pre id="depsBody" class="muted">Loading…</pre>
177
+ </section>
178
+ <section id="search" data-route="search" hidden>
179
+ <h2>Software search</h2>
180
+ <pre id="searchBody" class="muted">Loading…</pre>
181
+ </section>
182
+ <section id="whatif" data-route="whatif" hidden>
183
+ <h2>What-if</h2>
184
+ <pre id="whatifBody" class="muted">Loading…</pre>
185
+ </section>
186
+ <section id="forensic" data-route="forensic" hidden>
187
+ <h2>Forensic</h2>
188
+ <pre id="forensicBody" class="muted">Loading…</pre>
189
+ </section>
190
+ <section id="incident" data-route="incident" hidden>
191
+ <h2>Incident</h2>
192
+ <pre id="incidentBody" class="muted">Loading…</pre>
126
193
  </section>
127
- <section id="knowledge">
128
- <h2>Governed knowledge</h2>
129
- <pre id="knowledgeBody" class="muted">Loading…</pre>
194
+ <section id="infra" data-route="infra" hidden>
195
+ <h2>Infra</h2>
196
+ <pre id="infraBody" class="muted">Loading…</pre>
130
197
  </section>
131
- <section id="meta">
132
- <h2>Safe Fix audit / baselines / sessions</h2>
133
- <pre id="metaBody" class="muted">Loading…</pre>
198
+ <section id="evolution" data-route="evolution" hidden>
199
+ <h2>Evolution</h2>
200
+ <pre id="evolutionBody" class="muted">Loading…</pre>
201
+ </section>
202
+ <section id="memory" data-route="memory" hidden>
203
+ <h2>Institutional memory</h2>
204
+ <pre id="memoryBody" class="muted">Loading…</pre>
205
+ </section>
206
+ <section id="decisions" data-route="decisions" hidden>
207
+ <h2>Decisions</h2>
208
+ <pre id="decisionsBody" class="muted">Loading…</pre>
209
+ </section>
210
+ <section id="health" data-route="health" hidden>
211
+ <h2>Code health</h2>
212
+ <pre id="healthBody" class="muted">Loading…</pre>
213
+ </section>
214
+ <section id="agent" data-route="agent" hidden>
215
+ <h2>Product doctors (API, DB, events)</h2>
216
+ <pre id="agentBody" class="muted">Loading…</pre>
217
+ </section>
218
+ <section id="chat" data-route="chat" hidden>
219
+ <h2>Project Chat</h2>
220
+ <p class="muted">Ask about this repository. Answers use evidence + truth labels. No file writes from this panel.</p>
221
+ <div style="display:grid;grid-template-columns:1.4fr 1fr;gap:1rem">
222
+ <div>
223
+ <textarea id="chatInput" rows="3" style="width:100%;background:#0d1520;color:#e8eef5;border:1px solid #243040;border-radius:8px;padding:0.6rem" placeholder="How does authentication work?"></textarea>
224
+ <button id="chatAsk" style="margin-top:0.5rem;background:var(--accent);color:#041018;border:0;border-radius:6px;padding:0.45rem 0.9rem;font-weight:600;cursor:pointer">Ask</button>
225
+ <pre id="chatBody" class="muted" style="margin-top:0.75rem">Ask a question…</pre>
226
+ </div>
227
+ <div>
228
+ <h3 style="margin:0 0 0.5rem;font-size:0.9rem">Evidence</h3>
229
+ <pre id="chatEvidence" class="muted">—</pre>
230
+ </div>
231
+ </div>
134
232
  </section>
135
233
  </main>
136
234
  <script>
235
+ const routes = ['home','dna','graph','chat','security','twin','requirements','map','features','deps','search','whatif','forensic','incident','infra','evolution','memory','decisions','health','agent'];
236
+ function showRoute(name) {
237
+ const r = routes.includes(name) ? name : 'home';
238
+ for (const el of document.querySelectorAll('[data-route]')) {
239
+ el.hidden = el.getAttribute('data-route') !== r;
240
+ }
241
+ location.hash = r;
242
+ }
243
+ window.addEventListener('hashchange', () => showRoute((location.hash || '#home').slice(1)));
244
+ showRoute((location.hash || '#home').slice(1));
245
+
246
+ async function loadSection(route) {
247
+ const map = {
248
+ dna: [['dnaBody','/api/dna']],
249
+ graph: [['graphBody','/api/v2/graph']],
250
+ security: [['securityBody','/api/security']],
251
+ twin: [['twinBody','/api/twin']],
252
+ requirements: [['requirementsBody','/api/requirements']],
253
+ map: [['mapBody','/api/map']],
254
+ features: [['featuresBody','/api/features']],
255
+ deps: [['depsBody','/api/deps']],
256
+ search: [['searchBody','/api/search?q=main']],
257
+ whatif: [['whatifBody','/api/what-if?target=src']],
258
+ forensic: [['forensicBody','/api/forensic']],
259
+ incident: [['incidentBody','/api/incident']],
260
+ infra: [['infraBody','/api/infra']],
261
+ evolution: [['evolutionBody','/api/evolution']],
262
+ memory: [['memoryBody','/api/memory?q=change']],
263
+ decisions: [['decisionsBody','/api/decisions']],
264
+ health: [['healthBody','/api/health']],
265
+ agent: [['agentBody','/api/api-doctor']],
266
+ };
267
+ if (route === 'home') {
268
+ const [status, scan, brain, platform] = await Promise.all([
269
+ fetch('/api/status').then(r => r.json()),
270
+ fetch('/api/scan').then(r => r.json()),
271
+ fetch('/api/brain').then(r => r.json()),
272
+ fetch('/api/platform').then(r => r.json()),
273
+ ]);
274
+ document.getElementById('status').textContent = JSON.stringify({ status, scan, brain, platform }, null, 2);
275
+ return;
276
+ }
277
+ if (route === 'agent') {
278
+ const [api, db, events] = await Promise.all([
279
+ fetch('/api/api-doctor').then(r => r.json()),
280
+ fetch('/api/database').then(r => r.json()),
281
+ fetch('/api/events').then(r => r.json()),
282
+ ]);
283
+ document.getElementById('agentBody').textContent = JSON.stringify({ api, db, events }, null, 2);
284
+ return;
285
+ }
286
+ const loaders = map[route] || [];
287
+ for (const [elId, url] of loaders) {
288
+ const data = await fetch(url).then(r => r.json());
289
+ document.getElementById(elId).textContent = JSON.stringify(data, null, 2);
290
+ }
291
+ }
137
292
  async function load() {
138
- const [status, scan, brain, meta, platform, graph, knowledge] = await Promise.all([
139
- fetch('/api/status').then(r => r.json()),
140
- fetch('/api/scan').then(r => r.json()),
141
- fetch('/api/brain').then(r => r.json()),
142
- fetch('/api/meta').then(r => r.json()),
143
- fetch('/api/platform').then(r => r.json()),
144
- fetch('/api/v2/graph').then(r => r.json()),
145
- fetch('/api/v2/knowledge').then(r => r.json()),
146
- ]);
147
- document.getElementById('status').textContent = JSON.stringify(status, null, 2);
148
- document.getElementById('scanBody').textContent = JSON.stringify(scan, null, 2);
149
- document.getElementById('brainBody').textContent = JSON.stringify(brain, null, 2);
150
- document.getElementById('metaBody').textContent = JSON.stringify(meta, null, 2);
151
- document.getElementById('platformBody').textContent = JSON.stringify(platform, null, 2);
152
- document.getElementById('graphBody').textContent = JSON.stringify(graph, null, 2);
153
- document.getElementById('knowledgeBody').textContent = JSON.stringify(knowledge, null, 2);
293
+ const route = (location.hash || '#home').slice(1) || 'home';
294
+ await loadSection(route);
154
295
  }
296
+ window.addEventListener('hashchange', () => load().catch(err => console.error(err)));
155
297
  load().catch(err => {
156
298
  document.getElementById('status').textContent = String(err);
157
299
  });
300
+ document.getElementById('chatAsk').addEventListener('click', async () => {
301
+ const question = document.getElementById('chatInput').value.trim();
302
+ if (!question) return;
303
+ document.getElementById('chatBody').textContent = 'Thinking…';
304
+ try {
305
+ const res = await fetch('/api/chat', {
306
+ method: 'POST',
307
+ headers: { 'Content-Type': 'application/json' },
308
+ body: JSON.stringify({ question }),
309
+ });
310
+ const data = await res.json();
311
+ document.getElementById('chatBody').textContent = data.message || JSON.stringify(data, null, 2);
312
+ document.getElementById('chatEvidence').textContent = JSON.stringify({
313
+ truthClaims: data.truthClaims || [],
314
+ citations: data.citations || [],
315
+ limitations: data.limitations || [],
316
+ status: data.status,
317
+ }, null, 2);
318
+ } catch (err) {
319
+ document.getElementById('chatBody').textContent = String(err);
320
+ }
321
+ });
158
322
  </script>
159
323
  </body>
160
324
  </html>`;
@@ -186,8 +350,47 @@ export async function startDashboardServer(options) {
186
350
  return;
187
351
  }
188
352
  const url = new URL(rawUrl, `http://${host}:${port}`);
353
+ if (req.method === "POST" && url.pathname === "/api/chat") {
354
+ const chunks = [];
355
+ for await (const chunk of req) {
356
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
357
+ }
358
+ let body = {};
359
+ try {
360
+ body = JSON.parse(Buffer.concat(chunks).toString("utf8") || "{}");
361
+ }
362
+ catch {
363
+ sendJson(res, 400, { error: "invalid JSON body" });
364
+ return;
365
+ }
366
+ const question = typeof body.question === "string" ? body.question.trim() : "";
367
+ if (!question) {
368
+ sendJson(res, 400, { error: "question required" });
369
+ return;
370
+ }
371
+ const provider = options.chatProvider ?? createModelProvider(loadAiConfig());
372
+ const chat = new ChatService({
373
+ root,
374
+ provider,
375
+ persistAudit: false,
376
+ });
377
+ try {
378
+ const response = await chat.ask(question);
379
+ sendJson(res, response.status === "ok" ? 200 : 502, {
380
+ ...response,
381
+ cliPreview: formatChatResponseForCli(response),
382
+ note: "Dashboard chat is ask-only; it does not edit files or run commands.",
383
+ });
384
+ }
385
+ finally {
386
+ await chat.end();
387
+ }
388
+ return;
389
+ }
189
390
  if (req.method !== "GET") {
190
- sendJson(res, 405, { error: "read-only dashboard; GET only" });
391
+ sendJson(res, 405, {
392
+ error: "dashboard is read-only except POST /api/chat (ask-only; no repo writes)",
393
+ });
191
394
  return;
192
395
  }
193
396
  if (pathnameLooksHostile(url.pathname)) {
@@ -363,6 +566,93 @@ export async function startDashboardServer(options) {
363
566
  });
364
567
  return;
365
568
  }
569
+ if (url.pathname === "/api/dna") {
570
+ sendJson(res, 200, await buildProjectDna(root));
571
+ return;
572
+ }
573
+ if (url.pathname === "/api/map") {
574
+ sendJson(res, 200, await buildSoftwareMap(root));
575
+ return;
576
+ }
577
+ if (url.pathname === "/api/twin") {
578
+ sendJson(res, 200, await buildSoftwareDigitalTwin(root));
579
+ return;
580
+ }
581
+ if (url.pathname === "/api/health-code") {
582
+ sendJson(res, 200, await analyzeCodeHealth(root));
583
+ return;
584
+ }
585
+ if (url.pathname === "/api/requirements") {
586
+ sendJson(res, 200, await traceRequirements(root));
587
+ return;
588
+ }
589
+ if (url.pathname === "/api/api-doctor") {
590
+ sendJson(res, 200, await analyzeApiSurface(root));
591
+ return;
592
+ }
593
+ if (url.pathname === "/api/database") {
594
+ sendJson(res, 200, await analyzeDatabaseSchema(root));
595
+ return;
596
+ }
597
+ if (url.pathname === "/api/events") {
598
+ sendJson(res, 200, await analyzeEvents(root));
599
+ return;
600
+ }
601
+ if (url.pathname === "/api/deps") {
602
+ sendJson(res, 200, await analyzeDependencies(root));
603
+ return;
604
+ }
605
+ if (url.pathname === "/api/security") {
606
+ sendJson(res, 200, await analyzeSecuritySurface(root));
607
+ return;
608
+ }
609
+ if (url.pathname === "/api/search") {
610
+ const q = url.searchParams.get("q") ?? "";
611
+ sendJson(res, 200, await searchSymbolsAndConcepts(root, q));
612
+ return;
613
+ }
614
+ if (url.pathname === "/api/what-if") {
615
+ const target = url.searchParams.get("target") ?? "";
616
+ if (!target.trim()) {
617
+ sendJson(res, 400, { error: "target query param required" });
618
+ return;
619
+ }
620
+ sendJson(res, 200, await analyzeWhatIf(root, target));
621
+ return;
622
+ }
623
+ if (url.pathname === "/api/forensic") {
624
+ sendJson(res, 200, await runForensicAnalysis(root));
625
+ return;
626
+ }
627
+ if (url.pathname === "/api/incident") {
628
+ sendJson(res, 200, await buildIncidentHypotheses(root));
629
+ return;
630
+ }
631
+ if (url.pathname === "/api/infra") {
632
+ sendJson(res, 200, await analyzeInfra(root));
633
+ return;
634
+ }
635
+ if (url.pathname === "/api/features") {
636
+ sendJson(res, 200, await analyzeFeatureIntelligence(root));
637
+ return;
638
+ }
639
+ if (url.pathname === "/api/evolution") {
640
+ sendJson(res, 200, await buildSoftwareEvolutionTimeline(root));
641
+ return;
642
+ }
643
+ if (url.pathname === "/api/memory") {
644
+ const q = url.searchParams.get("q") ?? "";
645
+ sendJson(res, 200, await queryMemory(root, q));
646
+ return;
647
+ }
648
+ if (url.pathname === "/api/decisions") {
649
+ sendJson(res, 200, await loadDecisionLedger(root));
650
+ return;
651
+ }
652
+ if (url.pathname === "/api/health") {
653
+ sendJson(res, 200, await analyzeCodeHealth(root));
654
+ return;
655
+ }
366
656
  if (url.pathname === "/api/v2/projects" || url.pathname === "/api/v2/workspaces") {
367
657
  sendJson(res, 200, {
368
658
  mode: "local-single-repo",
@@ -1,4 +1,9 @@
1
1
  import type { PolicyDecisionContract } from "../contracts/index.js";
2
+ /**
3
+ * Map argv to a portable executable form for shell:false execution.
4
+ * Policy evaluation still uses the original human-facing argv/command string.
5
+ */
6
+ export declare function resolveExecutableArgv(argv: string[]): string[];
2
7
  export type ExecutionStatus = "executed" | "blocked-by-enforcement" | "not-executed" | "execution-failed";
3
8
  export interface EnforcementResult {
4
9
  decision: PolicyDecisionContract;
@@ -4,15 +4,59 @@ import { execFile, spawn } from "node:child_process";
4
4
  import fs from "node:fs/promises";
5
5
  import path from "node:path";
6
6
  import { promisify } from "node:util";
7
- import { realpathSync } from "node:fs";
7
+ import { existsSync, realpathSync } from "node:fs";
8
8
  import { evaluateAgentAction, EVALUATE_ONLY } from "../platform/firewall/evaluate.js";
9
9
  import { resolveRepoRoot } from "../utils/path.js";
10
10
  import { PathEscapeError, assertInsideRepo } from "../security/paths.js";
11
11
  const execFileAsync = promisify(execFile);
12
+ /**
13
+ * Resolve npm/npx to `node <cli.js>` on Windows so execFile(shell:false) does not
14
+ * hit ENOENT on the `npm` name or fail to spawn `.cmd` shims without a shell.
15
+ */
16
+ function resolveNpmCliJs(cliFile) {
17
+ const candidates = [
18
+ path.join(path.dirname(process.execPath), "node_modules", "npm", "bin", cliFile),
19
+ path.join(path.dirname(process.execPath), "..", "lib", "node_modules", "npm", "bin", cliFile),
20
+ ];
21
+ for (const candidate of candidates) {
22
+ if (existsSync(candidate))
23
+ return candidate;
24
+ }
25
+ return null;
26
+ }
27
+ /**
28
+ * Map argv to a portable executable form for shell:false execution.
29
+ * Policy evaluation still uses the original human-facing argv/command string.
30
+ */
31
+ export function resolveExecutableArgv(argv) {
32
+ if (argv.length === 0)
33
+ return argv;
34
+ const bin = argv[0];
35
+ if (process.platform === "win32" && (bin === "npm" || bin === "npx")) {
36
+ const cli = resolveNpmCliJs(bin === "npx" ? "npx-cli.js" : "npm-cli.js");
37
+ if (cli) {
38
+ return [process.execPath, cli, ...argv.slice(1)];
39
+ }
40
+ // Last resort: .cmd name (may still require shell on some hosts).
41
+ return [`${bin}.cmd`, ...argv.slice(1)];
42
+ }
43
+ return argv;
44
+ }
12
45
  const DEFAULT_TIMEOUT_MS = 30_000;
13
46
  const DEFAULT_MAX_BUFFER = 1024 * 1024;
14
47
  const OUTPUT_TRUNCATE = 32_768;
15
- const ENV_ALLOWLIST = new Set(["PATH", "NODE_ENV", "HOME", "LANG"]);
48
+ const ENV_ALLOWLIST = new Set([
49
+ "PATH",
50
+ "Path",
51
+ "NODE_ENV",
52
+ "HOME",
53
+ "USERPROFILE",
54
+ "LANG",
55
+ "SystemRoot",
56
+ "SYSTEMROOT",
57
+ "ComSpec",
58
+ "PATHEXT",
59
+ ]);
16
60
  /**
17
61
  * Parse a command string into argv without invoking a shell.
18
62
  * Supports simple double/single quotes; rejects unclosed quotes.
@@ -195,7 +239,8 @@ async function executeArgv(options) {
195
239
  });
196
240
  });
197
241
  }
198
- const [file, ...args] = options.argv;
242
+ const resolved = resolveExecutableArgv(options.argv);
243
+ const [file, ...args] = resolved;
199
244
  if (!file) {
200
245
  return {
201
246
  stdout: "",
@@ -206,6 +251,8 @@ async function executeArgv(options) {
206
251
  error: "empty command",
207
252
  };
208
253
  }
254
+ // Windows .cmd shims cannot be execFile'd with shell:false; use shell only then.
255
+ const needsWindowsCmdShell = process.platform === "win32" && /\.(cmd|bat)$/i.test(file);
209
256
  try {
210
257
  const result = await execFileAsync(file, args, {
211
258
  cwd,
@@ -213,7 +260,7 @@ async function executeArgv(options) {
213
260
  timeout: options.timeoutMs,
214
261
  maxBuffer: options.maxBuffer,
215
262
  windowsHide: true,
216
- shell: false,
263
+ shell: needsWindowsCmdShell,
217
264
  });
218
265
  return {
219
266
  stdout: truncate(typeof result.stdout === "string" ? result.stdout : String(result.stdout)),
package/dist/index.d.ts CHANGED
@@ -50,3 +50,20 @@ export { runFix } from "./core/fix/run.js";
50
50
  export { evaluatePolicy, evaluateScanPolicy, evaluateVerifyPolicy, parseFailOnRules, parseSeverityGate, } from "./core/policy/evaluate.js";
51
51
  export type { PolicyOptions, PolicyViolation, PolicyViolationCode, PolicyInput, } from "./core/policy/evaluate.js";
52
52
  export type { FixPlan, FixAction, FixApplyResult } from "./core/fix/types.js";
53
+ /** AgentDoctor 2.1 AI provider layer (optional — core works without AI). */
54
+ export { createModelProvider, loadAiConfig, publicAiConfig, redactForModel, AI_PROVIDER_REQUIRED_MESSAGE, NoneModelProvider, MockModelProvider, OpenAiCompatibleProvider, } from "./ai/index.js";
55
+ export type { AiConfig, AiProviderId, ChatMessage, ChatRequest, ChatResponse, ModelMetadata, ModelProvider, ToolSpec, ToolCallRequest, TokenUsage, } from "./ai/index.js";
56
+ /** AgentDoctor 2.1 Project AI Agent core (M1 scaffolding). */
57
+ export { AgentState, AgentStateMachine, AgentRuntime, DEFAULT_AGENT_LIMITS, retrieveProjectContext, truthLabelHelp, minTruth, } from "./agent/index.js";
58
+ export type { AgentLimits, AgentAuditEvent, AgentRuntimeOptions, AgentTurnResult, AgentStateTransition, ContextBundle, ContextCitation, EvidenceType, TruthLabel, RetrieveContextOptions, } from "./agent/index.js";
59
+ export { ChatService, createChatService, ChatMemory, CHAT_PROVIDER_NONE_MESSAGE, buildChatTurnResponse, formatChatResponseForCli, summarizeProjectForChat, } from "./agent/chat/index.js";
60
+ export type { ChatTurnResponse, ChatServiceOptions, TruthClaim, ProjectChatSummary, } from "./agent/chat/index.js";
61
+ /** AgentDoctor 2.1 agent tools + plan (M3). */
62
+ export { listAgentToolSpecs, getToolSpec, riskForTool, executeAgentTool, isReadTool, newToolCall, evaluateApproval, formatApprovalPrompt, buildAgentPlan, formatAgentPlan, approvePlan, runCodingLoop, verifyAgentWork, formatVerificationReport, } from "./agent/index.js";
63
+ export type { AgentToolName, AgentToolSpec, AgentToolCall, AgentToolResult, AgentRiskLevel, ApprovalRequest, ApprovalResult, ApprovalDecision, AgentPlan, AgentPlanStep, CodingLoopOptions, CodingLoopResult, AgentVerificationReport, VerificationCheck, } from "./agent/index.js";
64
+ export { getModeProfile, defaultStudentMode, parseAgentMode, modeAllowsMutation, modeBlocksToolCategory, StudentService, } from "./agent/index.js";
65
+ export { traceRequirements, analyzeApiSurface, analyzeDatabaseSchema, analyzeEvents, analyzeDependencies, analyzeCodeHealth, buildSoftwareMap, appendChangeLedgerEntry, readChangeLedger, analyzeWhatIf, loadDecisionLedger, runForensicAnalysis, assertForensicReadOnly, buildSoftwareDigitalTwin, runEvalLab, diagnoseAgentDoctorSelf, analyzeInfra, buildIncidentHypotheses, enrichGraphWithLanguageAdapters, analyzeSecuritySurface, analyzePrivacySurface, searchSymbolsAndConcepts, buildTechnicalDebtRoadmap, loadOrganizationModel, saveOrganizationModel, linkProjectToOrgModel, analyzeFeatureIntelligence, buildSoftwareEvolutionTimeline, queryMemory, evaluateApprovalRecord, formatApprovalRecordSummary, issueApprovalGrant, consumeApprovalGrant, hashPlanPayload, hashFileWritePlan, minProductTruth, truthLabelDescription, } from "./product/index.js";
66
+ export type { TruthLabel as ProductTruthLabel, ProductEvidence, RequirementsTraceReport, ApiDoctorReport, DatabaseDoctorReport, EventsDoctorReport, DependencyAnalysisReport, CodeHealthReport, SoftwareMap, ChangeLedgerEntry, WhatIfReport, DecisionRecord, ForensicAnalysisReport, SoftwareDigitalTwin, EvalLabReport, SelfDiagnoseReport, InfraReport, IncidentReport, LanguageGraphEnrichmentStats, SecurityDoctorReport, PrivacyDoctorReport, SoftwareSearchReport, TechnicalDebtRoadmap, OrganizationModel, FeatureIntelligenceReport, SoftwareEvolutionReport, InstitutionalMemoryQueryResult, ApprovalRecord, } from "./product/index.js";
67
+ export { rolePrompt, roleAllowedTools, runRoleAgent } from "./agent/roles.js";
68
+ export type { AgentRole, RoleAgentOptions } from "./agent/roles.js";
69
+ export type { AgentMode, ModeProfile, StudentDocSection, BuildWithMeResult, } from "./agent/index.js";
package/dist/index.js CHANGED
@@ -36,3 +36,13 @@ export { buildFixPlan } from "./core/fix/plan.js";
36
36
  export { applyFixPlan } from "./core/fix/apply.js";
37
37
  export { runFix } from "./core/fix/run.js";
38
38
  export { evaluatePolicy, evaluateScanPolicy, evaluateVerifyPolicy, parseFailOnRules, parseSeverityGate, } from "./core/policy/evaluate.js";
39
+ /** AgentDoctor 2.1 AI provider layer (optional — core works without AI). */
40
+ export { createModelProvider, loadAiConfig, publicAiConfig, redactForModel, AI_PROVIDER_REQUIRED_MESSAGE, NoneModelProvider, MockModelProvider, OpenAiCompatibleProvider, } from "./ai/index.js";
41
+ /** AgentDoctor 2.1 Project AI Agent core (M1 scaffolding). */
42
+ export { AgentState, AgentStateMachine, AgentRuntime, DEFAULT_AGENT_LIMITS, retrieveProjectContext, truthLabelHelp, minTruth, } from "./agent/index.js";
43
+ export { ChatService, createChatService, ChatMemory, CHAT_PROVIDER_NONE_MESSAGE, buildChatTurnResponse, formatChatResponseForCli, summarizeProjectForChat, } from "./agent/chat/index.js";
44
+ /** AgentDoctor 2.1 agent tools + plan (M3). */
45
+ export { listAgentToolSpecs, getToolSpec, riskForTool, executeAgentTool, isReadTool, newToolCall, evaluateApproval, formatApprovalPrompt, buildAgentPlan, formatAgentPlan, approvePlan, runCodingLoop, verifyAgentWork, formatVerificationReport, } from "./agent/index.js";
46
+ export { getModeProfile, defaultStudentMode, parseAgentMode, modeAllowsMutation, modeBlocksToolCategory, StudentService, } from "./agent/index.js";
47
+ export { traceRequirements, analyzeApiSurface, analyzeDatabaseSchema, analyzeEvents, analyzeDependencies, analyzeCodeHealth, buildSoftwareMap, appendChangeLedgerEntry, readChangeLedger, analyzeWhatIf, loadDecisionLedger, runForensicAnalysis, assertForensicReadOnly, buildSoftwareDigitalTwin, runEvalLab, diagnoseAgentDoctorSelf, analyzeInfra, buildIncidentHypotheses, enrichGraphWithLanguageAdapters, analyzeSecuritySurface, analyzePrivacySurface, searchSymbolsAndConcepts, buildTechnicalDebtRoadmap, loadOrganizationModel, saveOrganizationModel, linkProjectToOrgModel, analyzeFeatureIntelligence, buildSoftwareEvolutionTimeline, queryMemory, evaluateApprovalRecord, formatApprovalRecordSummary, issueApprovalGrant, consumeApprovalGrant, hashPlanPayload, hashFileWritePlan, minProductTruth, truthLabelDescription, } from "./product/index.js";
48
+ export { rolePrompt, roleAllowedTools, runRoleAgent } from "./agent/roles.js";