@oscharko-dev/keiko-server 0.2.7 → 0.2.9

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 (302) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/chat-handlers.d.ts +18 -2
  3. package/dist/chat-handlers.d.ts.map +1 -1
  4. package/dist/chat-handlers.js +185 -3
  5. package/dist/command-runner-errors.d.ts +17 -0
  6. package/dist/command-runner-errors.d.ts.map +1 -0
  7. package/dist/command-runner-errors.js +37 -0
  8. package/dist/command-runner-evidence.d.ts +23 -0
  9. package/dist/command-runner-evidence.d.ts.map +1 -0
  10. package/dist/command-runner-evidence.js +69 -0
  11. package/dist/command-runner-routes.d.ts +7 -0
  12. package/dist/command-runner-routes.d.ts.map +1 -0
  13. package/dist/command-runner-routes.js +175 -0
  14. package/dist/command-runner.d.ts +29 -0
  15. package/dist/command-runner.d.ts.map +1 -0
  16. package/dist/command-runner.js +348 -0
  17. package/dist/conversation-prompt.d.ts +2 -2
  18. package/dist/conversation-prompt.d.ts.map +1 -1
  19. package/dist/conversation-prompt.js +17 -1
  20. package/dist/csp.d.ts.map +1 -1
  21. package/dist/csp.js +3 -0
  22. package/dist/deps.d.ts +28 -1
  23. package/dist/deps.d.ts.map +1 -1
  24. package/dist/deps.js +288 -13
  25. package/dist/discussion-prompt.d.ts +4 -0
  26. package/dist/discussion-prompt.d.ts.map +1 -0
  27. package/dist/discussion-prompt.js +19 -0
  28. package/dist/editor/agentActionAudit.d.ts +18 -0
  29. package/dist/editor/agentActionAudit.d.ts.map +1 -0
  30. package/dist/editor/agentActionAudit.js +80 -0
  31. package/dist/editor/agentRoutes.d.ts +1 -0
  32. package/dist/editor/agentRoutes.d.ts.map +1 -1
  33. package/dist/editor/agentRoutes.js +292 -55
  34. package/dist/editor/agentSessionRegistry.d.ts +35 -0
  35. package/dist/editor/agentSessionRegistry.d.ts.map +1 -0
  36. package/dist/editor/agentSessionRegistry.js +243 -0
  37. package/dist/editor/completionRoutes.d.ts.map +1 -1
  38. package/dist/editor/completionRoutes.js +5 -10
  39. package/dist/editor/languageRoutes.d.ts +12 -1
  40. package/dist/editor/languageRoutes.d.ts.map +1 -1
  41. package/dist/editor/languageRoutes.js +71 -8
  42. package/dist/editor/languageService.d.ts +3 -2
  43. package/dist/editor/languageService.d.ts.map +1 -1
  44. package/dist/editor/languageService.js +41 -3
  45. package/dist/editor/languageServiceHost.d.ts.map +1 -1
  46. package/dist/editor/languageServiceHost.js +2 -2
  47. package/dist/editor/lsp/hostLanguageOperation.d.ts +17 -0
  48. package/dist/editor/lsp/hostLanguageOperation.d.ts.map +1 -0
  49. package/dist/editor/lsp/hostLanguageOperation.js +436 -0
  50. package/dist/editor/lsp/hostLanguageProviders.d.ts +26 -0
  51. package/dist/editor/lsp/hostLanguageProviders.d.ts.map +1 -0
  52. package/dist/editor/lsp/hostLanguageProviders.js +161 -0
  53. package/dist/editor/lsp/lspFrameCodec.d.ts +13 -0
  54. package/dist/editor/lsp/lspFrameCodec.d.ts.map +1 -0
  55. package/dist/editor/lsp/lspFrameCodec.js +164 -0
  56. package/dist/editor/lsp/lspJsonRpcClient.d.ts +34 -0
  57. package/dist/editor/lsp/lspJsonRpcClient.d.ts.map +1 -0
  58. package/dist/editor/lsp/lspJsonRpcClient.js +173 -0
  59. package/dist/editor/lsp/lspLanguageProvider.d.ts +7 -0
  60. package/dist/editor/lsp/lspLanguageProvider.d.ts.map +1 -0
  61. package/dist/editor/lsp/lspLanguageProvider.js +29 -0
  62. package/dist/editor/lsp/lspLifecycleLedger.d.ts +5 -0
  63. package/dist/editor/lsp/lspLifecycleLedger.d.ts.map +1 -0
  64. package/dist/editor/lsp/lspLifecycleLedger.js +37 -0
  65. package/dist/editor/lsp/lspNodeAdapter.d.ts +31 -0
  66. package/dist/editor/lsp/lspNodeAdapter.d.ts.map +1 -0
  67. package/dist/editor/lsp/lspNodeAdapter.js +230 -0
  68. package/dist/editor/lsp/lspProcessManager.d.ts +24 -0
  69. package/dist/editor/lsp/lspProcessManager.d.ts.map +1 -0
  70. package/dist/editor/lsp/lspProcessManager.js +255 -0
  71. package/dist/editor/lsp/lspRestartThrottle.d.ts +6 -0
  72. package/dist/editor/lsp/lspRestartThrottle.d.ts.map +1 -0
  73. package/dist/editor/lsp/lspRestartThrottle.js +24 -0
  74. package/dist/editor/lsp/lspStatusRoute.d.ts +8 -0
  75. package/dist/editor/lsp/lspStatusRoute.d.ts.map +1 -0
  76. package/dist/editor/lsp/lspStatusRoute.js +22 -0
  77. package/dist/editor/lsp/lspTransport.d.ts +19 -0
  78. package/dist/editor/lsp/lspTransport.d.ts.map +1 -0
  79. package/dist/editor/lsp/lspTransport.js +55 -0
  80. package/dist/editor/lsp/testing/fakeLspProcess.d.ts +23 -0
  81. package/dist/editor/lsp/testing/fakeLspProcess.d.ts.map +1 -0
  82. package/dist/editor/lsp/testing/fakeLspProcess.js +132 -0
  83. package/dist/files.d.ts +63 -0
  84. package/dist/files.d.ts.map +1 -1
  85. package/dist/files.js +799 -1
  86. package/dist/gateway-readiness.d.ts +6 -0
  87. package/dist/gateway-readiness.d.ts.map +1 -0
  88. package/dist/gateway-readiness.js +624 -0
  89. package/dist/gateway-setup.d.ts +2 -0
  90. package/dist/gateway-setup.d.ts.map +1 -1
  91. package/dist/gateway-setup.js +275 -11
  92. package/dist/gitDelivery/actionSheetProjection.d.ts +30 -0
  93. package/dist/gitDelivery/actionSheetProjection.d.ts.map +1 -0
  94. package/dist/gitDelivery/actionSheetProjection.js +206 -0
  95. package/dist/gitDelivery/actionSheetRoutes.d.ts +29 -0
  96. package/dist/gitDelivery/actionSheetRoutes.d.ts.map +1 -0
  97. package/dist/gitDelivery/actionSheetRoutes.js +293 -0
  98. package/dist/gitDelivery/agentOperationsRoutes.d.ts +33 -0
  99. package/dist/gitDelivery/agentOperationsRoutes.d.ts.map +1 -0
  100. package/dist/gitDelivery/agentOperationsRoutes.js +405 -0
  101. package/dist/gitDelivery/commitRoutes.d.ts +23 -0
  102. package/dist/gitDelivery/commitRoutes.d.ts.map +1 -0
  103. package/dist/gitDelivery/commitRoutes.js +204 -0
  104. package/dist/gitDelivery/evidenceRoutes.d.ts +9 -0
  105. package/dist/gitDelivery/evidenceRoutes.d.ts.map +1 -0
  106. package/dist/gitDelivery/evidenceRoutes.js +101 -0
  107. package/dist/gitDelivery/execution.d.ts +38 -0
  108. package/dist/gitDelivery/execution.d.ts.map +1 -0
  109. package/dist/gitDelivery/execution.js +117 -0
  110. package/dist/gitDelivery/localMutationRoutes.d.ts +30 -0
  111. package/dist/gitDelivery/localMutationRoutes.d.ts.map +1 -0
  112. package/dist/gitDelivery/localMutationRoutes.js +165 -0
  113. package/dist/gitDelivery/mergeExecution.d.ts +63 -0
  114. package/dist/gitDelivery/mergeExecution.d.ts.map +1 -0
  115. package/dist/gitDelivery/mergeExecution.js +168 -0
  116. package/dist/gitDelivery/mergeRoutes.d.ts +12 -0
  117. package/dist/gitDelivery/mergeRoutes.d.ts.map +1 -0
  118. package/dist/gitDelivery/mergeRoutes.js +218 -0
  119. package/dist/gitDelivery/mutationEvidenceLedger.d.ts +23 -0
  120. package/dist/gitDelivery/mutationEvidenceLedger.d.ts.map +1 -0
  121. package/dist/gitDelivery/mutationEvidenceLedger.js +87 -0
  122. package/dist/gitDelivery/prExecution.d.ts +54 -0
  123. package/dist/gitDelivery/prExecution.d.ts.map +1 -0
  124. package/dist/gitDelivery/prExecution.js +192 -0
  125. package/dist/gitDelivery/prRoutes.d.ts +12 -0
  126. package/dist/gitDelivery/prRoutes.d.ts.map +1 -0
  127. package/dist/gitDelivery/prRoutes.js +256 -0
  128. package/dist/gitDelivery/pushExecution.d.ts +43 -0
  129. package/dist/gitDelivery/pushExecution.d.ts.map +1 -0
  130. package/dist/gitDelivery/pushExecution.js +124 -0
  131. package/dist/gitDelivery/pushRoutes.d.ts +12 -0
  132. package/dist/gitDelivery/pushRoutes.d.ts.map +1 -0
  133. package/dist/gitDelivery/pushRoutes.js +200 -0
  134. package/dist/gitDelivery/requestGuards.d.ts +15 -0
  135. package/dist/gitDelivery/requestGuards.d.ts.map +1 -0
  136. package/dist/gitDelivery/requestGuards.js +97 -0
  137. package/dist/gitDelivery/syncEvidence.d.ts +37 -0
  138. package/dist/gitDelivery/syncEvidence.d.ts.map +1 -0
  139. package/dist/gitDelivery/syncEvidence.js +85 -0
  140. package/dist/gitDelivery/syncExecution.d.ts +30 -0
  141. package/dist/gitDelivery/syncExecution.d.ts.map +1 -0
  142. package/dist/gitDelivery/syncExecution.js +266 -0
  143. package/dist/gitDelivery/syncRoutes.d.ts +13 -0
  144. package/dist/gitDelivery/syncRoutes.d.ts.map +1 -0
  145. package/dist/gitDelivery/syncRoutes.js +200 -0
  146. package/dist/gitPorcelainStatus.d.ts +15 -0
  147. package/dist/gitPorcelainStatus.d.ts.map +1 -0
  148. package/dist/gitPorcelainStatus.js +104 -0
  149. package/dist/gitRepositoryReads.d.ts +10 -0
  150. package/dist/gitRepositoryReads.d.ts.map +1 -0
  151. package/dist/gitRepositoryReads.js +314 -0
  152. package/dist/gitRepositoryRoutes.d.ts +7 -0
  153. package/dist/gitRepositoryRoutes.d.ts.map +1 -0
  154. package/dist/gitRepositoryRoutes.js +221 -0
  155. package/dist/gitRoutes.d.ts +66 -0
  156. package/dist/gitRoutes.d.ts.map +1 -0
  157. package/dist/gitRoutes.js +543 -0
  158. package/dist/governed-workflow.d.ts +2 -0
  159. package/dist/governed-workflow.d.ts.map +1 -1
  160. package/dist/governed-workflow.js +4 -0
  161. package/dist/grounded-qa-hybrid.d.ts.map +1 -1
  162. package/dist/grounded-qa-hybrid.js +2 -0
  163. package/dist/grounded-qa-multi-source.d.ts.map +1 -1
  164. package/dist/grounded-qa-multi-source.js +1 -0
  165. package/dist/grounded-qa.d.ts +11 -0
  166. package/dist/grounded-qa.d.ts.map +1 -1
  167. package/dist/grounded-qa.js +14 -4
  168. package/dist/headers.d.ts +4 -1
  169. package/dist/headers.d.ts.map +1 -1
  170. package/dist/headers.js +11 -4
  171. package/dist/index.d.ts +8 -1
  172. package/dist/index.d.ts.map +1 -1
  173. package/dist/index.js +9 -1
  174. package/dist/local-knowledge-grounded-qa.d.ts.map +1 -1
  175. package/dist/local-knowledge-grounded-qa.js +11 -2
  176. package/dist/qualityIntelligence/figmaSnapshotRoutes.d.ts +1 -1
  177. package/dist/qualityIntelligence/figmaSnapshotRoutes.d.ts.map +1 -1
  178. package/dist/qualityIntelligence/figmaSnapshotRoutes.js +1 -1
  179. package/dist/read-handlers.d.ts +5 -0
  180. package/dist/read-handlers.d.ts.map +1 -1
  181. package/dist/read-handlers.js +57 -1
  182. package/dist/routes.d.ts.map +1 -1
  183. package/dist/routes.js +260 -12
  184. package/dist/run-engine.d.ts.map +1 -1
  185. package/dist/run-engine.js +3 -0
  186. package/dist/run-handlers.d.ts +0 -1
  187. package/dist/run-handlers.d.ts.map +1 -1
  188. package/dist/run-handlers.js +64 -211
  189. package/dist/run-request.d.ts +11 -0
  190. package/dist/run-request.d.ts.map +1 -1
  191. package/dist/run-request.js +158 -10
  192. package/dist/runtime/capabilityDetector.d.ts +38 -0
  193. package/dist/runtime/capabilityDetector.d.ts.map +1 -0
  194. package/dist/runtime/capabilityDetector.js +443 -0
  195. package/dist/runtime/capabilityRoutes.d.ts +9 -0
  196. package/dist/runtime/capabilityRoutes.d.ts.map +1 -0
  197. package/dist/runtime/capabilityRoutes.js +45 -0
  198. package/dist/runtime/containerEngineDetector.d.ts +17 -0
  199. package/dist/runtime/containerEngineDetector.d.ts.map +1 -0
  200. package/dist/runtime/containerEngineDetector.js +222 -0
  201. package/dist/runtime/containerRoutes.d.ts +8 -0
  202. package/dist/runtime/containerRoutes.d.ts.map +1 -0
  203. package/dist/runtime/containerRoutes.js +207 -0
  204. package/dist/runtime/containerRunner-errors.d.ts +18 -0
  205. package/dist/runtime/containerRunner-errors.d.ts.map +1 -0
  206. package/dist/runtime/containerRunner-errors.js +42 -0
  207. package/dist/runtime/containerRunner-evidence.d.ts +24 -0
  208. package/dist/runtime/containerRunner-evidence.d.ts.map +1 -0
  209. package/dist/runtime/containerRunner-evidence.js +74 -0
  210. package/dist/runtime/containerRunner.d.ts +37 -0
  211. package/dist/runtime/containerRunner.d.ts.map +1 -0
  212. package/dist/runtime/containerRunner.js +443 -0
  213. package/dist/server.d.ts.map +1 -1
  214. package/dist/server.js +24 -4
  215. package/dist/store/db.d.ts.map +1 -1
  216. package/dist/store/db.js +2 -1
  217. package/dist/store/index.d.ts +1 -1
  218. package/dist/store/index.d.ts.map +1 -1
  219. package/dist/store/messages.d.ts +2 -1
  220. package/dist/store/messages.d.ts.map +1 -1
  221. package/dist/store/messages.js +46 -4
  222. package/dist/store/schema.d.ts +1 -1
  223. package/dist/store/schema.d.ts.map +1 -1
  224. package/dist/store/schema.js +68 -1
  225. package/dist/store/types.d.ts +3 -2
  226. package/dist/store/types.d.ts.map +1 -1
  227. package/dist/task-workspace/active-store.d.ts +21 -0
  228. package/dist/task-workspace/active-store.d.ts.map +1 -0
  229. package/dist/task-workspace/active-store.js +55 -0
  230. package/dist/task-workspace/authorization.d.ts +7 -0
  231. package/dist/task-workspace/authorization.d.ts.map +1 -0
  232. package/dist/task-workspace/authorization.js +54 -0
  233. package/dist/task-workspace/binding.d.ts +3 -0
  234. package/dist/task-workspace/binding.d.ts.map +1 -0
  235. package/dist/task-workspace/binding.js +22 -0
  236. package/dist/task-workspace/cleanup.d.ts +4 -0
  237. package/dist/task-workspace/cleanup.d.ts.map +1 -0
  238. package/dist/task-workspace/cleanup.js +428 -0
  239. package/dist/task-workspace/errors.d.ts +14 -0
  240. package/dist/task-workspace/errors.d.ts.map +1 -0
  241. package/dist/task-workspace/errors.js +81 -0
  242. package/dist/task-workspace/evidence.d.ts +32 -0
  243. package/dist/task-workspace/evidence.d.ts.map +1 -0
  244. package/dist/task-workspace/evidence.js +52 -0
  245. package/dist/task-workspace/field-safety.d.ts +3 -0
  246. package/dist/task-workspace/field-safety.d.ts.map +1 -0
  247. package/dist/task-workspace/field-safety.js +42 -0
  248. package/dist/task-workspace/health.d.ts +4 -0
  249. package/dist/task-workspace/health.d.ts.map +1 -0
  250. package/dist/task-workspace/health.js +163 -0
  251. package/dist/task-workspace/lifecycle.d.ts +3 -0
  252. package/dist/task-workspace/lifecycle.d.ts.map +1 -0
  253. package/dist/task-workspace/lifecycle.js +248 -0
  254. package/dist/task-workspace/locks.d.ts +13 -0
  255. package/dist/task-workspace/locks.d.ts.map +1 -0
  256. package/dist/task-workspace/locks.js +44 -0
  257. package/dist/task-workspace/managed-root.d.ts +7 -0
  258. package/dist/task-workspace/managed-root.d.ts.map +1 -0
  259. package/dist/task-workspace/managed-root.js +98 -0
  260. package/dist/task-workspace/mutex.d.ts +8 -0
  261. package/dist/task-workspace/mutex.d.ts.map +1 -0
  262. package/dist/task-workspace/mutex.js +82 -0
  263. package/dist/task-workspace/naming.d.ts +15 -0
  264. package/dist/task-workspace/naming.d.ts.map +1 -0
  265. package/dist/task-workspace/naming.js +0 -0
  266. package/dist/task-workspace/provisioning.d.ts +3 -0
  267. package/dist/task-workspace/provisioning.d.ts.map +1 -0
  268. package/dist/task-workspace/provisioning.js +528 -0
  269. package/dist/task-workspace/reconciliation.d.ts +15 -0
  270. package/dist/task-workspace/reconciliation.d.ts.map +1 -0
  271. package/dist/task-workspace/reconciliation.js +274 -0
  272. package/dist/task-workspace/repair.d.ts +3 -0
  273. package/dist/task-workspace/repair.d.ts.map +1 -0
  274. package/dist/task-workspace/repair.js +286 -0
  275. package/dist/task-workspace/routes.d.ts +19 -0
  276. package/dist/task-workspace/routes.d.ts.map +1 -0
  277. package/dist/task-workspace/routes.js +481 -0
  278. package/dist/task-workspace/store.d.ts +12 -0
  279. package/dist/task-workspace/store.d.ts.map +1 -0
  280. package/dist/task-workspace/store.js +128 -0
  281. package/dist/task-workspace/types.d.ts +170 -0
  282. package/dist/task-workspace/types.d.ts.map +1 -0
  283. package/dist/task-workspace/types.js +5 -0
  284. package/dist/voice-action-governance.d.ts +23 -0
  285. package/dist/voice-action-governance.d.ts.map +1 -0
  286. package/dist/voice-action-governance.js +126 -0
  287. package/dist/voice-handlers.d.ts +6 -0
  288. package/dist/voice-handlers.d.ts.map +1 -0
  289. package/dist/voice-handlers.js +570 -0
  290. package/dist/voice-realtime-grounded-tool.d.ts +31 -0
  291. package/dist/voice-realtime-grounded-tool.d.ts.map +1 -0
  292. package/dist/voice-realtime-grounded-tool.js +322 -0
  293. package/dist/voice-realtime.d.ts +69 -0
  294. package/dist/voice-realtime.d.ts.map +1 -0
  295. package/dist/voice-realtime.js +787 -0
  296. package/dist/workspace-state-handlers.d.ts +5 -0
  297. package/dist/workspace-state-handlers.d.ts.map +1 -0
  298. package/dist/workspace-state-handlers.js +106 -0
  299. package/package.json +20 -19
  300. package/dist/grounded-handoff.d.ts +0 -4
  301. package/dist/grounded-handoff.d.ts.map +0 -1
  302. package/dist/grounded-handoff.js +0 -445
