@oscharko-dev/keiko-server 0.2.8 → 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 (281) 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 +27 -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 +45 -0
  84. package/dist/files.d.ts.map +1 -1
  85. package/dist/files.js +631 -7
  86. package/dist/gateway-readiness.js +3 -3
  87. package/dist/gateway-setup.d.ts +2 -0
  88. package/dist/gateway-setup.d.ts.map +1 -1
  89. package/dist/gateway-setup.js +275 -11
  90. package/dist/gitDelivery/actionSheetProjection.d.ts +30 -0
  91. package/dist/gitDelivery/actionSheetProjection.d.ts.map +1 -0
  92. package/dist/gitDelivery/actionSheetProjection.js +206 -0
  93. package/dist/gitDelivery/actionSheetRoutes.d.ts +29 -0
  94. package/dist/gitDelivery/actionSheetRoutes.d.ts.map +1 -0
  95. package/dist/gitDelivery/actionSheetRoutes.js +293 -0
  96. package/dist/gitDelivery/agentOperationsRoutes.d.ts +33 -0
  97. package/dist/gitDelivery/agentOperationsRoutes.d.ts.map +1 -0
  98. package/dist/gitDelivery/agentOperationsRoutes.js +405 -0
  99. package/dist/gitDelivery/commitRoutes.d.ts +23 -0
  100. package/dist/gitDelivery/commitRoutes.d.ts.map +1 -0
  101. package/dist/gitDelivery/commitRoutes.js +204 -0
  102. package/dist/gitDelivery/evidenceRoutes.d.ts +9 -0
  103. package/dist/gitDelivery/evidenceRoutes.d.ts.map +1 -0
  104. package/dist/gitDelivery/evidenceRoutes.js +101 -0
  105. package/dist/gitDelivery/execution.d.ts +38 -0
  106. package/dist/gitDelivery/execution.d.ts.map +1 -0
  107. package/dist/gitDelivery/execution.js +117 -0
  108. package/dist/gitDelivery/localMutationRoutes.d.ts +30 -0
  109. package/dist/gitDelivery/localMutationRoutes.d.ts.map +1 -0
  110. package/dist/gitDelivery/localMutationRoutes.js +165 -0
  111. package/dist/gitDelivery/mergeExecution.d.ts +63 -0
  112. package/dist/gitDelivery/mergeExecution.d.ts.map +1 -0
  113. package/dist/gitDelivery/mergeExecution.js +168 -0
  114. package/dist/gitDelivery/mergeRoutes.d.ts +12 -0
  115. package/dist/gitDelivery/mergeRoutes.d.ts.map +1 -0
  116. package/dist/gitDelivery/mergeRoutes.js +218 -0
  117. package/dist/gitDelivery/mutationEvidenceLedger.d.ts +23 -0
  118. package/dist/gitDelivery/mutationEvidenceLedger.d.ts.map +1 -0
  119. package/dist/gitDelivery/mutationEvidenceLedger.js +87 -0
  120. package/dist/gitDelivery/prExecution.d.ts +54 -0
  121. package/dist/gitDelivery/prExecution.d.ts.map +1 -0
  122. package/dist/gitDelivery/prExecution.js +192 -0
  123. package/dist/gitDelivery/prRoutes.d.ts +12 -0
  124. package/dist/gitDelivery/prRoutes.d.ts.map +1 -0
  125. package/dist/gitDelivery/prRoutes.js +256 -0
  126. package/dist/gitDelivery/pushExecution.d.ts +43 -0
  127. package/dist/gitDelivery/pushExecution.d.ts.map +1 -0
  128. package/dist/gitDelivery/pushExecution.js +124 -0
  129. package/dist/gitDelivery/pushRoutes.d.ts +12 -0
  130. package/dist/gitDelivery/pushRoutes.d.ts.map +1 -0
  131. package/dist/gitDelivery/pushRoutes.js +200 -0
  132. package/dist/gitDelivery/requestGuards.d.ts +15 -0
  133. package/dist/gitDelivery/requestGuards.d.ts.map +1 -0
  134. package/dist/gitDelivery/requestGuards.js +97 -0
  135. package/dist/gitDelivery/syncEvidence.d.ts +37 -0
  136. package/dist/gitDelivery/syncEvidence.d.ts.map +1 -0
  137. package/dist/gitDelivery/syncEvidence.js +85 -0
  138. package/dist/gitDelivery/syncExecution.d.ts +30 -0
  139. package/dist/gitDelivery/syncExecution.d.ts.map +1 -0
  140. package/dist/gitDelivery/syncExecution.js +266 -0
  141. package/dist/gitDelivery/syncRoutes.d.ts +13 -0
  142. package/dist/gitDelivery/syncRoutes.d.ts.map +1 -0
  143. package/dist/gitDelivery/syncRoutes.js +200 -0
  144. package/dist/gitPorcelainStatus.d.ts +15 -0
  145. package/dist/gitPorcelainStatus.d.ts.map +1 -0
  146. package/dist/gitPorcelainStatus.js +104 -0
  147. package/dist/gitRepositoryReads.d.ts +10 -0
  148. package/dist/gitRepositoryReads.d.ts.map +1 -0
  149. package/dist/gitRepositoryReads.js +314 -0
  150. package/dist/gitRepositoryRoutes.d.ts +7 -0
  151. package/dist/gitRepositoryRoutes.d.ts.map +1 -0
  152. package/dist/gitRepositoryRoutes.js +221 -0
  153. package/dist/gitRoutes.d.ts +66 -0
  154. package/dist/gitRoutes.d.ts.map +1 -0
  155. package/dist/gitRoutes.js +543 -0
  156. package/dist/governed-workflow.d.ts +2 -0
  157. package/dist/governed-workflow.d.ts.map +1 -1
  158. package/dist/governed-workflow.js +4 -0
  159. package/dist/grounded-qa.d.ts +11 -0
  160. package/dist/grounded-qa.d.ts.map +1 -1
  161. package/dist/grounded-qa.js +13 -4
  162. package/dist/headers.d.ts +4 -1
  163. package/dist/headers.d.ts.map +1 -1
  164. package/dist/headers.js +11 -4
  165. package/dist/index.d.ts +8 -1
  166. package/dist/index.d.ts.map +1 -1
  167. package/dist/index.js +9 -1
  168. package/dist/qualityIntelligence/figmaSnapshotRoutes.d.ts +1 -1
  169. package/dist/qualityIntelligence/figmaSnapshotRoutes.d.ts.map +1 -1
  170. package/dist/qualityIntelligence/figmaSnapshotRoutes.js +1 -1
  171. package/dist/read-handlers.d.ts +5 -0
  172. package/dist/read-handlers.d.ts.map +1 -1
  173. package/dist/read-handlers.js +57 -1
  174. package/dist/routes.d.ts.map +1 -1
  175. package/dist/routes.js +259 -6
  176. package/dist/run-engine.d.ts.map +1 -1
  177. package/dist/run-engine.js +3 -0
  178. package/dist/run-handlers.d.ts.map +1 -1
  179. package/dist/run-handlers.js +74 -4
  180. package/dist/run-request.d.ts +11 -0
  181. package/dist/run-request.d.ts.map +1 -1
  182. package/dist/run-request.js +158 -10
  183. package/dist/runtime/capabilityDetector.d.ts +38 -0
  184. package/dist/runtime/capabilityDetector.d.ts.map +1 -0
  185. package/dist/runtime/capabilityDetector.js +443 -0
  186. package/dist/runtime/capabilityRoutes.d.ts +9 -0
  187. package/dist/runtime/capabilityRoutes.d.ts.map +1 -0
  188. package/dist/runtime/capabilityRoutes.js +45 -0
  189. package/dist/runtime/containerEngineDetector.d.ts +17 -0
  190. package/dist/runtime/containerEngineDetector.d.ts.map +1 -0
  191. package/dist/runtime/containerEngineDetector.js +222 -0
  192. package/dist/runtime/containerRoutes.d.ts +8 -0
  193. package/dist/runtime/containerRoutes.d.ts.map +1 -0
  194. package/dist/runtime/containerRoutes.js +207 -0
  195. package/dist/runtime/containerRunner-errors.d.ts +18 -0
  196. package/dist/runtime/containerRunner-errors.d.ts.map +1 -0
  197. package/dist/runtime/containerRunner-errors.js +42 -0
  198. package/dist/runtime/containerRunner-evidence.d.ts +24 -0
  199. package/dist/runtime/containerRunner-evidence.d.ts.map +1 -0
  200. package/dist/runtime/containerRunner-evidence.js +74 -0
  201. package/dist/runtime/containerRunner.d.ts +37 -0
  202. package/dist/runtime/containerRunner.d.ts.map +1 -0
  203. package/dist/runtime/containerRunner.js +443 -0
  204. package/dist/server.d.ts.map +1 -1
  205. package/dist/server.js +24 -4
  206. package/dist/store/schema.d.ts +1 -1
  207. package/dist/store/schema.d.ts.map +1 -1
  208. package/dist/store/schema.js +62 -1
  209. package/dist/task-workspace/active-store.d.ts +21 -0
  210. package/dist/task-workspace/active-store.d.ts.map +1 -0
  211. package/dist/task-workspace/active-store.js +55 -0
  212. package/dist/task-workspace/authorization.d.ts +7 -0
  213. package/dist/task-workspace/authorization.d.ts.map +1 -0
  214. package/dist/task-workspace/authorization.js +54 -0
  215. package/dist/task-workspace/binding.d.ts +3 -0
  216. package/dist/task-workspace/binding.d.ts.map +1 -0
  217. package/dist/task-workspace/binding.js +22 -0
  218. package/dist/task-workspace/cleanup.d.ts +4 -0
  219. package/dist/task-workspace/cleanup.d.ts.map +1 -0
  220. package/dist/task-workspace/cleanup.js +428 -0
  221. package/dist/task-workspace/errors.d.ts +14 -0
  222. package/dist/task-workspace/errors.d.ts.map +1 -0
  223. package/dist/task-workspace/errors.js +81 -0
  224. package/dist/task-workspace/evidence.d.ts +32 -0
  225. package/dist/task-workspace/evidence.d.ts.map +1 -0
  226. package/dist/task-workspace/evidence.js +52 -0
  227. package/dist/task-workspace/field-safety.d.ts +3 -0
  228. package/dist/task-workspace/field-safety.d.ts.map +1 -0
  229. package/dist/task-workspace/field-safety.js +42 -0
  230. package/dist/task-workspace/health.d.ts +4 -0
  231. package/dist/task-workspace/health.d.ts.map +1 -0
  232. package/dist/task-workspace/health.js +163 -0
  233. package/dist/task-workspace/lifecycle.d.ts +3 -0
  234. package/dist/task-workspace/lifecycle.d.ts.map +1 -0
  235. package/dist/task-workspace/lifecycle.js +248 -0
  236. package/dist/task-workspace/locks.d.ts +13 -0
  237. package/dist/task-workspace/locks.d.ts.map +1 -0
  238. package/dist/task-workspace/locks.js +44 -0
  239. package/dist/task-workspace/managed-root.d.ts +7 -0
  240. package/dist/task-workspace/managed-root.d.ts.map +1 -0
  241. package/dist/task-workspace/managed-root.js +98 -0
  242. package/dist/task-workspace/mutex.d.ts +8 -0
  243. package/dist/task-workspace/mutex.d.ts.map +1 -0
  244. package/dist/task-workspace/mutex.js +82 -0
  245. package/dist/task-workspace/naming.d.ts +15 -0
  246. package/dist/task-workspace/naming.d.ts.map +1 -0
  247. package/dist/task-workspace/naming.js +0 -0
  248. package/dist/task-workspace/provisioning.d.ts +3 -0
  249. package/dist/task-workspace/provisioning.d.ts.map +1 -0
  250. package/dist/task-workspace/provisioning.js +528 -0
  251. package/dist/task-workspace/reconciliation.d.ts +15 -0
  252. package/dist/task-workspace/reconciliation.d.ts.map +1 -0
  253. package/dist/task-workspace/reconciliation.js +274 -0
  254. package/dist/task-workspace/repair.d.ts +3 -0
  255. package/dist/task-workspace/repair.d.ts.map +1 -0
  256. package/dist/task-workspace/repair.js +286 -0
  257. package/dist/task-workspace/routes.d.ts +19 -0
  258. package/dist/task-workspace/routes.d.ts.map +1 -0
  259. package/dist/task-workspace/routes.js +481 -0
  260. package/dist/task-workspace/store.d.ts +12 -0
  261. package/dist/task-workspace/store.d.ts.map +1 -0
  262. package/dist/task-workspace/store.js +128 -0
  263. package/dist/task-workspace/types.d.ts +170 -0
  264. package/dist/task-workspace/types.d.ts.map +1 -0
  265. package/dist/task-workspace/types.js +5 -0
  266. package/dist/voice-action-governance.d.ts +23 -0
  267. package/dist/voice-action-governance.d.ts.map +1 -0
  268. package/dist/voice-action-governance.js +126 -0
  269. package/dist/voice-handlers.d.ts +6 -0
  270. package/dist/voice-handlers.d.ts.map +1 -0
  271. package/dist/voice-handlers.js +570 -0
  272. package/dist/voice-realtime-grounded-tool.d.ts +31 -0
  273. package/dist/voice-realtime-grounded-tool.d.ts.map +1 -0
  274. package/dist/voice-realtime-grounded-tool.js +322 -0
  275. package/dist/voice-realtime.d.ts +69 -0
  276. package/dist/voice-realtime.d.ts.map +1 -0
  277. package/dist/voice-realtime.js +787 -0
  278. package/dist/workspace-state-handlers.d.ts +5 -0
  279. package/dist/workspace-state-handlers.d.ts.map +1 -0
  280. package/dist/workspace-state-handlers.js +106 -0
  281. package/package.json +20 -19