package/dist/deps.js CHANGED
@@ -20,12 +20,25 @@ import { dirname, join } from "node:path";
20
20
  import { createRunRegistry } from "./runs.js";
21
21
  import { assertUiDbOutsideProject, buildUiStoreOverDatabase, openNodeUiDatabase, resolveUiDbPath, validateProjectPath, } from "./store/index.js";
22
22
  import { createTerminalExecutionManager } from "./terminal.js";
23
+ import { createCommandRunnerManager } from "./command-runner.js";
24
+ import { createContainerRunnerManager, } from "./runtime/containerRunner.js";
23
25
  import { createBrowserSessionManager } from "@oscharko-dev/keiko-tools";
24
26
  import {} from "@oscharko-dev/keiko-memory-vault";
25
27
  import { createBffMemoryVault } from "./memory-handlers.js";
26
28
  import { createMemoryAuditHandler } from "./memory-audit-handler.js";
27
29
  import { createConsolidationJobRegistry, } from "./memory-consolidation-registry.js";
28
30
  import { createRelationshipStorePort, } from "./relationship-handlers.js";
31
+ import { createNodeGitWorktreeAdapter } from "@oscharko-dev/keiko-tools/internal/git-mutation";
32
+ import { buildWorkspaceInstanceStoreOverDatabase, } from "./task-workspace/store.js";
33
+ import { buildActiveWorkspacePointerStoreOverDatabase, } from "./task-workspace/active-store.js";
34
+ import { createWorkspaceProvisioningService } from "./task-workspace/provisioning.js";
35
+ import { createWorkspaceLifecycleService } from "./task-workspace/lifecycle.js";
36
+ import { createWorkspaceMutexRegistry, } from "./task-workspace/mutex.js";
37
+ import { createWorkspaceReconciliationService } from "./task-workspace/reconciliation.js";
38
+ import { createWorkspaceRepairService } from "./task-workspace/repair.js";
39
+ import { createWorkspaceHealthService } from "./task-workspace/health.js";
40
+ import { createWorkspaceCleanupService } from "./task-workspace/cleanup.js";
41
+ import { randomUUID } from "node:crypto";
29
42
  import { resolveGroundingLimits, } from "@oscharko-dev/keiko-contracts/bff-wire";
30
43
  import { createProviderSecretResolver } from "./credentialVault.js";
31
44
  import { createLocalKnowledgeKeyProvider } from "./localKnowledgeKeyProvider.js";
@@ -310,6 +323,34 @@ function buildTerminalManager(options) {
310
323
  },
311
324
  });
312
325
  }
326
+ // Issue #1387 — the command runner reuses the same store + evidence + live-redactor wiring as the
327
+ // terminal manager so discovered test/build/run tasks inherit the identical workspace containment,
328
+ // secret-shape scrubbing, and content-free audit trail.
329
+ function buildCommandRunner(options) {
330
+ return createCommandRunnerManager({
331
+ store: options.store,
332
+ evidenceStore: options.evidenceStore,
333
+ processEnv: options.env,
334
+ redactor: (value) => {
335
+ const redacted = options.liveRedactor(value);
336
+ return typeof redacted === "string" ? redacted : value;
337
+ },
338
+ });
339
+ }
340
+ // Issue #1388 — the container runner reuses the same store + evidence + live-redactor wiring as the
341
+ // command runner so its content-free run audit inherits the identical secret-shape scrubbing. The
342
+ // active engine probe and the frozen-argv container run both compose the single runCommand boundary.
343
+ function buildContainerRunner(options) {
344
+ return createContainerRunnerManager({
345
+ store: options.store,
346
+ evidenceStore: options.evidenceStore,
347
+ processEnv: options.env,
348
+ redactor: (value) => {
349
+ const redacted = options.liveRedactor(value);
350
+ return typeof redacted === "string" ? redacted : value;
351
+ },
352
+ });
353
+ }
313
354
  // ADR-0019 direction rule 3c: the tools package cannot import src/audit. The BFF injects the