@@ -0,0 +1,543 @@
1
+ import { spawn } from "node:child_process";
2
+ import { Buffer } from "node:buffer";
3
+ import { realpath } from "node:fs/promises";
4
+ import { isAbsolute, relative, resolve } from "node:path";
5
+ import { GIT_REPOSITORY_SCHEMA_VERSION, isRootRelativeFileIdentifier, } from "@oscharko-dev/keiko-contracts";
6
+ import { errorBody } from "./routes.js";
7
+ import { FilesError, resolveRoot, runFilesHandler } from "./files.js";
8
+ const DEFAULT_STATUS_MAX_BYTES = 512 * 1024;
9
+ const DEFAULT_DIFF_MAX_BYTES = 128 * 1024;
10
+ const DEFAULT_MAX_CHANGES = 500;
11
+ const DEFAULT_TIMEOUT_MS = 5_000;
12
+ function devNullPath() {
13
+ return process.platform === "win32" ? "NUL" : "/dev/null";
14
+ }
15
+ // Local-read env: fully config-isolated. HOME/XDG/global+system config are neutralized so a read
16
+ // can never load a user `~/.gitconfig`, a credential helper, or an SSH identity. Correct for the
17
+ // local status/diff/branches/summary/history/remotes reads, which never authenticate to a remote.
18
+ export function gitEnv() {
19
+ const env = {
20
+ PATH: process.env.PATH ?? "",
21
+ GIT_TERMINAL_PROMPT: "0",
22
+ GIT_PAGER: "cat",
23
+ PAGER: "cat",
24
+ GIT_CONFIG_NOSYSTEM: "1",
25
+ GIT_CONFIG_GLOBAL: devNullPath(),
26
+ GIT_OPTIONAL_LOCKS: "0",
27
+ };
28
+ if (process.platform === "win32") {
29
+ env.SystemRoot = process.env.SystemRoot ?? "";
30
+ env.WINDIR = process.env.WINDIR ?? "";
31
+ }
32
+ else {
33
+ env.HOME = "/nonexistent";
34
+ env.XDG_CONFIG_HOME = "/nonexistent";
35
+ }
36
+ return env;
37
+ }
38
+ // Network-sync env: a fetch/pull MUST be able to authenticate to a private/SSH remote, so it
39
+ // inherits the real environment (the user's global `~/.gitconfig` credential.helper, the macOS
40
+ // osxkeychain helper, and the real `~/.ssh` identities). It still never prompts — GIT_TERMINAL_PROMPT
41
+ // is forced off and SSH runs in BatchMode — so it fails closed if no stored credential satisfies the
42
+ // remote rather than hanging on an interactive prompt. Used ONLY for the actual fetch/pull command;
43
+ // local reads keep the hardened, config-isolated `gitEnv` above.
44
+ export function networkGitEnv() {
45
+ return {
46
+ ...process.env,
47
+ GIT_TERMINAL_PROMPT: "0", // never prompt — fail closed
48
+ GIT_PAGER: "cat",
49
+ PAGER: "cat",
50
+ GIT_OPTIONAL_LOCKS: "0",
51
+ // No SSH credential prompt and no implicit first-use trust. Unknown or changed host keys fail
52
+ // closed and are surfaced by the sync outcome classifier.
53
+ GIT_SSH_COMMAND: "ssh -oBatchMode=yes -oStrictHostKeyChecking=yes",
54
+ };
55
+ }
56
+ // Factory: the runner owns process lifecycle state, byte caps, timeout, and spawn-error mapping
57
+ // together. `buildEnv` is the only seam — the local reads pass the hardened `gitEnv`, network sync
58
+ // passes the credential-capable `networkGitEnv`; everything else is identical.
59
+ // eslint-disable-next-line max-lines-per-function
60
+ export function createGitProcessRunner(buildEnv) {
61
+ // eslint-disable-next-line max-lines-per-function
62
+ return (args, options) =>
63
+ // eslint-disable-next-line max-lines-per-function
64
+ new Promise((resolveResult) => {
65
+ const child = spawn("git", args, {
66
+ cwd: options.cwd,
67
+ env: buildEnv(),
68
+ shell: false,
69
+ windowsHide: true,
70
+ stdio: ["ignore", "pipe", "pipe"],
71
+ });
72
+ const stdoutChunks = [];
73
+ const stderrChunks = [];
74
+ let stdoutBytes = 0;
75
+ let stderrBytes = 0;
76
+ let truncated = false;
77
+ let settled = false;
78
+ const timer = setTimeout(() => {
79
+ truncated = true;
80
+ child.kill("SIGTERM");
81
+ }, options.timeoutMs);
82
+ const capture = (chunks, currentBytes, chunk) => {
83
+ const remaining = options.maxBytes - currentBytes;
84
+ if (remaining <= 0) {
85
+ truncated = true;
86
+ child.kill("SIGTERM");
87
+ return currentBytes;
88
+ }
89
+ if (chunk.byteLength > remaining) {
90
+ chunks.push(chunk.subarray(0, remaining));
91
+ truncated = true;
92
+ child.kill("SIGTERM");
93
+ return options.maxBytes;
94
+ }
95
+ chunks.push(chunk);
96
+ return currentBytes + chunk.byteLength;
97
+ };
98
+ child.stdout.on("data", (chunk) => {
99
+ stdoutBytes = capture(stdoutChunks, stdoutBytes, chunk);
100
+ });
101
+ child.stderr.on("data", (chunk) => {
102
+ stderrBytes = capture(stderrChunks, stderrBytes, chunk);
103
+ });
104
+ child.on("error", () => {
105
+ if (settled)
106
+ return;
107
+ settled = true;
108
+ clearTimeout(timer);
109
+ resolveResult({
110
+ exitCode: 127,
111
+ signal: null,
112
+ stdout: "",
113
+ stderr: "git executable unavailable",
114
+ truncated,
115
+ });
116
+ });
117
+ child.on("close", (exitCode, signal) => {
118
+ if (settled)
119
+ return;
120
+ settled = true;
121
+ clearTimeout(timer);
122
+ resolveResult({
123
+ exitCode,
124
+ signal,
125
+ stdout: Buffer.concat(stdoutChunks).toString("utf8"),
126
+ stderr: Buffer.concat(stderrChunks).toString("utf8"),
127
+ truncated,
128
+ });
129
+ });
130
+ });
131
+ }
132
+ // Local reads use the hardened, config-isolated env; network sync needs the user's credential
133
+ // configuration but must still never prompt (fail-closed) — see networkGitEnv.
134
+ export const defaultGitProcessRunner = createGitProcessRunner(gitEnv);
135
+ export const defaultGitNetworkProcessRunner = createGitProcessRunner(networkGitEnv);
136
+ export function isContained(root, target) {
137
+ const rootCmp = process.platform === "win32" ? root.toLowerCase() : root;
138
+ const targetCmp = process.platform === "win32" ? target.toLowerCase() : target;
139
+ const rel = relative(rootCmp, targetCmp);
140
+ return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel));
141
+ }
142
+ function toPosix(value) {
143
+ return value.replaceAll("\\", "/");
144
+ }
145
+ function genericUnavailable(root, reason, message) {
146
+ return {
147
+ schemaVersion: GIT_REPOSITORY_SCHEMA_VERSION,
148
+ root,
149
+ state: reason === "unsafe-repository" ? "unsafe" : "unavailable",
150
+ available: false,
151
+ reason,
152
+ message,
153
+ detached: false,
154
+ clean: true,
155
+ stagedCount: 0,
156
+ unstagedCount: 0,
157
+ untrackedCount: 0,
158
+ conflictedCount: 0,
159
+ changes: [],
160
+ truncated: false,
161
+ maxChanges: DEFAULT_MAX_CHANGES,
162
+ };
163
+ }
164
+ export function classifyFailure(result) {
165
+ const text = `${result.stdout}\n${result.stderr}`.toLowerCase();
166
+ if (result.exitCode === 127)
167
+ return "git-missing";
168
+ if (text.includes("dubious ownership") || text.includes("safe.directory")) {
169
+ return "unsafe-repository";
170
+ }
171
+ if (text.includes("not a git repository")) {
172
+ return "not-a-repository";
173
+ }
174
+ return "git-error";
175
+ }
176
+ // eslint-disable-next-line complexity
177
+ export function optionsWithDefaults(options) {
178
+ return {
179
+ runner: options?.runner ?? defaultGitProcessRunner,
180
+ maxStatusBytes: options?.maxStatusBytes ?? DEFAULT_STATUS_MAX_BYTES,
181
+ maxDiffBytes: options?.maxDiffBytes ?? DEFAULT_DIFF_MAX_BYTES,
182
+ maxChanges: options?.maxChanges ?? DEFAULT_MAX_CHANGES,
183
+ timeoutMs: options?.timeoutMs ?? DEFAULT_TIMEOUT_MS,
184
+ };
185
+ }
186
+ export async function resolveRepository(ctx, deps, options) {
187
+ const selectedRoot = await resolveRoot(deps.store, ctx.url.searchParams.get("root"), deps.redactor);
188
+ const revParse = await options.runner([
189
+ "--no-pager",
190
+ "--no-optional-locks",
191
+ "-C",
192
+ selectedRoot.realRoot,
193
+ "rev-parse",
194
+ "--show-toplevel",
195
+ ], { cwd: selectedRoot.realRoot, maxBytes: 16 * 1024, timeoutMs: options.timeoutMs });
196
+ if (revParse.exitCode !== 0) {
197
+ const reason = classifyFailure(revParse);
198
+ return genericUnavailable(selectedRoot.root, reason, reason === "unsafe-repository"
199
+ ? "Git blocked this repository because its ownership is unsafe."
200
+ : "Git status is unavailable for this folder.");
201
+ }
202
+ const rawRepositoryRoot = resolve(revParse.stdout.split(/\r?\n/u)[0]?.trim() ?? "");
203
+ const repositoryRoot = await realpath(rawRepositoryRoot).catch(() => rawRepositoryRoot);
204
+ if (!isContained(repositoryRoot, selectedRoot.realRoot)) {
205
+ return genericUnavailable(selectedRoot.root, "repository-root-outside-root", "Git status is unavailable because the repository root is outside the selected folder.");
206
+ }
207
+ return {
208
+ root: selectedRoot.root,
209
+ realRoot: selectedRoot.realRoot,
210
+ repositoryRoot,
211
+ selectedRootPrefix: toPosix(relative(repositoryRoot, selectedRoot.realRoot)),
212
+ };
213
+ }
214
+ function parseBranch(header) {
215
+ if (header.includes("HEAD (no branch)") || header.includes("HEAD detached")) {
216
+ return { detached: true };
217
+ }
218
+ const trimmed = header.replace(/^##\s*/u, "");
219
+ const branch = trimmed
220
+ .split("...")[0]
221
+ ?.replace(/\s+\[.*$/u, "")
222
+ .trim();
223
+ if (branch === undefined || branch.length === 0 || branch.startsWith("No commits yet on ")) {
224
+ const unborn = branch?.replace(/^No commits yet on\s+/u, "");
225
+ return unborn === undefined || unborn.length === 0
226
+ ? { detached: false }
227
+ : { branch: unborn, detached: false };
228
+ }
229
+ return { branch, detached: false };
230
+ }
231
+ function stripSelectedPrefix(path, prefix) {
232
+ if (prefix.length === 0 || prefix === ".")
233
+ return path;
234
+ if (path === prefix)
235
+ return "";
236
+ const start = `${prefix}/`;
237
+ return path.startsWith(start) ? path.slice(start.length) : null;
238
+ }
239
+ function toStatusCode(value) {
240
+ if (value === undefined || value === "")
241
+ return " ";
242
+ return [" ", "M", "A", "D", "R", "C", "U", "?", "!"].includes(value)
243
+ ? value
244
+ : " ";
245
+ }
246
+ // Porcelain parsing is intentionally centralized so Git XY semantics stay audited in one place.
247
+ // eslint-disable-next-line max-lines-per-function, complexity
248
+ function parseStatus(stdout, root, repositoryRoot, selectedRootPrefix, maxChanges, processTruncated) {
249
+ const records = stdout.split("\0").filter((record) => record.length > 0);
250
+ let branch;
251
+ let detached = false;
252
+ const changes = [];
253
+ for (let index = 0; index < records.length; index += 1) {
254
+ const record = records[index] ?? "";
255
+ if (record.startsWith("## ")) {
256
+ const parsed = parseBranch(record);
257
+ branch = parsed.branch;
258
+ detached = parsed.detached;
259
+ continue;
260
+ }
261
+ if (record.length < 4)
262
+ continue;
263
+ const indexStatus = toStatusCode(record[0]);
264
+ const worktreeStatus = toStatusCode(record[1]);
265
+ const rawPath = record.slice(3);
266
+ const path = stripSelectedPrefix(rawPath, selectedRootPrefix);
267
+ if (path === null || path.length === 0)
268
+ continue;
269
+ const oldRawPath = indexStatus === "R" || indexStatus === "C" ? records[index + 1] : undefined;
270
+ if (oldRawPath !== undefined)
271
+ index += 1;
272
+ if (changes.length < maxChanges) {
273
+ const oldPath = oldRawPath === undefined
274
+ ? undefined
275
+ : (stripSelectedPrefix(oldRawPath, selectedRootPrefix) ?? undefined);
276
+ changes.push({
277
+ path,
278
+ oldPath,
279
+ indexStatus,
280
+ worktreeStatus,
281
+ staged: indexStatus !== " " && indexStatus !== "?",
282
+ unstaged: worktreeStatus !== " " && worktreeStatus !== "?",
283
+ untracked: indexStatus === "?" && worktreeStatus === "?",
284
+ conflicted: indexStatus === "U" ||
285
+ worktreeStatus === "U" ||
286
+ (indexStatus === "A" && worktreeStatus === "A") ||
287
+ (indexStatus === "D" && worktreeStatus === "D"),
288
+ });
289
+ }
290
+ }
291
+ const stagedCount = changes.filter((change) => change.staged).length;
292
+ const unstagedCount = changes.filter((change) => change.unstaged).length;
293
+ const untrackedCount = changes.filter((change) => change.untracked).length;
294
+ const conflictedCount = changes.filter((change) => change.conflicted).length;
295
+ return {
296
+ schemaVersion: GIT_REPOSITORY_SCHEMA_VERSION,
297
+ root,
298
+ repositoryRoot,
299
+ state: "available",
300
+ available: true,
301
+ branch,
302
+ detached,
303
+ clean: changes.length === 0,
304
+ stagedCount,
305
+ unstagedCount,
306
+ untrackedCount,
307
+ conflictedCount,
308
+ changes,
309
+ truncated: processTruncated || records.length - 1 > maxChanges,
310
+ maxChanges,
311
+ };
312
+ }
313
+ function redacted(deps, value) {
314
+ return deps.redactor(value);
315
+ }
316
+ function unavailableBranchList(repo) {
317
+ return {
318
+ schemaVersion: GIT_REPOSITORY_SCHEMA_VERSION,
319
+ root: repo.root,
320
+ available: false,
321
+ state: repo.state === "error" ? "unavailable" : repo.state,
322
+ reason: repo.reason,
323
+ message: repo.message,
324
+ branches: [],
325
+ truncated: false,
326
+ };
327
+ }
328
+ function parseBranches(stdout) {
329
+ const fields = stdout.split("\0");
330
+ const branches = [];
331
+ for (let index = 0; index + 2 < fields.length; index += 3) {
332
+ const name = fields[index]?.trim() ?? "";
333
+ const headRefHash = fields[index + 1]?.trim() ?? "";
334
+ const headMarker = fields[index + 2]?.trim() ?? "";
335
+ if (name.length === 0 || headRefHash.length === 0)
336
+ continue;
337
+ branches.push({ name, headRefHash, current: headMarker === "*" });
338
+ }
339
+ return branches;
340
+ }
341
+ function branchListFailure(repo, result) {
342
+ const reason = classifyFailure(result);
343
+ return {
344
+ schemaVersion: GIT_REPOSITORY_SCHEMA_VERSION,
345
+ root: repo.root,
346
+ repositoryRoot: repo.repositoryRoot,
347
+ available: false,
348
+ state: reason === "unsafe-repository" ? "unsafe" : "unavailable",
349
+ reason,
350
+ message: "Git branches are unavailable for this folder.",
351
+ branches: [],
352
+ truncated: result.truncated,
353
+ };
354
+ }
355
+ export async function handleGitBranches(ctx, deps, rawOptions) {
356
+ return runFilesHandler(async () => {
357
+ const options = optionsWithDefaults(rawOptions ?? deps.gitRouteOptions);
358
+ const repo = await resolveRepository(ctx, deps, options);
359
+ if ("available" in repo) {
360
+ return { status: 200, body: redacted(deps, unavailableBranchList(repo)) };
361
+ }
362
+ const result = await options.runner([
363
+ "--no-pager",
364
+ "--no-optional-locks",
365
+ "-C",
366
+ repo.repositoryRoot,
367
+ "for-each-ref",
368
+ "--format=%(refname:short)%00%(objectname)%00%(HEAD)%00",
369
+ "refs/heads",
370
+ ], { cwd: repo.repositoryRoot, maxBytes: options.maxStatusBytes, timeoutMs: options.timeoutMs });
371
+ if (result.exitCode !== 0) {
372
+ return { status: 200, body: redacted(deps, branchListFailure(repo, result)) };
373
+ }
374
+ return {
375
+ status: 200,
376
+ body: redacted(deps, {
377
+ schemaVersion: GIT_REPOSITORY_SCHEMA_VERSION,
378
+ root: repo.root,
379
+ repositoryRoot: repo.repositoryRoot,
380
+ available: true,
381
+ state: "available",
382
+ branches: parseBranches(result.stdout),
383
+ truncated: result.truncated,
384
+ }),
385
+ };
386
+ });
387
+ }
388
+ function validatePath(path) {
389
+ const trimmed = path?.trim();
390
+ if (trimmed === undefined || trimmed.length === 0)
391
+ return undefined;
392
+ if (!isRootRelativeFileIdentifier(trimmed)) {
393
+ throw new FilesError(400, "BAD_PATH", "The path must be relative to the selected root.");
394
+ }
395
+ return trimmed;
396
+ }
397
+ function gitPath(prefix, path) {
398
+ const normalizedPrefix = prefix === "." ? "" : prefix;
399
+ if (path === undefined)
400
+ return normalizedPrefix.length > 0 ? normalizedPrefix : undefined;
401
+ return normalizedPrefix.length > 0 ? `${normalizedPrefix}/${path}` : path;
402
+ }
403
+ function literalGitPathspec(path) {
404
+ return `:(literal)${path}`;
405
+ }
406
+ function parseScope(input) {
407
+ if (input === null || input.length === 0)
408
+ return "all";
409
+ if (input === "all" || input === "worktree" || input === "staged")
410
+ return input;
411
+ throw new FilesError(400, "BAD_REQUEST", "The diff scope must be all, worktree, or staged.");
412
+ }
413
+ async function runDiff(repo, options, staged, path) {
414
+ const args = [
415
+ "--no-pager",
416
+ "--no-optional-locks",
417
+ "-C",
418
+ repo.repositoryRoot,
419
+ "diff",
420
+ "--no-ext-diff",
421
+ "--no-textconv",
422
+ "--no-color",
423
+ ];
424
+ if (staged)
425
+ args.push("--cached");
426
+ const relativePath = gitPath(repo.selectedRootPrefix, path);
427
+ if (relativePath !== undefined)
428
+ args.push("--", literalGitPathspec(relativePath));
429
+ return options.runner(args, {
430
+ cwd: repo.repositoryRoot,
431
+ maxBytes: options.maxDiffBytes,
432
+ timeoutMs: options.timeoutMs,
433
+ });
434
+ }
435
+ // eslint-disable-next-line max-lines-per-function
436
+ export async function handleGitStatus(ctx, deps, rawOptions) {
437
+ return runFilesHandler(async () => {
438
+ const options = optionsWithDefaults(rawOptions ?? deps.gitRouteOptions);
439
+ const repo = await resolveRepository(ctx, deps, options);
440
+ if ("available" in repo) {
441
+ const body = { ...repo, maxChanges: options.maxChanges };
442
+ return { status: 200, body: redacted(deps, body) };
443
+ }
444
+ const status = await options.runner([
445
+ "--no-pager",
446
+ "--no-optional-locks",
447
+ "-C",
448
+ repo.repositoryRoot,
449
+ "status",
450
+ "--porcelain=v1",
451
+ "-z",
452
+ "--branch",
453
+ "--untracked-files=all",
454
+ "--",
455
+ ...(repo.selectedRootPrefix.length > 0 && repo.selectedRootPrefix !== "."
456
+ ? [literalGitPathspec(repo.selectedRootPrefix)]
457
+ : []),
458
+ ], { cwd: repo.repositoryRoot, maxBytes: options.maxStatusBytes, timeoutMs: options.timeoutMs });
459
+ if (status.exitCode !== 0) {
460
+ const reason = classifyFailure(status);
461
+ const body = genericUnavailable(repo.root, reason, reason === "unsafe-repository"
462
+ ? "Git blocked this repository because its ownership is unsafe."
463
+ : "Git status is unavailable for this folder.");
464
+ return { status: 200, body: redacted(deps, { ...body, maxChanges: options.maxChanges }) };
465
+ }
466
+ const body = parseStatus(status.stdout, repo.root, repo.repositoryRoot, repo.selectedRootPrefix, options.maxChanges, status.truncated);
467
+ return { status: 200, body: redacted(deps, body) };
468
+ });
469
+ }
470
+ // eslint-disable-next-line max-lines-per-function
471
+ export async function handleGitDiff(ctx, deps, rawOptions) {
472
+ return runFilesHandler(
473
+ // eslint-disable-next-line max-lines-per-function
474
+ async () => {
475
+ const options = optionsWithDefaults(rawOptions ?? deps.gitRouteOptions);
476
+ const scope = parseScope(ctx.url.searchParams.get("scope"));
477
+ const path = validatePath(ctx.url.searchParams.get("path"));
478
+ const repo = await resolveRepository(ctx, deps, options);
479
+ if ("available" in repo) {
480
+ const body = {
481
+ schemaVersion: GIT_REPOSITORY_SCHEMA_VERSION,
482
+ root: repo.root,
483
+ state: repo.state,
484
+ available: false,
485
+ reason: repo.reason,
486
+ path,
487
+ scope,
488
+ diff: "",
489
+ truncated: false,
490
+ maxBytes: options.maxDiffBytes,
491
+ };
492
+ return { status: 200, body: redacted(deps, body) };
493
+ }
494
+ const runs = scope === "all"
495
+ ? [await runDiff(repo, options, true, path), await runDiff(repo, options, false, path)]
496
+ : [await runDiff(repo, options, scope === "staged", path)];
497
+ const failed = runs.find((result) => result.exitCode !== 0);
498
+ if (failed !== undefined) {
499
+ const reason = classifyFailure(failed);
500
+ if (reason === "unsafe-repository" || reason === "git-missing") {
501
+ const body = {
502
+ schemaVersion: GIT_REPOSITORY_SCHEMA_VERSION,
503
+ root: repo.root,
504
+ repositoryRoot: repo.repositoryRoot,
505
+ state: reason === "unsafe-repository" ? "unsafe" : "unavailable",
506
+ available: false,
507
+ reason,
508
+ path,
509
+ scope,
510
+ diff: "",
511
+ truncated: failed.truncated,
512
+ maxBytes: options.maxDiffBytes,
513
+ };
514
+ return { status: 200, body: redacted(deps, body) };
515
+ }
516
+ return {
517
+ status: 500,
518
+ body: errorBody("GIT_DIFF_FAILED", "Git diff is unavailable for this folder."),
519
+ };
520
+ }
521
+ const rawDiff = runs
522
+ .map((result) => result.stdout)
523
+ .filter((entry) => entry.length > 0)
524
+ .join("\n");
525
+ const rawDiffBytes = Buffer.byteLength(rawDiff, "utf8");
526
+ const diff = rawDiffBytes > options.maxDiffBytes
527
+ ? Buffer.from(rawDiff, "utf8").subarray(0, options.maxDiffBytes).toString("utf8")
528
+ : rawDiff;
529
+ const body = {
530
+ schemaVersion: GIT_REPOSITORY_SCHEMA_VERSION,
531
+ root: repo.root,
532
+ repositoryRoot: repo.repositoryRoot,
533
+ state: "available",
534
+ available: true,
535
+ path,
536
+ scope,
537
+ diff,
538
+ truncated: runs.some((result) => result.truncated) || rawDiffBytes > options.maxDiffBytes,
539
+ maxBytes: options.maxDiffBytes,
540
+ };
541
+ return { status: 200, body: redacted(deps, body) };
542
+ });
543
+ }
@@ -1,3 +1,4 @@
1
+ import type { SpokenActionAuditRecord } from "@oscharko-dev/keiko-contracts";
1
2
  import type { EvidenceGovernedWorkflowHandoff } from "@oscharko-dev/keiko-contracts/evidence";
2
3
  import type { ConnectedContextPack } from "@oscharko-dev/keiko-contracts/connected-context";
3
4
  import { type ProposedPatchEntry, type UserApprovalTokenInput, type WorkflowHandoffRequest } from "@oscharko-dev/keiko-contracts/workflow-handoff";
@@ -5,6 +6,7 @@ import type { PatchValidation, WorkspaceWriter } from "@oscharko-dev/keiko-tools
5
6
  export interface GovernedWorkflowHandoffContext {
6
7
  readonly request: WorkflowHandoffRequest;
7
8
  readonly sourceGroundedRunId?: string | undefined;
9
+ readonly voiceAction?: SpokenActionAuditRecord | undefined;
8
10
  }
9
11
  export declare function contextPackStableIdForPacks(packs: readonly ConnectedContextPack[]): string;
10
12
  export declare function readOnlyPathsForPacks(packs: readonly ConnectedContextPack[], editablePaths: readonly string[]): readonly string[];
@@ -1 +1 @@
1
- {"version":3,"file":"governed-workflow.d.ts","sourceRoot":"","sources":["../src/governed-workflow.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,wCAAwC,CAAC;AAC9F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iDAAiD,CAAC;AAC5F,OAAO,EAGL,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC5B,MAAM,gDAAgD,CAAC;AACxD,OAAO,KAAK,EAAmB,eAAe,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAGnG,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,OAAO,EAAE,sBAAsB,CAAC;IACzC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACnD;AAkDD,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,SAAS,oBAAoB,EAAE,GAAG,MAAM,CAS1F;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,SAAS,oBAAoB,EAAE,EACtC,aAAa,EAAE,SAAS,MAAM,EAAE,GAC/B,SAAS,MAAM,EAAE,CAWnB;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,SAAS,oBAAoB,EAAE,GAAG,SAAS,MAAM,EAAE,CAUjG;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB,GAAG,sBAAsB,CAW7F;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,sBAAsB,GAAG,MAAM,CAEzE;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,8BAA8B,GACtC,+BAA+B,CAWjC;AAED,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,eAAe,EAC3B,aAAa,EAAE,MAAM,EACrB,aAAa,EAAE,SAAS,MAAM,EAAE,GAC/B,eAAe,CA4BjB;AAED,wBAAgB,kCAAkC,CAChD,UAAU,EAAE,eAAe,GAC1B,SAAS,kBAAkB,EAAE,CAkB/B"}
1
+ {"version":3,"file":"governed-workflow.d.ts","sourceRoot":"","sources":["../src/governed-workflow.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAC7E,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,wCAAwC,CAAC;AAC9F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iDAAiD,CAAC;AAC5F,OAAO,EAGL,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC5B,MAAM,gDAAgD,CAAC;AACxD,OAAO,KAAK,EAAmB,eAAe,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAGnG,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,OAAO,EAAE,sBAAsB,CAAC;IACzC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAGlD,QAAQ,CAAC,WAAW,CAAC,EAAE,uBAAuB,GAAG,SAAS,CAAC;CAC5D;AAkDD,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,SAAS,oBAAoB,EAAE,GAAG,MAAM,CAS1F;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,SAAS,oBAAoB,EAAE,EACtC,aAAa,EAAE,SAAS,MAAM,EAAE,GAC/B,SAAS,MAAM,EAAE,CAWnB;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,SAAS,oBAAoB,EAAE,GAAG,SAAS,MAAM,EAAE,CAUjG;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB,GAAG,sBAAsB,CAW7F;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,sBAAsB,GAAG,MAAM,CAEzE;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,8BAA8B,GACtC,+BAA+B,CAejC;AAED,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,eAAe,EAC3B,aAAa,EAAE,MAAM,EACrB,aAAa,EAAE,SAAS,MAAM,EAAE,GAC/B,eAAe,CA4BjB;AAED,wBAAgB,kCAAkC,CAChD,UAAU,EAAE,eAAe,GAC1B,SAAS,kBAAkB,EAAE,CAkB/B"}
@@ -95,6 +95,10 @@ export function buildGovernedHandoffEvidence(handoff) {
95
95
  evidenceAtomCount: handoff.request.patchScope.evidenceAtomIds.length,
96
96
  expectedChecks: [...handoff.request.patchScope.expectedChecks],
97
97
  approvalTokenHash: sha256Hex(handoff.request.userApprovalToken),
98
+ // Additive-optional: the text path passes no `voiceAction`, so the field stays absent and the emitted
99
+ // evidence is byte-identical to the pre-#503 shape. A voice-originated handoff threads its content-free
100
+ // audit record here.
101
+ ...(handoff.voiceAction === undefined ? {} : { voiceAction: handoff.voiceAction }),
98
102
  };
99
103
  }
100
104
  export function createScopedWriter(baseWriter, workspaceRoot, editablePaths) {
@@ -16,6 +16,11 @@ export declare function internalError(message: string): RouteResult;
16
16
  export declare function mappedGatewayError(error: unknown, deps: UiHandlerDeps): RouteResult | undefined;
17
17
  export declare function mappedWorkspaceError(error: unknown): RouteResult | undefined;
18
18
  export declare function isValidGroundedPack(pack: ConnectedContextPack): boolean;
19
+ export interface AskInput {
20
+ readonly chatId: string;
21
+ readonly content: string;
22
+ readonly modelId: string | undefined;
23
+ }
19
24
  export declare function deriveScopeIdFrom(chat: Chat, cs: ChatConnectedScope, index: number): string;
20
25
  export declare function buildSelectedScopeFrom(chat: Chat, cs: ChatConnectedScope, scopeId: string): SelectedScope;
21
26
  export declare function buildQuery(content: string, nowMs: () => number): RetrievalQuery;
@@ -45,5 +50,11 @@ export interface HybridSeam {
45
50
  readonly connectorRetrieve?: ConnectorRetrieve;
46
51
  readonly answer?: HybridAnswerer;
47
52
  }
53
+ export declare function runGroundedAskInput(input: AskInput, deps: UiHandlerDeps, options?: {
54
+ readonly signal?: AbortSignal | undefined;
55
+ readonly runner?: GroundedRunner | undefined;
56
+ readonly multiSource?: MultiSourceSeam | undefined;
57
+ readonly hybrid?: HybridSeam | undefined;
58
+ }): Promise<RouteResult>;
48
59
  export declare function handleGroundedAsk(ctx: RouteContext, deps: UiHandlerDeps, runner?: GroundedRunner, multiSource?: MultiSourceSeam, hybrid?: HybridSeam): Promise<RouteResult>;
49
60
  //# sourceMappingURL=grounded-qa.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"grounded-qa.d.ts","sourceRoot":"","sources":["../src/grounded-qa.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"grounded-qa.d.ts","sourceRoot":"","sources":["../src/grounded-qa.ts"],"names":[],"mappings":"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"}
@@ -877,10 +877,7 @@ async function dispatchHybridAsk(prepared, deps, skippedFolders, seam) {
877
877
  });
878
878
  }
879
879
  // ─── Public handler ───────────────────────────────────────────────────────────
880
- export async function handleGroundedAsk(ctx, deps, runner, multiSource, hybrid) {
881
- const prepared = await prepareGroundedAsk(ctx, deps);
882
- if ("status" in prepared)
883
- return prepared;
880
+ async function dispatchPreparedGroundedAsk(prepared, deps, runner, multiSource, hybrid) {
884
881
  const { chat } = prepared;
885
882
  // Epic #189 — count-based dispatch over BOTH source kinds. 0+0 → no scope. Connector-free chats
886
883
  // keep the EXISTING folder path (#532, byte-identical). A lone connector with no folders keeps the
@@ -909,3 +906,15 @@ export async function handleGroundedAsk(ctx, deps, runner, multiSource, hybrid)
909
906
  }
910
907
  return dispatchHybridAsk(preparedWithCanonicalFolders, deps, skippedFolders, hybrid);
911
908
  }
909
+ export async function runGroundedAskInput(input, deps, options = {}) {
910
+ const chat = findChatById(deps, input.chatId);
911
+ if (chat === undefined)
912
+ return notFound("Chat not found.");
913
+ return dispatchPreparedGroundedAsk({ chat, input, signal: options.signal ?? new AbortController().signal }, deps, options.runner, options.multiSource, options.hybrid);
914
+ }
915
+ export async function handleGroundedAsk(ctx, deps, runner, multiSource, hybrid) {
916
+ const prepared = await prepareGroundedAsk(ctx, deps);
917
+ if ("status" in prepared)
918
+ return prepared;
919
+ return dispatchPreparedGroundedAsk(prepared, deps, runner, multiSource, hybrid);
920
+ }
package/dist/headers.d.ts CHANGED
@@ -1,3 +1,6 @@
1
1
  import type { ServerResponse } from "node:http";
2
- export declare function applySecurityHeaders(res: ServerResponse, csp: string, isApiPath: boolean): void;
2
+ export interface SecurityHeaderOptions {
3
+ readonly allowMicrophone?: boolean | undefined;
4
+ }
5
+ export declare function applySecurityHeaders(res: ServerResponse, csp: string, isApiPath: boolean, options?: SecurityHeaderOptions): void;
3
6
  //# sourceMappingURL=headers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"headers.d.ts","sourceRoot":"","sources":["../src/headers.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAchD,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,IAAI,CAQ/F"}
1
+ {"version":3,"file":"headers.d.ts","sourceRoot":"","sources":["../src/headers.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAahD,MAAM,WAAW,qBAAqB;IAKpC,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAChD;AAUD,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,cAAc,EACnB,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,OAAO,EAClB,OAAO,GAAE,qBAA0B,GAClC,IAAI,CASN"}