314
355
  // cost-class resolver and a side-file writer that closes over the resolved evidenceDir + the
315
356
  // nodeWorkspaceFs realpath-containment port, so the browser session manager stays self-contained
@@ -342,13 +383,15 @@ function resolveLoopbackWorkspaceId(env) {
342
383
  return explicit;
343
384
  return DEFAULT_LOOPBACK_WORKSPACE_ID;
344
385
  }
345
- // When no UiStore is injected, open one DatabaseSync against the resolved UI-DB and share it
346
- // with the relationship-engine store so V5 sibling tables share the UI-store transaction model
347
- // (issue #539, storage.md §3.1). When tests inject a UiStore we leave `relationship` undefined;
348
- // relationship-engine tests inject their own deps.
349
386
  function composePersistence(injected, resolvedUiDbPath, redactString, env) {
350
- if (injected !== undefined)
351
- return { store: injected, relationship: undefined };
387
+ if (injected !== undefined) {
388
+ return {
389
+ store: injected,
390
+ relationship: undefined,
391
+ workspaceInstanceStore: undefined,
392
+ activeWorkspacePointerStore: undefined,
393
+ };
394
+ }
352
395
  const db = openNodeUiDatabase(resolvedUiDbPath);
353
396
  const store = buildUiStoreOverDatabase(db, { redactString });
354
397
  const relationship = {
@@ -357,7 +400,151 @@ function composePersistence(injected, resolvedUiDbPath, redactString, env) {
357
400
  }),
358
401
  store: createRelationshipStorePort({ db, redactString }),
359
402
  };
360
- return { store, relationship };
403
+ return {
404
+ store,
405
+ relationship,
406
+ workspaceInstanceStore: buildWorkspaceInstanceStoreOverDatabase(db),
407
+ activeWorkspacePointerStore: buildActiveWorkspacePointerStoreOverDatabase(db),
408
+ };
409
+ }
410
+ // The Keiko-owned managed task-workspace root lives alongside the UI database (`<uiDbDir>/
411
+ // task-workspaces`), so it inherits the same per-user data directory and 0o700 hardening posture.
412
+ function resolveManagedWorktreeRoot(uiDbPath) {
413
+ return join(dirname(uiDbPath), "task-workspaces");
414
+ }
415
+ function buildWorkspaceProvisioning(options, store, resolvedUiDbPath, evidenceStore, redactString, mutex) {
416
+ if (options.workspaceProvisioning !== undefined)
417
+ return options.workspaceProvisioning;
418
+ if (store === undefined)
419
+ return undefined;
420
+ return createWorkspaceProvisioningService({
421
+ store,
422
+ evidenceStore,
423
+ managedRoot: resolveManagedWorktreeRoot(resolvedUiDbPath),
424
+ createAdapter: (workspace) => createNodeGitWorktreeAdapter({ workspace, processEnv: options.env }),
425
+ redactString,
426
+ now: () => Date.now(),
427
+ newId: randomUUID,
428
+ mutex,
429
+ });
430
+ }
431
+ // Issue #446 — the active-binding lifecycle service. It composes the SAME #445 instance store,
432
+ // provisioning service, evidence store, and active-pointer store (no second worktree/lock/transition
433
+ // engine). Returns undefined whenever any composed dependency is absent (injected UiStore tests), so
434
+ // the active-binding routes degrade to 503 exactly like the provisioning routes.
435
+ function buildWorkspaceLifecycle(options, instanceStore, activePointerStore, provisioning, resolvedUiDbPath, evidenceStore, redactString, mutex) {
436
+ if (options.workspaceLifecycle !== undefined)
437
+ return options.workspaceLifecycle;
438
+ if (instanceStore === undefined ||
439
+ activePointerStore === undefined ||
440
+ provisioning === undefined) {
441
+ return undefined;
442
+ }
443
+ return createWorkspaceLifecycleService({
444
+ store: instanceStore,
445
+ activePointerStore,
446
+ managedRoot: resolveManagedWorktreeRoot(resolvedUiDbPath),
447
+ provisioning,
448
+ evidenceStore,
449
+ redactString,
450
+ now: () => Date.now(),
451
+ newId: randomUUID,
452
+ mutex,
453
+ });
454
+ }
455
+ // Issue #447 — the startup reconciliation service. It composes the SAME #445 instance store, #446
456
+ // active pointer, evidence store, managed root, and node worktree adapter (no second engine). Returns
457
+ // undefined whenever a composed dependency is absent (injected UiStore tests) so the reconciliation
458
+ // routes degrade to 503 exactly like the provisioning routes.
459
+ function buildWorkspaceReconciliation(options, instanceStore, activePointerStore, resolvedUiDbPath, evidenceStore, redactString) {
460
+ if (options.workspaceReconciliation !== undefined)
461
+ return options.workspaceReconciliation;
462
+ if (instanceStore === undefined || activePointerStore === undefined)
463
+ return undefined;
464
+ return createWorkspaceReconciliationService({
465
+ store: instanceStore,
466
+ activePointerStore,
467
+ evidenceStore,
468
+ managedRoot: resolveManagedWorktreeRoot(resolvedUiDbPath),
469
+ createAdapter: (workspace) => createNodeGitWorktreeAdapter({ workspace, processEnv: options.env }),
470
+ redactString,
471
+ now: () => Date.now(),
472
+ newId: randomUUID,
473
+ });
474
+ }
475
+ // Issue #447 — the controlled repair service. It reuses the #445 provisioning service for the
476
+ // worktree-recreating strategies and the same store/pointer/adapter for the rest (no second engine).
477
+ function buildWorkspaceRepair(options, instanceStore, activePointerStore, provisioning, resolvedUiDbPath, evidenceStore, redactString, mutex) {
478
+ if (options.workspaceRepair !== undefined)
479
+ return options.workspaceRepair;
480
+ if (instanceStore === undefined ||
481
+ activePointerStore === undefined ||
482
+ provisioning === undefined) {
483
+ return undefined;
484
+ }
485
+ return createWorkspaceRepairService({
486
+ store: instanceStore,
487
+ activePointerStore,
488
+ evidenceStore,
489
+ provisioning,
490
+ managedRoot: resolveManagedWorktreeRoot(resolvedUiDbPath),
491
+ createAdapter: (workspace) => createNodeGitWorktreeAdapter({ workspace, processEnv: options.env }),
492
+ redactString,
493
+ now: () => Date.now(),
494
+ newId: randomUUID,
495
+ mutex,
496
+ });
497
+ }
498
+ // Issue #448 — the read-only health/drift/orphan report service and the governed cleanup service. Both
499
+ // reuse the SAME #445 instance store, #446 active pointer, evidence store, managed root, and node
500
+ // worktree adapter (no second engine). Return undefined whenever a composed dependency is absent so the
501
+ // health/cleanup routes degrade to 503 exactly like the provisioning routes.
502
+ function buildWorkspaceHealth(options, instanceStore, activePointerStore, resolvedUiDbPath, evidenceStore, redactString) {
503
+ if (options.workspaceHealth !== undefined)
504
+ return options.workspaceHealth;
505
+ if (instanceStore === undefined || activePointerStore === undefined)
506
+ return undefined;
507
+ return createWorkspaceHealthService({
508
+ store: instanceStore,
509
+ activePointerStore,
510
+ evidenceStore,
511
+ managedRoot: resolveManagedWorktreeRoot(resolvedUiDbPath),
512
+ createAdapter: (workspace) => createNodeGitWorktreeAdapter({ workspace, processEnv: options.env }),
513
+ redactString,
514
+ now: () => Date.now(),
515
+ newId: randomUUID,
516
+ });
517
+ }
518
+ function buildWorkspaceCleanup(options, instanceStore, activePointerStore, resolvedUiDbPath, evidenceStore, redactString, mutex) {
519
+ if (options.workspaceCleanup !== undefined)
520
+ return options.workspaceCleanup;
521
+ if (instanceStore === undefined || activePointerStore === undefined)
522
+ return undefined;
523
+ return createWorkspaceCleanupService({
524
+ store: instanceStore,
525
+ activePointerStore,
526
+ evidenceStore,
527
+ managedRoot: resolveManagedWorktreeRoot(resolvedUiDbPath),
528
+ createAdapter: (workspace) => createNodeGitWorktreeAdapter({ workspace, processEnv: options.env }),
529
+ redactString,
530
+ now: () => Date.now(),
531
+ newId: randomUUID,
532
+ mutex,
533
+ });
534
+ }
535
+ // Best-effort startup reconciliation (Issue #447): mirror the QI-retention startup pass — run once at
536
+ // bootstrap, never throw into construction, and never block server start (the reconcile IO is detached
537
+ // and self-contained). A failure simply leaves the persisted classification untouched until the next
538
+ // pass or an explicit refresh.
539
+ function reconcileTaskWorkspacesAtStartup(service) {
540
+ if (service === undefined)
541
+ return;
542
+ try {
543
+ void service.reconcile().catch(() => undefined);
544
+ }
545
+ catch {
546
+ // construction must never fail because of reconciliation.
547
+ }
361
548
  }
362
549
  function seedInitialProject(store, uiDbPath, initialProjectPath) {
363
550
  if (initialProjectPath === undefined || initialProjectPath.trim().length === 0) {
@@ -375,6 +562,18 @@ function buildPeripherals(options, uiStore, evidenceStore, redactString, liveRed
375
562
  env: options.env,
376
563
  liveRedactor,
377
564
  }),
565
+ commandRunner: buildCommandRunner({
566
+ store: uiStore,
567
+ evidenceStore,
568
+ env: options.env,
569
+ liveRedactor,
570
+ }),
571
+ containerRunner: buildContainerRunner({
572
+ store: uiStore,
573
+ evidenceStore,
574
+ env: options.env,
575
+ liveRedactor,
576
+ }),
378
577
  browser: buildBrowserManager({
379
578
  evidenceDir: resolveEvidenceDir(options.evidenceDir, options.env),
380
579
  evidenceStore,
@@ -419,6 +618,79 @@ function resolveEvidenceDirAndEnforceRetention(options) {
419
618
  });
420
619
  return evidenceDir;
421
620
  }
621
+ // Issue #448 — the health + cleanup pair, split out to keep composeTaskWorkspaceServices small.
622
+ function composeHealthAndCleanup(options, workspaceInstanceStore, activeWorkspacePointerStore, resolvedUiDbPath, evidenceStore, redactString, mutex) {
623
+ return {
624
+ workspaceHealth: buildWorkspaceHealth(options, workspaceInstanceStore, activeWorkspacePointerStore, resolvedUiDbPath, evidenceStore, redactString),
625
+ workspaceCleanup: buildWorkspaceCleanup(options, workspaceInstanceStore, activeWorkspacePointerStore, resolvedUiDbPath, evidenceStore, redactString, mutex),
626
+ };
627
+ }
628
+ // Issue #445/#446/#447 — provisioning + active-binding lifecycle + reconciliation + repair.
629
+ function composeCoreTaskWorkspaceServices(options, workspaceInstanceStore, activeWorkspacePointerStore, resolvedUiDbPath, evidenceStore, redactString, mutex) {
630
+ const workspaceProvisioning = buildWorkspaceProvisioning(options, workspaceInstanceStore, resolvedUiDbPath, evidenceStore, redactString, mutex);
631
+ return {
632
+ workspaceProvisioning,
633
+ workspaceLifecycle: buildWorkspaceLifecycle(options, workspaceInstanceStore, activeWorkspacePointerStore, workspaceProvisioning, resolvedUiDbPath, evidenceStore, redactString, mutex),
634
+ workspaceReconciliation: buildWorkspaceReconciliation(options, workspaceInstanceStore, activeWorkspacePointerStore, resolvedUiDbPath, evidenceStore, redactString),
635
+ workspaceRepair: buildWorkspaceRepair(options, workspaceInstanceStore, activeWorkspacePointerStore, workspaceProvisioning, resolvedUiDbPath, evidenceStore, redactString, mutex),
636
+ };
637
+ }
638
+ function composeTaskWorkspaceServices(options, workspaceInstanceStore, activeWorkspacePointerStore, resolvedUiDbPath, evidenceStore, redactString) {
639
+ // One shared in-process mutex registry across ALL mutating task-workspace services (#449, ADR-0093 D1):
640
+ // provisioning, lifecycle, repair, and cleanup must serialize against each other on the same `ws:`
641
+ // keyspace, so they receive the SAME registry instance. Read-only services (reconciliation, health) do
642
+ // not take it.
643
+ const mutex = createWorkspaceMutexRegistry();
644
+ const args = [
645
+ options,
646
+ workspaceInstanceStore,
647
+ activeWorkspacePointerStore,
648
+ resolvedUiDbPath,
649
+ evidenceStore,
650
+ redactString,
651
+ mutex,
652
+ ];
653
+ return {
654
+ ...composeCoreTaskWorkspaceServices(...args),
655
+ ...composeHealthAndCleanup(...args),
656
+ };
657
+ }
658
+ function buildPersistenceBundle(options, resolvedUiDbPath, redactString, evidenceStore) {
659
+ const { store, relationship, workspaceInstanceStore, activeWorkspacePointerStore } = composePersistence(options.store, resolvedUiDbPath, redactString, options.env);
660
+ const services = composeTaskWorkspaceServices(options, workspaceInstanceStore, activeWorkspacePointerStore, resolvedUiDbPath, evidenceStore, redactString);
661
+ return {
662
+ uiStore: store,
663
+ relationship,
664
+ ...services,
665
+ managedTaskWorkspaceRoot: services.workspaceProvisioning === undefined
666
+ ? undefined
667
+ : resolveManagedWorktreeRoot(resolvedUiDbPath),
668
+ preferredProjectPath: seedInitialProject(store, resolvedUiDbPath, options.initialProjectPath),
669
+ };
670
+ }
671
+ // The optional persistence services (relationship engine + the #445/#446/#447 task-workspace
672
+ // services) spread onto the handler deps only when they were composed (production) — absent ones leave
673
+ // the corresponding routes to degrade to 503, exactly as before.
674
+ function optionalPersistenceServices(bundle) {
675
+ return {
676
+ ...(bundle.relationship === undefined ? {} : { relationship: bundle.relationship }),
677
+ ...(bundle.workspaceProvisioning === undefined
678
+ ? {}
679
+ : { workspaceProvisioning: bundle.workspaceProvisioning }),
680
+ ...(bundle.managedTaskWorkspaceRoot === undefined
681
+ ? {}
682
+ : { managedTaskWorkspaceRoot: bundle.managedTaskWorkspaceRoot }),
683
+ ...(bundle.workspaceLifecycle === undefined
684
+ ? {}
685
+ : { workspaceLifecycle: bundle.workspaceLifecycle }),
686
+ ...(bundle.workspaceReconciliation === undefined
687
+ ? {}
688
+ : { workspaceReconciliation: bundle.workspaceReconciliation }),
689
+ ...(bundle.workspaceRepair === undefined ? {} : { workspaceRepair: bundle.workspaceRepair }),
690
+ ...(bundle.workspaceHealth === undefined ? {} : { workspaceHealth: bundle.workspaceHealth }),
691
+ ...(bundle.workspaceCleanup === undefined ? {} : { workspaceCleanup: bundle.workspaceCleanup }),
692
+ };
693
+ }
422
694
  export function buildUiHandlerDeps(options) {
423
695
  const resolvedUiDbPath = resolveUiDbPath(options.uiDbPath, options.env);
424
696
  const runtimeConfigPath = localGatewayConfigPath(resolvedUiDbPath);
@@ -429,8 +701,11 @@ export function buildUiHandlerDeps(options) {
429
701
  const evidenceStore = createNodeEvidenceStore(resolvedEvidenceDir);
430
702
  const redactString = runtimeRedactString(options.env, runtimeConfig, egress);
431
703
  const liveRedactor = (value) => deepRedactStrings(value, redactString);
432
- const { store: uiStore, relationship } = composePersistence(options.store, resolvedUiDbPath, redactString, options.env);
433
- const preferredProjectPath = seedInitialProject(uiStore, resolvedUiDbPath, options.initialProjectPath);
704
+ const bundle = buildPersistenceBundle(options, resolvedUiDbPath, redactString, evidenceStore);
705
+ // Issue #447: run a best-effort startup reconciliation only on the real bootstrap path (no injected
706
+ // store), so test fixtures stay deterministic and trigger reconcile() explicitly when they need it.
707
+ if (options.store === undefined)
708
+ reconcileTaskWorkspacesAtStartup(bundle.workspaceReconciliation);
434
709
  return {
435
710
  config,
436
711
  configPresent,
@@ -442,17 +717,17 @@ export function buildUiHandlerDeps(options) {
442
717
  registry: options.registry ?? createRunRegistry(),
443
718
  modelPortFactory: options.modelPortFactory ?? defaultModelPortFactory(runtimeConfig),
444
719
  redactionSecrets: runtimeRedactionSecrets(options.env, runtimeConfig, egress),
445
- store: uiStore,
720
+ store: bundle.uiStore,
446
721
  uiDbPath: resolvedUiDbPath,
447
- preferredProjectPath,
722
+ preferredProjectPath: bundle.preferredProjectPath,
448
723
  gatewayConfig: runtimeConfig,
449
724
  gatewaySetupTester: options.gatewaySetupTester,
450
725
  gatewayModelDiscovery: options.gatewayModelDiscovery,
451
726
  figmaCredentialTester: options.figmaCredentialTester,
452
727
  localKnowledgeKeyProvider: createLocalKnowledgeKeyProvider({ env: options.env }),
453
728
  contextProfile: DEFAULT_CONTEXT_PROFILE,
454
- ...buildPeripherals(options, uiStore, evidenceStore, redactString, liveRedactor),
729
+ ...buildPeripherals(options, bundle.uiStore, evidenceStore, redactString, liveRedactor),
455
730
  consolidationJobs: createConsolidationJobRegistry(),
456
- ...(relationship === undefined ? {} : { relationship }),
731
+ ...optionalPersistenceServices(bundle),
457
732
  };
458
733
  }
@@ -0,0 +1,4 @@
1
+ import { type DiscussionMode } from "@oscharko-dev/keiko-contracts";
2
+ export declare const CONVERSATION_DISCUSSION_BLOCK_HEADER = "Discussion mode directives:";
3
+ export declare function composeDiscussionDirectiveBlock(mode: DiscussionMode): string;
4
+ //# sourceMappingURL=discussion-prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discussion-prompt.d.ts","sourceRoot":"","sources":["../src/discussion-prompt.ts"],"names":[],"mappings":"AASA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,+BAA+B,CAAC;AAIvC,eAAO,MAAM,oCAAoC,gCAAgC,CAAC;AAKlF,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAK5E"}
@@ -0,0 +1,19 @@
1
+ // Issue #502 — Pure renderer for the discussion-mode directive block (ADR-0065).
2
+ //
3
+ // When a discussion mode is selected, the model receives the mode's directives as an ADDITIVE,
4
+ // labeled prompt block. This module turns the content-free contract plan
5
+ // (`DISCUSSION_MODE_PLANS[mode].directives`) into deterministic prompt text via the fixed
6
+ // `DISCUSSION_DIRECTIVE_TEMPLATES`. It performs no IO and echoes no raw input: every line is one
7
+ // of the bounded, content-free templates the contract defines, so the block can never leak user
8
+ // or assistant text, credentials, or provider URLs.
9
+ import { DISCUSSION_DIRECTIVE_TEMPLATES, DISCUSSION_MODE_PLANS, } from "@oscharko-dev/keiko-contracts";
10
+ // Fixed label that opens the directive block. Exported so the prompt composer and the test suite
11
+ // can assert the block boundary directly (mirrors the CONVERSATION_*_BLOCK_HEADER constants).
12
+ export const CONVERSATION_DISCUSSION_BLOCK_HEADER = "Discussion mode directives:";
13
+ // Renders the selected mode's directives into a deterministic labeled block: the header line
14
+ // followed by one bulleted template line per directive, in the contract's declared directive
15
+ // order. Pure and content-free — driven entirely by the frozen contract plan + templates.
16
+ export function composeDiscussionDirectiveBlock(mode) {
17
+ const directiveLines = DISCUSSION_MODE_PLANS[mode].directives.map((directive) => `- ${DISCUSSION_DIRECTIVE_TEMPLATES[directive]}`);
18
+ return [CONVERSATION_DISCUSSION_BLOCK_HEADER, ...directiveLines].join("\n");
19
+ }
@@ -0,0 +1,18 @@
1
+ import { type EditorAgentActionAuditRecord, type EditorAgentActionPolicyDecision, type EditorAgentActionStatus, type EditorAgentActionType, type EditorAgentConflictCode, type EditorAgentFailureCode } from "@oscharko-dev/keiko-contracts";
2
+ export interface EditorAgentAuditInput {
3
+ readonly occurredAt: number;
4
+ readonly sessionId: string;
5
+ readonly actionId: string;
6
+ readonly actionType: EditorAgentActionType;
7
+ readonly decision: EditorAgentActionPolicyDecision;
8
+ readonly outcome: EditorAgentActionStatus;
9
+ readonly conflictCode?: EditorAgentConflictCode | undefined;
10
+ readonly failureCode?: EditorAgentFailureCode | undefined;
11
+ readonly targetPath?: string | null | undefined;
12
+ readonly editCount?: number | undefined;
13
+ readonly patchByteLength?: number | undefined;
14
+ }
15
+ export declare function recordEditorAgentActionAudit(input: EditorAgentAuditInput): EditorAgentActionAuditRecord | null;
16
+ export declare function listEditorAgentActionAudit(sessionId?: string): readonly EditorAgentActionAuditRecord[];
17
+ export declare function _resetEditorAgentAuditForTests(): void;
18
+ //# sourceMappingURL=agentActionAudit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agentActionAudit.d.ts","sourceRoot":"","sources":["../../src/editor/agentActionAudit.ts"],"names":[],"mappings":"AASA,OAAO,EAGL,KAAK,4BAA4B,EACjC,KAAK,+BAA+B,EACpC,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC5B,MAAM,+BAA+B,CAAC;AAOvC,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC;IAC3C,QAAQ,CAAC,QAAQ,EAAE,+BAA+B,CAAC;IACnD,QAAQ,CAAC,OAAO,EAAE,uBAAuB,CAAC;IAC1C,QAAQ,CAAC,YAAY,CAAC,EAAE,uBAAuB,GAAG,SAAS,CAAC;IAC5D,QAAQ,CAAC,WAAW,CAAC,EAAE,sBAAsB,GAAG,SAAS,CAAC;IAC1D,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAChD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/C;AAkCD,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,qBAAqB,GAC3B,4BAA4B,GAAG,IAAI,CA0BrC;AAID,wBAAgB,0BAA0B,CACxC,SAAS,CAAC,EAAE,MAAM,GACjB,SAAS,4BAA4B,EAAE,CAKzC;AAED,wBAAgB,8BAA8B,IAAI,IAAI,CAGrD"}
@@ -0,0 +1,80 @@
1
+ // Issue #1395, ADR-0062 — bounded, content-free audit ledger for agent editor actions.
2
+ //
3
+ // A per-session, append-only, FIFO-evicted in-memory ledger surfaces "recent agent editor actions"
4
+ // to the BFF read route and the UI. It is intentionally ephemeral (not persisted to disk): the issue
5
+ // excludes long-term telemetry collection. The record shape is content-free by construction (the
6
+ // contract builder is handed only enums, counts, identifiers, and a workspace-relative path) and is
7
+ // run through the keiko-security redactor (defense in depth) before it is stored or served, so raw
8
+ // source text and secrets cannot reach the ledger.
9
+ import { buildEditorAgentActionAuditRecord, isMutatingEditorAgentAction, } from "@oscharko-dev/keiko-contracts";
10
+ import { deepRedactStrings, redact } from "@oscharko-dev/keiko-security";
11
+ // Bounded like the route-edge idempotency map: a long-lived server cannot grow this without limit.
12
+ const MAX_RECORDS_PER_SESSION = 100;
13
+ const MAX_SESSIONS = 256;
14
+ const state = { bySession: new Map(), seq: 0 };
15
+ // Defense in depth: re-redact every string leaf of the already-content-free record so a secret-shaped
16
+ // substring that slipped into a workspace-relative path or summary is scrubbed before storage.
17
+ function redactRecord(record) {
18
+ return deepRedactStrings(record, redact);
19
+ }
20
+ function appendRecord(sessionId, record) {
21
+ const existing = state.bySession.get(sessionId) ?? [];
22
+ const next = [...existing, record];
23
+ if (next.length > MAX_RECORDS_PER_SESSION) {
24
+ next.splice(0, next.length - MAX_RECORDS_PER_SESSION);
25
+ }
26
+ state.bySession.set(sessionId, next);
27
+ while (state.bySession.size > MAX_SESSIONS) {
28
+ const oldest = state.bySession.keys().next().value;
29
+ if (oldest === undefined)
30
+ break;
31
+ state.bySession.delete(oldest);
32
+ }
33
+ }
34
+ // Record one content-free audit entry for an agent editor action. Best-effort and throw-free: a
35
+ // ledger failure must never break the action path. AC1: every mutating action is audited. A denied
36
+ // action is audited even if it is not mutating, so a blocked attempt stays visible. Allowed
37
+ // navigation/layout actions are not recorded — the ledger is for governance-relevant activity.
38
+ // Returns the stored (redacted) record, or null when the action is not audited or recording failed.
39
+ export function recordEditorAgentActionAudit(input) {
40
+ if (!isMutatingEditorAgentAction(input.actionType) && input.decision.disposition !== "denied") {
41
+ return null;
42
+ }
43
+ try {
44
+ state.seq += 1;
45
+ const record = buildEditorAgentActionAuditRecord({
46
+ auditId: `editor-agent-audit-${String(state.seq)}`,
47
+ occurredAt: input.occurredAt,
48
+ sessionId: input.sessionId,
49
+ actionId: input.actionId,
50
+ actionType: input.actionType,
51
+ decision: input.decision,
52
+ outcome: input.outcome,
53
+ conflictCode: input.conflictCode,
54
+ failureCode: input.failureCode,
55
+ targetPath: input.targetPath,
56
+ editCount: input.editCount,
57
+ patchByteLength: input.patchByteLength,
58
+ });
59
+ const redacted = redactRecord(record);
60
+ appendRecord(input.sessionId, redacted);
61
+ return redacted;
62
+ }
63
+ catch {
64
+ return null;
65
+ }
66
+ }
67
+ // Recent records, newest last. With a sessionId, returns that session's bounded list; without one,
68
+ // returns a bounded flattened view across sessions (the global observer's recent-activity feed).
69
+ export function listEditorAgentActionAudit(sessionId) {
70
+ if (sessionId !== undefined)
71
+ return state.bySession.get(sessionId) ?? [];
72
+ const all = [];
73
+ for (const records of state.bySession.values())
74
+ all.push(...records);
75
+ return all.slice(-MAX_RECORDS_PER_SESSION);
76
+ }
77
+ export function _resetEditorAgentAuditForTests() {
78
+ state.bySession.clear();
79
+ state.seq = 0;
80
+ }
@@ -3,5 +3,6 @@ export declare function handleEditorAgentSessions(): RouteResult;
3
3
  export declare function handleEditorAgentSnapshot(ctx: RouteContext): Promise<RouteResult>;
4
4
  export declare function handleEditorAgentActions(ctx: RouteContext): Promise<RouteResult>;
5
5
  export declare function handleEditorAgentEvents(ctx: RouteContext): HandlerOutcome;
6
+ export declare function handleEditorAgentAudit(ctx: RouteContext): RouteResult;
6
7
  export declare function _resetEditorAgentStateForTests(): void;
7
8
  //# sourceMappingURL=agentRoutes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agentRoutes.d.ts","sourceRoot":"","sources":["../../src/editor/agentRoutes.ts"],"names":[],"mappings":"AAYA,OAAO,EAAwB,KAAK,cAAc,EAAE,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAiJ9G,wBAAgB,yBAAyB,IAAI,WAAW,CAEvD;AAED,wBAAsB,yBAAyB,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAsBvF;AAED,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAsCtF;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,YAAY,GAAG,cAAc,CAMzE;AAeD,wBAAgB,8BAA8B,IAAI,IAAI,CAKrD"}
1
+ {"version":3,"file":"agentRoutes.d.ts","sourceRoot":"","sources":["../../src/editor/agentRoutes.ts"],"names":[],"mappings":"AAiDA,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,WAAW,EACjB,MAAM,cAAc,CAAC;AA+WtB,wBAAgB,yBAAyB,IAAI,WAAW,CAEvD;AAED,wBAAsB,yBAAyB,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAkBvF;AAgDD,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAqCtF;AAoCD,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,YAAY,GAAG,cAAc,CAIzE;AAKD,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,YAAY,GAAG,WAAW,CAGrE;AAoBD,wBAAgB,8BAA8B,IAAI,IAAI,CAIrD"}