salmon-loop 0.2.3

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 (655) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +144 -0
  3. package/README.zh-CN.md +144 -0
  4. package/dist/cli/argv/headless-detection.js +60 -0
  5. package/dist/cli/argv/print-mode.js +60 -0
  6. package/dist/cli/authorization/allowlist.js +908 -0
  7. package/dist/cli/authorization/non-interactive.js +166 -0
  8. package/dist/cli/authorization/provider.js +416 -0
  9. package/dist/cli/chat-interface.js +83 -0
  10. package/dist/cli/chat.js +492 -0
  11. package/dist/cli/cli-runtime-context.js +12 -0
  12. package/dist/cli/commander-error-adapter.js +35 -0
  13. package/dist/cli/commander-error-meta.js +13 -0
  14. package/dist/cli/commands/allowlist.js +270 -0
  15. package/dist/cli/commands/chat.js +120 -0
  16. package/dist/cli/commands/config.js +250 -0
  17. package/dist/cli/commands/context.js +57 -0
  18. package/dist/cli/commands/dispatcher.js +53 -0
  19. package/dist/cli/commands/exit.js +9 -0
  20. package/dist/cli/commands/llm-output.js +135 -0
  21. package/dist/cli/commands/log-mode.js +143 -0
  22. package/dist/cli/commands/mode.js +136 -0
  23. package/dist/cli/commands/new.js +18 -0
  24. package/dist/cli/commands/parallel.js +256 -0
  25. package/dist/cli/commands/queue.js +130 -0
  26. package/dist/cli/commands/registry.js +85 -0
  27. package/dist/cli/commands/restore.js +26 -0
  28. package/dist/cli/commands/run/assistant-message.js +14 -0
  29. package/dist/cli/commands/run/config-resolution.js +37 -0
  30. package/dist/cli/commands/run/early-errors.js +108 -0
  31. package/dist/cli/commands/run/execute.js +73 -0
  32. package/dist/cli/commands/run/extensions-resolution.js +22 -0
  33. package/dist/cli/commands/run/handler.js +434 -0
  34. package/dist/cli/commands/run/headless-error-writer.js +182 -0
  35. package/dist/cli/commands/run/instruction-guard.js +24 -0
  36. package/dist/cli/commands/run/loop-params.js +46 -0
  37. package/dist/cli/commands/run/mode.js +8 -0
  38. package/dist/cli/commands/run/parse-options.js +67 -0
  39. package/dist/cli/commands/run/persist-session.js +35 -0
  40. package/dist/cli/commands/run/preflight.js +156 -0
  41. package/dist/cli/commands/run/reporter-factory.js +52 -0
  42. package/dist/cli/commands/run/runtime-llm.js +56 -0
  43. package/dist/cli/commands/run/runtime-options.js +30 -0
  44. package/dist/cli/commands/run/session.js +19 -0
  45. package/dist/cli/commands/run/structured-output.js +106 -0
  46. package/dist/cli/commands/run/types.js +2 -0
  47. package/dist/cli/commands/run/validate-options.js +28 -0
  48. package/dist/cli/commands/run/verbose.js +36 -0
  49. package/dist/cli/commands/run.js +2 -0
  50. package/dist/cli/commands/serve.js +323 -0
  51. package/dist/cli/commands/session.js +77 -0
  52. package/dist/cli/commands/snapshot-interactive.js +165 -0
  53. package/dist/cli/commands/snapshot.js +159 -0
  54. package/dist/cli/commands/status.js +17 -0
  55. package/dist/cli/commands/subagent.js +178 -0
  56. package/dist/cli/commands/subcommand-suggestions.js +63 -0
  57. package/dist/cli/commands/tool-names.js +155 -0
  58. package/dist/cli/commands/types.js +2 -0
  59. package/dist/cli/commands/utils.js +42 -0
  60. package/dist/cli/config.js +16 -0
  61. package/dist/cli/crash-reporter.js +5 -0
  62. package/dist/cli/headless/anthropic-stream-normalized-encoder.js +164 -0
  63. package/dist/cli/headless/anthropic-stream-protocol.js +62 -0
  64. package/dist/cli/headless/json-protocol.js +124 -0
  65. package/dist/cli/headless/native-stream-normalized-encoder.js +206 -0
  66. package/dist/cli/headless/openai-responses-canonical-applier.js +94 -0
  67. package/dist/cli/headless/openai-responses-state.js +294 -0
  68. package/dist/cli/headless/openai-stream-encoder.js +152 -0
  69. package/dist/cli/headless/stdout-writer.js +9 -0
  70. package/dist/cli/headless/stream-json-protocol.js +136 -0
  71. package/dist/cli/index.js +8 -0
  72. package/dist/cli/locales/en.js +409 -0
  73. package/dist/cli/locales/index.js +7 -0
  74. package/dist/cli/program-bootstrap.js +14 -0
  75. package/dist/cli/program-commands.js +106 -0
  76. package/dist/cli/program-options.js +15 -0
  77. package/dist/cli/program-output-mode.js +11 -0
  78. package/dist/cli/program-parse.js +24 -0
  79. package/dist/cli/reporters/anthropic-stream.js +77 -0
  80. package/dist/cli/reporters/base.js +2 -0
  81. package/dist/cli/reporters/json.js +69 -0
  82. package/dist/cli/reporters/openai-stream.js +72 -0
  83. package/dist/cli/reporters/standard.js +226 -0
  84. package/dist/cli/reporters/stderr-log-reporter.js +71 -0
  85. package/dist/cli/reporters/stream-json.js +111 -0
  86. package/dist/cli/run-cli.js +25 -0
  87. package/dist/cli/slash/runtime.js +240 -0
  88. package/dist/cli/ui/App.js +273 -0
  89. package/dist/cli/ui/authorization/bus.js +35 -0
  90. package/dist/cli/ui/components/CommandInput.js +200 -0
  91. package/dist/cli/ui/components/CommandSuggestionList.js +20 -0
  92. package/dist/cli/ui/components/Markdown.js +423 -0
  93. package/dist/cli/ui/components/MessageList.js +34 -0
  94. package/dist/cli/ui/components/StatusBannerLine.js +7 -0
  95. package/dist/cli/ui/components/TodoDrawer.js +60 -0
  96. package/dist/cli/ui/components/WelcomeMessage.js +14 -0
  97. package/dist/cli/ui/components/animations/StretchingThinking.js +51 -0
  98. package/dist/cli/ui/components/animations/ThinkingWave.js +15 -0
  99. package/dist/cli/ui/components/animations/TypeIndicator.js +30 -0
  100. package/dist/cli/ui/components/layout/SplitPane.js +11 -0
  101. package/dist/cli/ui/components/messageList/MessageItem.js +27 -0
  102. package/dist/cli/ui/components/messageList/QueuePreviewList.js +11 -0
  103. package/dist/cli/ui/components/messageList/items/EmphasisMessageItem.js +20 -0
  104. package/dist/cli/ui/components/messageList/items/InterruptMessageItem.js +10 -0
  105. package/dist/cli/ui/components/messageList/items/LightweightMessageItem.js +12 -0
  106. package/dist/cli/ui/components/messageList/items/StandardMessageItem.js +23 -0
  107. package/dist/cli/ui/components/messageList/items/WelcomeMessageItem.js +7 -0
  108. package/dist/cli/ui/components/messageList/messageListLayout.js +27 -0
  109. package/dist/cli/ui/components/messageList/streaming.js +51 -0
  110. package/dist/cli/ui/components/messageList/types.js +2 -0
  111. package/dist/cli/ui/components/messageList/utils.js +7 -0
  112. package/dist/cli/ui/components/sidebar/FileContext.js +8 -0
  113. package/dist/cli/ui/components/sidebar/MissionControl.js +8 -0
  114. package/dist/cli/ui/config.js +59 -0
  115. package/dist/cli/ui/hooks/useCommandLifecycle.js +110 -0
  116. package/dist/cli/ui/hooks/useCommandSuggestions.js +87 -0
  117. package/dist/cli/ui/hooks/useInputHistory.js +57 -0
  118. package/dist/cli/ui/hooks/useLoopEvents.js +382 -0
  119. package/dist/cli/ui/hooks/useLoopState.js +73 -0
  120. package/dist/cli/ui/hooks/useOnionExit.js +31 -0
  121. package/dist/cli/ui/hooks/useTerminalDimensions.js +34 -0
  122. package/dist/cli/ui/index.js +136 -0
  123. package/dist/cli/ui/selection/bus.js +35 -0
  124. package/dist/cli/ui/status/formatStatusBanner.js +8 -0
  125. package/dist/cli/ui/store/context.js +17 -0
  126. package/dist/cli/ui/store/reducer.js +264 -0
  127. package/dist/cli/ui/store/types.js +81 -0
  128. package/dist/cli/ui/styles/theme.js +295 -0
  129. package/dist/cli/ui/types.js +2 -0
  130. package/dist/cli/ui/utils/sanitizer.js +122 -0
  131. package/dist/cli/ui/utils/transcript.js +28 -0
  132. package/dist/cli/utils/asyncQueue.js +125 -0
  133. package/dist/cli/utils/audit-scope.js +10 -0
  134. package/dist/cli/utils/detectors/index.js +38 -0
  135. package/dist/cli/utils/llm-output.js +34 -0
  136. package/dist/cli/utils/outcome-reporter.js +17 -0
  137. package/dist/cli/utils/safe-fs.js +184 -0
  138. package/dist/cli/utils/verify-resolver.js +34 -0
  139. package/dist/cli/utils/worktree-prepare-resolver.js +18 -0
  140. package/dist/core/adapters/fs/atomic-file-writer.js +129 -0
  141. package/dist/core/adapters/fs/file-adapter.js +95 -0
  142. package/dist/core/adapters/fs/filesystem.js +31 -0
  143. package/dist/core/adapters/fs/index.js +5 -0
  144. package/dist/core/adapters/fs/node-fs.js +7 -0
  145. package/dist/core/adapters/fs/readonly-filesystem.js +23 -0
  146. package/dist/core/adapters/git/git-adapter.js +704 -0
  147. package/dist/core/adapters/git/git-runner.js +119 -0
  148. package/dist/core/adapters/git/lock-manager.js +314 -0
  149. package/dist/core/adapters/git/types.js +2 -0
  150. package/dist/core/adapters/path/index.js +2 -0
  151. package/dist/core/adapters/path/path-adapter.js +23 -0
  152. package/dist/core/ast/guard.js +116 -0
  153. package/dist/core/ast/index.js +4 -0
  154. package/dist/core/ast/parser.js +284 -0
  155. package/dist/core/ast/validator.js +46 -0
  156. package/dist/core/backends/salmon-loop/task-executor.js +68 -0
  157. package/dist/core/checkpoint-domain/manifest-store.js +379 -0
  158. package/dist/core/checkpoint-domain/service.js +84 -0
  159. package/dist/core/checkpoint-domain/types.js +2 -0
  160. package/dist/core/config/defaults.js +50 -0
  161. package/dist/core/config/errors.js +11 -0
  162. package/dist/core/config/file-format.js +108 -0
  163. package/dist/core/config/index.js +7 -0
  164. package/dist/core/config/limits.js +77 -0
  165. package/dist/core/config/load.js +34 -0
  166. package/dist/core/config/normalize.js +35 -0
  167. package/dist/core/config/paths.js +20 -0
  168. package/dist/core/config/redact.js +16 -0
  169. package/dist/core/config/resolve-env.js +43 -0
  170. package/dist/core/config/resolve-llm.js +130 -0
  171. package/dist/core/config/resolve.js +68 -0
  172. package/dist/core/config/resolvers/ast-validation.js +8 -0
  173. package/dist/core/config/resolvers/context.js +21 -0
  174. package/dist/core/config/resolvers/observability.js +45 -0
  175. package/dist/core/config/resolvers/output.js +8 -0
  176. package/dist/core/config/resolvers/permission-mode.js +6 -0
  177. package/dist/core/config/resolvers/security.js +14 -0
  178. package/dist/core/config/resolvers/server.js +36 -0
  179. package/dist/core/config/resolvers/tool-authorization.js +39 -0
  180. package/dist/core/config/resolvers/ui.js +26 -0
  181. package/dist/core/config/types/config-file.js +2 -0
  182. package/dist/core/config/types/primitives.js +9 -0
  183. package/dist/core/config/types/resolved.js +2 -0
  184. package/dist/core/config/types.js +4 -0
  185. package/dist/core/config/validate.js +852 -0
  186. package/dist/core/context/assembly/default-prompt-assembler.js +7 -0
  187. package/dist/core/context/assembly/prompt-assembler.js +2 -0
  188. package/dist/core/context/ast/import-extractor.js +28 -0
  189. package/dist/core/context/ast/module-resolver.js +61 -0
  190. package/dist/core/context/ast/source-outline.js +25 -0
  191. package/dist/core/context/audit-constants.js +23 -0
  192. package/dist/core/context/audit.js +54 -0
  193. package/dist/core/context/budget/dynamic-adjuster.js +149 -0
  194. package/dist/core/context/budget/example-integration.js +49 -0
  195. package/dist/core/context/budget/integration.js +93 -0
  196. package/dist/core/context/builder.js +289 -0
  197. package/dist/core/context/cache/errors.js +16 -0
  198. package/dist/core/context/cache/incremental-updater.js +131 -0
  199. package/dist/core/context/cache/index.js +25 -0
  200. package/dist/core/context/cache/path-resolver.js +127 -0
  201. package/dist/core/context/cache/prompt-caching.js +207 -0
  202. package/dist/core/context/cache/store-factory.js +63 -0
  203. package/dist/core/context/cache/store.js +193 -0
  204. package/dist/core/context/cache/types.js +15 -0
  205. package/dist/core/context/compression/js-like-comments.js +139 -0
  206. package/dist/core/context/compression/smart-compress.js +61 -0
  207. package/dist/core/context/compression/whitespace.js +26 -0
  208. package/dist/core/context/dependencies.js +102 -0
  209. package/dist/core/context/effectiveness/index.js +25 -0
  210. package/dist/core/context/effectiveness/tracker.js +253 -0
  211. package/dist/core/context/effectiveness/types.js +15 -0
  212. package/dist/core/context/formatters/index.js +7 -0
  213. package/dist/core/context/formatters/json-converter.js +662 -0
  214. package/dist/core/context/formatters/types.js +6 -0
  215. package/dist/core/context/formatters/xml-context.js +296 -0
  216. package/dist/core/context/gatherers/architecture-gatherer.js +75 -0
  217. package/dist/core/context/gatherers/artifact-gatherer.js +53 -0
  218. package/dist/core/context/gatherers/ast-gatherer.js +370 -0
  219. package/dist/core/context/gatherers/ghost-dependency-gatherer.js +46 -0
  220. package/dist/core/context/gatherers/git-diff-gatherer.js +91 -0
  221. package/dist/core/context/gatherers/git-history-gatherer.js +57 -0
  222. package/dist/core/context/gatherers/knowledge-gatherer.js +101 -0
  223. package/dist/core/context/gatherers/metadata-gatherer.js +59 -0
  224. package/dist/core/context/gatherers/primary-text-gatherer.js +36 -0
  225. package/dist/core/context/gatherers/ripgrep-gatherer.js +104 -0
  226. package/dist/core/context/hash.js +52 -0
  227. package/dist/core/context/index.js +3 -0
  228. package/dist/core/context/keywords.js +179 -0
  229. package/dist/core/context/policies/budget-policy.js +36 -0
  230. package/dist/core/context/policies/pack-until-full.js +419 -0
  231. package/dist/core/context/scoring/relevance.js +191 -0
  232. package/dist/core/context/service-deps.js +32 -0
  233. package/dist/core/context/service-helpers.js +32 -0
  234. package/dist/core/context/service.js +265 -0
  235. package/dist/core/context/steps/context-budget.js +157 -0
  236. package/dist/core/context/steps/context-gather.js +71 -0
  237. package/dist/core/context/steps/context-primary.js +19 -0
  238. package/dist/core/context/steps/context-promotion.js +78 -0
  239. package/dist/core/context/steps/context-targets.js +85 -0
  240. package/dist/core/context/steps/types.js +2 -0
  241. package/dist/core/context/summarization/index.js +27 -0
  242. package/dist/core/context/summarization/prompts.js +80 -0
  243. package/dist/core/context/summarization/summarizer.js +377 -0
  244. package/dist/core/context/summarization/types.js +29 -0
  245. package/dist/core/context/targeting/churn-policy.js +27 -0
  246. package/dist/core/context/targeting/target-resolver.js +491 -0
  247. package/dist/core/context/token/adaptive-budget.js +364 -0
  248. package/dist/core/context/token/cache.js +163 -0
  249. package/dist/core/context/token/counter.js +190 -0
  250. package/dist/core/context/token/encoding-registry.js +173 -0
  251. package/dist/core/context/token/index.js +31 -0
  252. package/dist/core/context/token/token-budget.js +213 -0
  253. package/dist/core/context/token/types.js +10 -0
  254. package/dist/core/context/truncation/index.js +23 -0
  255. package/dist/core/context/truncation/semantic-truncator.js +103 -0
  256. package/dist/core/context/truncation/strategies/error-stack.js +94 -0
  257. package/dist/core/context/truncation/strategies/generic.js +48 -0
  258. package/dist/core/context/truncation/strategies/git-diff.js +99 -0
  259. package/dist/core/context/truncation/strategies/index.js +10 -0
  260. package/dist/core/context/truncation/strategies/json.js +142 -0
  261. package/dist/core/context/truncation/strategies/log.js +131 -0
  262. package/dist/core/context/truncation/strategies/test-result.js +140 -0
  263. package/dist/core/context/truncation/type-detector.js +133 -0
  264. package/dist/core/context/truncation/types.js +16 -0
  265. package/dist/core/context/types.js +2 -0
  266. package/dist/core/extensions/index.js +118 -0
  267. package/dist/core/extensions/load.js +36 -0
  268. package/dist/core/extensions/merge.js +29 -0
  269. package/dist/core/extensions/paths.js +40 -0
  270. package/dist/core/extensions/redact.js +37 -0
  271. package/dist/core/extensions/schemas.js +70 -0
  272. package/dist/core/extensions/types.js +2 -0
  273. package/dist/core/facades/cli-authorization-allowlist.js +3 -0
  274. package/dist/core/facades/cli-authorization-non-interactive.js +3 -0
  275. package/dist/core/facades/cli-authorization-provider.js +2 -0
  276. package/dist/core/facades/cli-chat.js +11 -0
  277. package/dist/core/facades/cli-command-allowlist.js +3 -0
  278. package/dist/core/facades/cli-command-chat.js +8 -0
  279. package/dist/core/facades/cli-command-checkpoint.js +3 -0
  280. package/dist/core/facades/cli-command-config.js +10 -0
  281. package/dist/core/facades/cli-command-dispatcher.js +2 -0
  282. package/dist/core/facades/cli-command-parallel.js +8 -0
  283. package/dist/core/facades/cli-command-session.js +2 -0
  284. package/dist/core/facades/cli-command-tool-names.js +6 -0
  285. package/dist/core/facades/cli-context.js +8 -0
  286. package/dist/core/facades/cli-headless.js +3 -0
  287. package/dist/core/facades/cli-observability.js +3 -0
  288. package/dist/core/facades/cli-program-bootstrap.js +2 -0
  289. package/dist/core/facades/cli-reporters.js +5 -0
  290. package/dist/core/facades/cli-run-execute.js +3 -0
  291. package/dist/core/facades/cli-run-handler.js +7 -0
  292. package/dist/core/facades/cli-run-headless-error-writer.js +2 -0
  293. package/dist/core/facades/cli-run-loop-params.js +2 -0
  294. package/dist/core/facades/cli-run-persist-session.js +2 -0
  295. package/dist/core/facades/cli-run-runtime-llm.js +5 -0
  296. package/dist/core/facades/cli-serve.js +21 -0
  297. package/dist/core/facades/cli-slash-runtime.js +9 -0
  298. package/dist/core/facades/cli-subagent.js +2 -0
  299. package/dist/core/facades/cli-ui.js +5 -0
  300. package/dist/core/facades/cli-utils-llm-output.js +3 -0
  301. package/dist/core/facades/cli-utils-path.js +2 -0
  302. package/dist/core/facades/cli-utils-worktree.js +2 -0
  303. package/dist/core/failure/diagnostics.js +221 -0
  304. package/dist/core/feedback/index.js +28 -0
  305. package/dist/core/feedback/parsers.js +59 -0
  306. package/dist/core/feedback/patterns.js +26 -0
  307. package/dist/core/feedback/types.js +2 -0
  308. package/dist/core/grizzco/domain/grizzco-types.js +41 -0
  309. package/dist/core/grizzco/dsl/DecisionEngine.js +149 -0
  310. package/dist/core/grizzco/dsl/MicroTaskRunner.js +39 -0
  311. package/dist/core/grizzco/dsl/llm-strategy.js +80 -0
  312. package/dist/core/grizzco/dsl/strategies.js +69 -0
  313. package/dist/core/grizzco/dsl/types.js +2 -0
  314. package/dist/core/grizzco/engine/observability/event-adapter.js +41 -0
  315. package/dist/core/grizzco/engine/observability/index.js +3 -0
  316. package/dist/core/grizzco/engine/observability/loop-telemetry.js +51 -0
  317. package/dist/core/grizzco/engine/outcome/index.js +2 -0
  318. package/dist/core/grizzco/engine/outcome/loop-result-mapper.js +167 -0
  319. package/dist/core/grizzco/engine/pipeline/pipeline.js +335 -0
  320. package/dist/core/grizzco/engine/pipeline/types.js +2 -0
  321. package/dist/core/grizzco/engine/transaction/attempt-failure.js +242 -0
  322. package/dist/core/grizzco/engine/transaction/authorization-summary.js +44 -0
  323. package/dist/core/grizzco/engine/transaction/index.js +3 -0
  324. package/dist/core/grizzco/engine/transaction/report-mapper.js +50 -0
  325. package/dist/core/grizzco/engine/transaction/retry-policy.js +19 -0
  326. package/dist/core/grizzco/engine/transaction/runner-builder.js +45 -0
  327. package/dist/core/grizzco/engine/transaction/session.js +58 -0
  328. package/dist/core/grizzco/engine/transaction/transaction-runner.js +193 -0
  329. package/dist/core/grizzco/engine/transaction/types.js +2 -0
  330. package/dist/core/grizzco/execution/Executor.js +58 -0
  331. package/dist/core/grizzco/execution/RejectionManager.js +71 -0
  332. package/dist/core/grizzco/execution/WorkerFactory.js +31 -0
  333. package/dist/core/grizzco/flows/SalmonLoopFlow.js +102 -0
  334. package/dist/core/grizzco/runtime/apply-back-runtime.js +136 -0
  335. package/dist/core/grizzco/runtime/apply-back-utils.js +13 -0
  336. package/dist/core/grizzco/runtime/host/host-runner.js +99 -0
  337. package/dist/core/grizzco/runtime/host/index.js +2 -0
  338. package/dist/core/grizzco/runtime/host/types.js +2 -0
  339. package/dist/core/grizzco/services/CachedService.js +42 -0
  340. package/dist/core/grizzco/services/implementations/default/GitConfigService.js +38 -0
  341. package/dist/core/grizzco/services/implementations/mock/MockLockService.js +11 -0
  342. package/dist/core/grizzco/services/implementations/mock/MockUserQuotaService.js +11 -0
  343. package/dist/core/grizzco/services/registry.js +30 -0
  344. package/dist/core/grizzco/services/types.js +2 -0
  345. package/dist/core/grizzco/steps/answer.js +75 -0
  346. package/dist/core/grizzco/steps/apply-back.js +46 -0
  347. package/dist/core/grizzco/steps/apply.js +136 -0
  348. package/dist/core/grizzco/steps/ast-validate.js +37 -0
  349. package/dist/core/grizzco/steps/audit.js +311 -0
  350. package/dist/core/grizzco/steps/context.js +74 -0
  351. package/dist/core/grizzco/steps/display-answer.js +6 -0
  352. package/dist/core/grizzco/steps/display-report.js +158 -0
  353. package/dist/core/grizzco/steps/display-research.js +6 -0
  354. package/dist/core/grizzco/steps/displayReview.js +6 -0
  355. package/dist/core/grizzco/steps/explore.js +245 -0
  356. package/dist/core/grizzco/steps/extractIssues.js +27 -0
  357. package/dist/core/grizzco/steps/generateFixPlan.js +13 -0
  358. package/dist/core/grizzco/steps/generateReview.js +71 -0
  359. package/dist/core/grizzco/steps/patch.js +220 -0
  360. package/dist/core/grizzco/steps/plan.js +191 -0
  361. package/dist/core/grizzco/steps/preflight.js +93 -0
  362. package/dist/core/grizzco/steps/prepare-deps.js +49 -0
  363. package/dist/core/grizzco/steps/read-only-shrink.js +4 -0
  364. package/dist/core/grizzco/steps/research.js +188 -0
  365. package/dist/core/grizzco/steps/rollback.js +138 -0
  366. package/dist/core/grizzco/steps/shrink.js +64 -0
  367. package/dist/core/grizzco/steps/validate.js +40 -0
  368. package/dist/core/grizzco/steps/verify.js +136 -0
  369. package/dist/core/grizzco/validation/AstValidationService.js +133 -0
  370. package/dist/core/grizzco/validation/ContextValidator.js +17 -0
  371. package/dist/core/grizzco/validation/ast-validation-policy.js +11 -0
  372. package/dist/core/grizzco/workers/direct-write-worker.js +44 -0
  373. package/dist/core/grizzco/workers/git-apply-worker.js +75 -0
  374. package/dist/core/grizzco/workers/i-merge-worker.js +2 -0
  375. package/dist/core/grizzco/workers/mm-three-way-worker.js +117 -0
  376. package/dist/core/grizzco/workers/no-op-worker.js +18 -0
  377. package/dist/core/grizzco/workers/overwrite-binary-worker.js +29 -0
  378. package/dist/core/grizzco/workers/strata-sync-worker.js +69 -0
  379. package/dist/core/grizzco/workers/three-way-merge-worker.js +84 -0
  380. package/dist/core/grizzco/workers/three-way-staged-worker.js +93 -0
  381. package/dist/core/grizzco/workers/union-merge-worker.js +71 -0
  382. package/dist/core/history/input-history.js +55 -0
  383. package/dist/core/intent/chat-intent.js +250 -0
  384. package/dist/core/interaction/events/bus.js +52 -0
  385. package/dist/core/interaction/model/events.js +2 -0
  386. package/dist/core/interaction/model/index.js +3 -0
  387. package/dist/core/interaction/model/task-state.js +9 -0
  388. package/dist/core/interaction/model/transition-policy.js +50 -0
  389. package/dist/core/interaction/model/types.js +2 -0
  390. package/dist/core/interaction/orchestration/facade.js +190 -0
  391. package/dist/core/interaction/orchestration/index.js +2 -0
  392. package/dist/core/interaction/orchestration/store.js +32 -0
  393. package/dist/core/interaction/sync/task-sync-engine.js +57 -0
  394. package/dist/core/interaction/turn-stop-reason.js +27 -0
  395. package/dist/core/language-support/index.js +3 -0
  396. package/dist/core/language-support/orchestrator.js +37 -0
  397. package/dist/core/language-support/strategies/extension-candidate-strategy.js +27 -0
  398. package/dist/core/language-support/strategies/index.js +3 -0
  399. package/dist/core/language-support/strategies/language-query-strategy.js +26 -0
  400. package/dist/core/llm/ai-sdk/chat-executor.js +88 -0
  401. package/dist/core/llm/ai-sdk/langfuse-headers.js +28 -0
  402. package/dist/core/llm/ai-sdk/message-mapper.js +240 -0
  403. package/dist/core/llm/ai-sdk/observation-context.js +16 -0
  404. package/dist/core/llm/ai-sdk/provider-factory.js +29 -0
  405. package/dist/core/llm/ai-sdk/request-params.js +18 -0
  406. package/dist/core/llm/ai-sdk/request-runtime.js +168 -0
  407. package/dist/core/llm/ai-sdk/result-mapper.js +31 -0
  408. package/dist/core/llm/ai-sdk/retry-classifier.js +82 -0
  409. package/dist/core/llm/ai-sdk/retry-executor.js +38 -0
  410. package/dist/core/llm/ai-sdk.js +92 -0
  411. package/dist/core/llm/audit.js +2 -0
  412. package/dist/core/llm/base-url.js +18 -0
  413. package/dist/core/llm/contracts/repair.js +68 -0
  414. package/dist/core/llm/errors.js +172 -0
  415. package/dist/core/llm/factory.js +21 -0
  416. package/dist/core/llm/http/index.js +2 -0
  417. package/dist/core/llm/index.js +6 -0
  418. package/dist/core/llm/message-composition.js +25 -0
  419. package/dist/core/llm/openai.js +69 -0
  420. package/dist/core/llm/output-policy.js +192 -0
  421. package/dist/core/llm/phase-router.js +55 -0
  422. package/dist/core/llm/redact.js +37 -0
  423. package/dist/core/llm/registry.js +81 -0
  424. package/dist/core/llm/retry-utils.js +114 -0
  425. package/dist/core/llm/stream-utils.js +87 -0
  426. package/dist/core/llm/utils.js +82 -0
  427. package/dist/core/observability/audit-file.js +199 -0
  428. package/dist/core/observability/audit-trail.js +125 -0
  429. package/dist/core/observability/authorization-decisions.js +54 -0
  430. package/dist/core/observability/debug-artifacts.js +61 -0
  431. package/dist/core/observability/error-envelope.js +63 -0
  432. package/dist/core/observability/error-mapping.js +271 -0
  433. package/dist/core/observability/ignored-error.js +6 -0
  434. package/dist/core/observability/logger.js +457 -0
  435. package/dist/core/observability/loop-event-reporter.js +46 -0
  436. package/dist/core/observability/monitor.js +240 -0
  437. package/dist/core/observability/run-outcome-reporter.js +15 -0
  438. package/dist/core/observability/token-usage.js +36 -0
  439. package/dist/core/observability/ui-log-sanitize.js +35 -0
  440. package/dist/core/patch/aggregator.js +93 -0
  441. package/dist/core/patch/diff.js +298 -0
  442. package/dist/core/permission-gate/default-gate.js +115 -0
  443. package/dist/core/permission-gate/gate.js +2 -0
  444. package/dist/core/permission-gate/types.js +2 -0
  445. package/dist/core/plan/index.js +2 -0
  446. package/dist/core/plan/manager.js +123 -0
  447. package/dist/core/plan/markdown-editor.js +238 -0
  448. package/dist/core/plan/storage.js +75 -0
  449. package/dist/core/plan/types.js +2 -0
  450. package/dist/core/plugin/interface.js +2 -0
  451. package/dist/core/plugin/loader.js +130 -0
  452. package/dist/core/plugin/registry.js +90 -0
  453. package/dist/core/plugin/validator.js +98 -0
  454. package/dist/core/prompts/registry.js +189 -0
  455. package/dist/core/prompts/runtime.js +69 -0
  456. package/dist/core/prompts/schema.js +2 -0
  457. package/dist/core/prompts/templates/phases/explore_user.hbs +26 -0
  458. package/dist/core/prompts/templates/phases/patch_user.hbs +57 -0
  459. package/dist/core/prompts/templates/phases/plan_user.hbs +33 -0
  460. package/dist/core/prompts/templates/system/_context_json_legend.hbs +21 -0
  461. package/dist/core/prompts/templates/system/_tool_defs.hbs +60 -0
  462. package/dist/core/prompts/templates/system/explore_system.hbs +26 -0
  463. package/dist/core/prompts/templates/system/main_system.hbs +18 -0
  464. package/dist/core/prompts/templates/system/patch_system.hbs +10 -0
  465. package/dist/core/prompts/templates/system/plan_system.hbs +1 -0
  466. package/dist/core/prompts/templates/system/reflection.hbs +39 -0
  467. package/dist/core/protocols/a2a/agent-card.js +30 -0
  468. package/dist/core/protocols/a2a/mapper.js +14 -0
  469. package/dist/core/protocols/a2a/sdk/auth-middleware.js +31 -0
  470. package/dist/core/protocols/a2a/sdk/executor.js +301 -0
  471. package/dist/core/protocols/a2a/sdk/server.js +24 -0
  472. package/dist/core/protocols/a2a/task-projection.js +45 -0
  473. package/dist/core/protocols/acp/acp-command-runner.js +204 -0
  474. package/dist/core/protocols/acp/acp-filesystem.js +43 -0
  475. package/dist/core/protocols/acp/checkpoint-meta.js +2 -0
  476. package/dist/core/protocols/acp/formal-agent.js +1201 -0
  477. package/dist/core/protocols/acp/handlers.js +51 -0
  478. package/dist/core/protocols/acp/permission-provider.js +122 -0
  479. package/dist/core/protocols/acp/stdio-server.js +116 -0
  480. package/dist/core/reflection/engine.js +55 -0
  481. package/dist/core/reflection/types.js +2 -0
  482. package/dist/core/runtime/agent-server-runtime.js +88 -0
  483. package/dist/core/runtime/bun-runtime.js +26 -0
  484. package/dist/core/runtime/command-runner-context.js +16 -0
  485. package/dist/core/runtime/exit-codes.js +11 -0
  486. package/dist/core/runtime/fastify-fetch-bridge.js +51 -0
  487. package/dist/core/runtime/fastify-server-bundle.js +26 -0
  488. package/dist/core/runtime/initialize.js +132 -0
  489. package/dist/core/runtime/loop-finalize.js +71 -0
  490. package/dist/core/runtime/loop-run-lifecycle.js +73 -0
  491. package/dist/core/runtime/loop-run-reporter.js +19 -0
  492. package/dist/core/runtime/loop-runtime-config.js +26 -0
  493. package/dist/core/runtime/loop-session-runner.js +30 -0
  494. package/dist/core/runtime/loop.js +84 -0
  495. package/dist/core/runtime/paths.js +84 -0
  496. package/dist/core/runtime/process-runner.js +16 -0
  497. package/dist/core/runtime/process-types.js +2 -0
  498. package/dist/core/runtime/semaphore.js +41 -0
  499. package/dist/core/runtime/sidecar-fastify-plugin.js +35 -0
  500. package/dist/core/runtime/sidecar-paths.js +47 -0
  501. package/dist/core/runtime/sidecar-route-catalog.js +103 -0
  502. package/dist/core/runtime/spawn-command.js +392 -0
  503. package/dist/core/runtime/spawn-interactive.js +71 -0
  504. package/dist/core/security/redaction.js +160 -0
  505. package/dist/core/session/compression.js +323 -0
  506. package/dist/core/session/flow.js +85 -0
  507. package/dist/core/session/manager.js +313 -0
  508. package/dist/core/session/pruning-strategy.js +153 -0
  509. package/dist/core/session/session-context-builder.js +122 -0
  510. package/dist/core/session/summary-sync.js +82 -0
  511. package/dist/core/session/token-tracker.js +82 -0
  512. package/dist/core/session/types.js +2 -0
  513. package/dist/core/skills/bridge.js +33 -0
  514. package/dist/core/skills/index.js +8 -0
  515. package/dist/core/skills/loader.js +80 -0
  516. package/dist/core/skills/parser.js +66 -0
  517. package/dist/core/skills/runtime/MicroTaskRunner.js +102 -0
  518. package/dist/core/skills/runtime/SkillRunner.js +108 -0
  519. package/dist/core/skills/strategy.js +29 -0
  520. package/dist/core/skills/types.js +2 -0
  521. package/dist/core/slash/index.js +6 -0
  522. package/dist/core/slash/parser.js +33 -0
  523. package/dist/core/slash/registry.js +78 -0
  524. package/dist/core/slash/router.js +76 -0
  525. package/dist/core/slash/steps/slash-decide.js +19 -0
  526. package/dist/core/slash/steps/slash-execute.js +73 -0
  527. package/dist/core/slash/steps/types.js +2 -0
  528. package/dist/core/slash/strategy.js +33 -0
  529. package/dist/core/slash/types.js +2 -0
  530. package/dist/core/strata/checkpoint/manager.js +492 -0
  531. package/dist/core/strata/checkpoint/snapshot-audit.js +88 -0
  532. package/dist/core/strata/checkpoint/snapshot-create.js +79 -0
  533. package/dist/core/strata/checkpoint/snapshot-write-tree.js +72 -0
  534. package/dist/core/strata/engine/shadow-merge-engine.js +394 -0
  535. package/dist/core/strata/index.js +15 -0
  536. package/dist/core/strata/interaction/content-guardian.js +59 -0
  537. package/dist/core/strata/interaction/file-system-provider.js +89 -0
  538. package/dist/core/strata/layers/file-state-resolver.js +157 -0
  539. package/dist/core/strata/layers/immutable-git-layer.js +42 -0
  540. package/dist/core/strata/layers/shadow-driver/copy-backend.js +114 -0
  541. package/dist/core/strata/layers/shadow-driver/env.js +29 -0
  542. package/dist/core/strata/layers/shadow-driver/error-classifier.js +41 -0
  543. package/dist/core/strata/layers/shadow-driver/index.js +17 -0
  544. package/dist/core/strata/layers/shadow-driver/readonly-lock.js +221 -0
  545. package/dist/core/strata/layers/shadow-driver/shadow-driver.js +234 -0
  546. package/dist/core/strata/layers/shadow-driver/strategy.js +86 -0
  547. package/dist/core/strata/layers/sidecar-layer.js +96 -0
  548. package/dist/core/strata/layers/worktree.js +240 -0
  549. package/dist/core/strata/runtime/environment.js +377 -0
  550. package/dist/core/strata/runtime/synchronizer.js +819 -0
  551. package/dist/core/strata/types.js +46 -0
  552. package/dist/core/streaming/canonical/canonical-responses-event-emitter.js +326 -0
  553. package/dist/core/streaming/canonical/function-call-item-id.js +13 -0
  554. package/dist/core/streaming/canonical/parts-from-llm-stream-chunk.js +54 -0
  555. package/dist/core/streaming/canonical/responses-event-emitter.js +127 -0
  556. package/dist/core/streaming/canonical/responses-events.js +2 -0
  557. package/dist/core/streaming/normalized-events.js +9 -0
  558. package/dist/core/streaming/normalized-from-text.js +47 -0
  559. package/dist/core/streaming/stream-assembler.js +347 -0
  560. package/dist/core/structured-output/index.js +3 -0
  561. package/dist/core/structured-output/json-extract.js +70 -0
  562. package/dist/core/structured-output/json-schema-validator.js +90 -0
  563. package/dist/core/structured-output/types.js +2 -0
  564. package/dist/core/sub-agent/artifacts/store.js +141 -0
  565. package/dist/core/sub-agent/artifacts/types.js +2 -0
  566. package/dist/core/sub-agent/controller.js +69 -0
  567. package/dist/core/sub-agent/core/loop.js +79 -0
  568. package/dist/core/sub-agent/core/manager.js +246 -0
  569. package/dist/core/sub-agent/registry-defaults.js +52 -0
  570. package/dist/core/sub-agent/registry.js +35 -0
  571. package/dist/core/sub-agent/tools/task-spawn.js +29 -0
  572. package/dist/core/sub-agent/types.js +23 -0
  573. package/dist/core/target-runtime/command-resolver.js +42 -0
  574. package/dist/core/target-runtime/index.js +3 -0
  575. package/dist/core/target-runtime/profile.js +73 -0
  576. package/dist/core/testgen/detector.js +17 -0
  577. package/dist/core/testgen/index.js +38 -0
  578. package/dist/core/testgen/templates.js +46 -0
  579. package/dist/core/tools/audit.js +140 -0
  580. package/dist/core/tools/authorization/types.js +2 -0
  581. package/dist/core/tools/budget.js +118 -0
  582. package/dist/core/tools/builtin/artifact.js +29 -0
  583. package/dist/core/tools/builtin/ast-grep.js +107 -0
  584. package/dist/core/tools/builtin/ast.js +62 -0
  585. package/dist/core/tools/builtin/code-search/backends/powershell.js +84 -0
  586. package/dist/core/tools/builtin/code-search/backends/rg.js +85 -0
  587. package/dist/core/tools/builtin/code-search/executor.js +87 -0
  588. package/dist/core/tools/builtin/code-search/parse/plain-grep.js +59 -0
  589. package/dist/core/tools/builtin/code-search/parse/rg-json.js +31 -0
  590. package/dist/core/tools/builtin/code-search/spec.js +82 -0
  591. package/dist/core/tools/builtin/fs.js +243 -0
  592. package/dist/core/tools/builtin/git.js +118 -0
  593. package/dist/core/tools/builtin/index.js +80 -0
  594. package/dist/core/tools/builtin/interaction.js +120 -0
  595. package/dist/core/tools/builtin/knowledge.js +98 -0
  596. package/dist/core/tools/builtin/plan.js +148 -0
  597. package/dist/core/tools/builtin/proposal.js +207 -0
  598. package/dist/core/tools/builtin/shell.js +71 -0
  599. package/dist/core/tools/builtin/verify.js +41 -0
  600. package/dist/core/tools/capability/executor.js +84 -0
  601. package/dist/core/tools/capability/runner.js +50 -0
  602. package/dist/core/tools/capability/types.js +2 -0
  603. package/dist/core/tools/dispatcher.js +80 -0
  604. package/dist/core/tools/headless-payload.js +37 -0
  605. package/dist/core/tools/loader.js +100 -0
  606. package/dist/core/tools/mapper.js +142 -0
  607. package/dist/core/tools/mcp/client.js +308 -0
  608. package/dist/core/tools/mcp/loader.js +110 -0
  609. package/dist/core/tools/mcp/schema.js +54 -0
  610. package/dist/core/tools/mcp/streamable-http.js +101 -0
  611. package/dist/core/tools/mcp/types.js +26 -0
  612. package/dist/core/tools/parallel/isolation.js +25 -0
  613. package/dist/core/tools/parallel/lock-manager.js +124 -0
  614. package/dist/core/tools/parallel/persistence.js +126 -0
  615. package/dist/core/tools/parallel/plan-builder.js +66 -0
  616. package/dist/core/tools/parallel/plan.js +2 -0
  617. package/dist/core/tools/parallel/refs.js +7 -0
  618. package/dist/core/tools/parallel/resolve-args.js +50 -0
  619. package/dist/core/tools/parallel/resource-helpers.js +35 -0
  620. package/dist/core/tools/parallel/resources.js +2 -0
  621. package/dist/core/tools/parallel/scheduler.js +372 -0
  622. package/dist/core/tools/parser.js +89 -0
  623. package/dist/core/tools/permissions/permission-rules.js +503 -0
  624. package/dist/core/tools/plugins/loader.js +102 -0
  625. package/dist/core/tools/policy.js +87 -0
  626. package/dist/core/tools/registry.js +29 -0
  627. package/dist/core/tools/router.js +514 -0
  628. package/dist/core/tools/sanitize.js +78 -0
  629. package/dist/core/tools/schema-utils.js +71 -0
  630. package/dist/core/tools/session.js +1105 -0
  631. package/dist/core/tools/streaming/ToolCallAccumulator.js +64 -0
  632. package/dist/core/tools/types.js +2 -0
  633. package/dist/core/types/authorization.js +2 -0
  634. package/dist/core/types/context.js +2 -0
  635. package/dist/core/types/errors.js +29 -0
  636. package/dist/core/types/execution.js +65 -0
  637. package/dist/core/types/index.js +9 -0
  638. package/dist/core/types/llm.js +9 -0
  639. package/dist/core/types/loop.js +2 -0
  640. package/dist/core/types/planning.js +2 -0
  641. package/dist/core/types/runtime.js +2 -0
  642. package/dist/core/types/usage.js +2 -0
  643. package/dist/core/ui/kaomoji.js +5 -0
  644. package/dist/core/utils/path.js +116 -0
  645. package/dist/core/utils/platform-shell.js +10 -0
  646. package/dist/core/utils/sanitizer.js +107 -0
  647. package/dist/core/verification/runner.js +265 -0
  648. package/dist/integrations/langfuse/litellm-langfuse-outcome-reporter.js +272 -0
  649. package/dist/integrations/langfuse/outcome-proxy.js +68 -0
  650. package/dist/interfaces/cli/task-runner.js +11 -0
  651. package/dist/languages/typescript/index.js +178 -0
  652. package/dist/locales/en.js +679 -0
  653. package/dist/locales/index.js +11 -0
  654. package/dist/utils/eol.js +35 -0
  655. package/package.json +153 -0
@@ -0,0 +1,704 @@
1
+ import { randomBytes } from 'crypto';
2
+ import { realpathSync } from 'fs';
3
+ import { promises as fs } from 'fs';
4
+ import { tmpdir } from 'os';
5
+ import * as path from 'path';
6
+ import { text } from '../../../locales/index.js';
7
+ import { LIMITS } from '../../config/limits.js';
8
+ import { logIgnoredError } from '../../observability/ignored-error.js';
9
+ import { getLogger } from '../../observability/logger.js';
10
+ import { GitError } from '../../types/index.js';
11
+ import { isPathWithinDirectory, normalizePath } from '../../utils/path.js';
12
+ import { runGitCommand } from './git-runner.js';
13
+ import { FileHandleManager } from './lock-manager.js';
14
+ // Singleton map to ensure one lock manager per repository path
15
+ const lockManagers = new Map();
16
+ function getLockManager(repoPath) {
17
+ if (!lockManagers.has(repoPath)) {
18
+ lockManagers.set(repoPath, new FileHandleManager());
19
+ }
20
+ return lockManagers.get(repoPath);
21
+ }
22
+ function isShaLike(value) {
23
+ return /^[0-9a-f]{7,40}$/i.test(value);
24
+ }
25
+ function splitPathsByCharBudget(baseArgs, paths, maxChars) {
26
+ const batches = [];
27
+ let current = [];
28
+ const baseLen = baseArgs.reduce((sum, a) => sum + a.length + 1, 0);
29
+ let currentLen = baseLen;
30
+ for (const p of paths) {
31
+ const addLen = p.length + 1;
32
+ if (current.length > 0 && currentLen + addLen > maxChars) {
33
+ batches.push(current);
34
+ current = [];
35
+ currentLen = baseLen;
36
+ }
37
+ current.push(p);
38
+ currentLen += addLen;
39
+ }
40
+ if (current.length > 0)
41
+ batches.push(current);
42
+ return batches;
43
+ }
44
+ function joinNulTerminated(values) {
45
+ // Git pathspec-from-file expects elements separated by NUL when --pathspec-file-nul is set.
46
+ return Buffer.from(values.join('\0') + '\0', 'utf8');
47
+ }
48
+ /**
49
+ * GitAdapter: The unified security gateway for Git interactions.
50
+ * This is the EXCLUSIVE outlet for all Git commands in the system.
51
+ */
52
+ export class GitAdapter {
53
+ repoPath;
54
+ lockManager;
55
+ constructor(repoPath) {
56
+ this.repoPath = repoPath;
57
+ this.lockManager = getLockManager(repoPath);
58
+ }
59
+ // ==================== Base Execution Layer ====================
60
+ /**
61
+ * Low-level git execution that returns structured output without throwing.
62
+ * Prefer higher-level helpers (`exec`, `query`) unless the caller must
63
+ * inspect spawn errors (e.g., ENOENT) or truncation flags.
64
+ */
65
+ async execMeta(args, options = {}) {
66
+ return await runGitCommand({
67
+ repoRoot: this.repoPath,
68
+ args,
69
+ cwd: options.cwd,
70
+ env: options.env,
71
+ input: options.input,
72
+ timeoutMs: options.timeoutMs ?? LIMITS.gitTimeoutMs,
73
+ limits: options.limits,
74
+ });
75
+ }
76
+ /**
77
+ * Primary executor for Git commands.
78
+ * Standardizes environment, timeout, and handles machine-readable output.
79
+ */
80
+ async exec(args, options = {}) {
81
+ const res = await this.execRaw(args, options);
82
+ const output = res.stdout.toString('utf8');
83
+ return options.trim === false ? output : output.replace(/\s+$/, '');
84
+ }
85
+ /**
86
+ * Raw executor for Git commands that returns Buffers.
87
+ * Internal use only to support binary data and stdin.
88
+ */
89
+ async execRaw(args, options = {}) {
90
+ const res = await this.execMeta(args, {
91
+ cwd: options.cwd,
92
+ env: options.env,
93
+ input: options.input,
94
+ timeoutMs: options.timeoutMs,
95
+ limits: options.limits,
96
+ });
97
+ if (res.stdoutTruncated && !options.allowTruncatedStdout) {
98
+ const maxStdoutBytes = options.limits?.maxStdoutBytes;
99
+ const safeMaxBytes = typeof maxStdoutBytes === 'number' && Number.isFinite(maxStdoutBytes)
100
+ ? maxStdoutBytes
101
+ : LIMITS.maxToolOutputBytes;
102
+ throw new GitError(text.git.outputTruncated(safeMaxBytes), args.join(' '), res.stderr);
103
+ }
104
+ if (res.ok || options.allowError) {
105
+ return { stdout: res.stdout, stderr: res.stderr, code: res.code };
106
+ }
107
+ if (res.timedOut) {
108
+ throw new GitError(text.git.timeout(options.timeoutMs ?? LIMITS.gitTimeoutMs), args.join(' '), res.stderr);
109
+ }
110
+ if (res.code === 128) {
111
+ getLogger().debug(`[GitAdapter] Code 128 Debug: Args: ${args.join(' ')}\nStderr: ${res.stderr}`);
112
+ }
113
+ if (res.error?.message) {
114
+ throw new GitError(text.git.processError(res.error.message), args.join(' '), res.stderr);
115
+ }
116
+ throw new GitError(text.git.commandFailed(res.code), args.join(' '), res.stderr);
117
+ }
118
+ /**
119
+ * Execute validated Git commands with security validation.
120
+ *
121
+ * Note: Despite the historic name, this gateway is not strictly read-only.
122
+ * It allows a small set of well-scoped plumbing commands used by the
123
+ * execution model (e.g., worktree management and ref bookkeeping).
124
+ */
125
+ async query(args, options = {}) {
126
+ this.assertQueryAllowed(args);
127
+ return this.exec(args, options);
128
+ }
129
+ // ==================== Business Layer ====================
130
+ /**
131
+ * Generates a blob hash for the given content without writing to the object database.
132
+ * Useful for comparing content against git objects.
133
+ */
134
+ async hashObject(content) {
135
+ const res = await this.execRaw(['hash-object', '--stdin'], { input: content });
136
+ return res.stdout.toString('utf8').trim();
137
+ }
138
+ /**
139
+ * Updates the index with the given content.
140
+ * Uses plumbing commands (hash-object -w + update-index) to avoid touching the working tree.
141
+ */
142
+ async updateIndex(mode, hash, relativePath) {
143
+ if (!this.isShadowWorktreePath()) {
144
+ throw new GitError(text.git.indexWriteDenied, 'updateIndex', 'Index Write Denied');
145
+ }
146
+ await this.exec(['update-index', '--cacheinfo', mode, hash, relativePath]);
147
+ }
148
+ /**
149
+ * Check if a path is ignored by .gitignore rules.
150
+ * Uses check-ignore plumbing command.
151
+ */
152
+ async checkIgnore(relativePath) {
153
+ const res = await this.execRaw(['check-ignore', '-q', '--no-index', relativePath], {
154
+ allowError: true,
155
+ });
156
+ return res.code === 0;
157
+ }
158
+ async getStatus(paths) {
159
+ const base = ['status', '--porcelain=v2'];
160
+ if (!paths || paths.length === 0)
161
+ return this.exec(base);
162
+ const safePaths = this.sanitizePaths(paths);
163
+ if (safePaths.length === 0)
164
+ return this.exec(base);
165
+ const batches = splitPathsByCharBudget([...base, '--'], safePaths, LIMITS.gitArgMaxChars);
166
+ const outputs = [];
167
+ for (const batch of batches) {
168
+ outputs.push(await this.exec([...base, '--', ...batch]));
169
+ }
170
+ return outputs.join('\n').replace(/\n+$/, '');
171
+ }
172
+ /**
173
+ * Get the status of a specific path.
174
+ * Uses git status --porcelain -z -- [path] to handle special characters in filenames.
175
+ *
176
+ * @param relativePath - The relative path to check
177
+ * @returns PathStatus object or null if path is not tracked
178
+ */
179
+ async getStatusForPath(relativePath) {
180
+ const res = await this.execRaw(['status', '--porcelain', '-z', '--', relativePath], {
181
+ allowError: true,
182
+ });
183
+ // If no output, path is not tracked
184
+ if (!res.stdout || res.stdout.length === 0) {
185
+ return null;
186
+ }
187
+ const status = res.stdout.toString('utf8');
188
+ const tokens = status.split('\0').filter((token) => token.length > 0);
189
+ if (tokens.length === 0) {
190
+ return null;
191
+ }
192
+ // Parse the status codes
193
+ let staged = false;
194
+ let unstaged = false;
195
+ let untracked = false;
196
+ let deleted = false;
197
+ for (let i = 0; i < tokens.length; i += 1) {
198
+ const entry = tokens[i];
199
+ const code = entry.slice(0, 2);
200
+ // Handle rename/copy entries
201
+ if (code.startsWith('R') || code.startsWith('C')) {
202
+ // In -z format, renames are: XY PATH1\0PATH2\0
203
+ // entry (tokens[i]) is "XY PATH1", tokens[i+1] is "PATH2"
204
+ const originalPath = entry.slice(3);
205
+ const newPath = tokens[i + 1];
206
+ // Check if this rename/copy affects our target path
207
+ if (originalPath && normalizePath(originalPath) === normalizePath(relativePath)) {
208
+ // Original path matches - this is the "from" side of rename
209
+ const x = code[0]; // Index status
210
+ const y = code[1]; // Working tree status
211
+ staged = staged || (x !== ' ' && x !== '?');
212
+ unstaged = unstaged || y !== ' ';
213
+ deleted = deleted || x === 'D' || y === 'D';
214
+ }
215
+ if (newPath && normalizePath(newPath) === normalizePath(relativePath)) {
216
+ // New path matches - this is the "to" side of rename
217
+ const x = code[0]; // Index status
218
+ const y = code[1]; // Working tree status
219
+ staged = staged || (x !== ' ' && x !== '?');
220
+ unstaged = unstaged || y !== ' ';
221
+ // For the "to" side, it's not deleted (it's the new location)
222
+ }
223
+ i += 1;
224
+ continue;
225
+ }
226
+ // Extract path from entry
227
+ let pathPart = '';
228
+ if (entry.length > 2) {
229
+ const maybeSep = entry[2];
230
+ if (maybeSep === ' ' || maybeSep === '\t') {
231
+ pathPart = entry.slice(3);
232
+ }
233
+ else {
234
+ pathPart = entry.slice(2);
235
+ }
236
+ }
237
+ if (pathPart && normalizePath(pathPart) === normalizePath(relativePath)) {
238
+ // Correct parsing logic according to Git porcelain format
239
+ const x = code[0]; // Index status
240
+ const y = code[1]; // Working tree status
241
+ // Staged: X is not space or question mark
242
+ staged = staged || (x !== ' ' && x !== '?');
243
+ // Unstaged: Y is not space
244
+ unstaged = unstaged || y !== ' ';
245
+ // Untracked: both X and Y are question marks
246
+ untracked = untracked || (x === '?' && y === '?');
247
+ // Deleted: X or Y contains 'D'
248
+ deleted = deleted || x === 'D' || y === 'D';
249
+ }
250
+ }
251
+ return { staged, unstaged, untracked, deleted };
252
+ }
253
+ /**
254
+ * Read file content as Buffer to handle binary data safely.
255
+ */
256
+ async show(revision, filePath) {
257
+ const res = await this.execRaw(['show', `${revision}:${filePath}`]);
258
+ return res.stdout;
259
+ }
260
+ /**
261
+ * Perform a three-way merge on files using git merge-file.
262
+ */
263
+ async mergeFile(basePath, currentPath, incomingPath, options = {}) {
264
+ const args = ['merge-file', '-p', '-q'];
265
+ if (options.union)
266
+ args.push('--union');
267
+ args.push(currentPath, basePath, incomingPath);
268
+ const res = await this.execRaw(args, { allowError: true });
269
+ // git merge-file exit codes:
270
+ // 0: success, no conflicts
271
+ // 1: success, conflicts present (markers in output)
272
+ // other: error (invalid inputs, unreadable files, etc.)
273
+ // We must treat any non-(0|1) code as a hard failure; otherwise callers may write empty output to disk.
274
+ if (res.code !== 0 && res.code !== 1) {
275
+ throw new GitError('git merge-file failed', args.join(' '), res.stderr);
276
+ }
277
+ return {
278
+ content: res.stdout,
279
+ hasConflict: res.code === 1,
280
+ };
281
+ }
282
+ async applyPatch(diffText, options = {}) {
283
+ await this.lockManager.acquireLock(this.repoPath);
284
+ try {
285
+ // NOTE:
286
+ // - `git apply -3` requires valid preimage blob ids (from `index <old>..<new>` lines).
287
+ // - LLM-generated diffs often contain fake index lines, which triggers:
288
+ // "repository lacks the necessary blob to perform 3-way merge."
289
+ // - For safety, we dynamically decide whether 3-way is possible:
290
+ // - If all referenced old blobs exist, keep index lines and run -3.
291
+ // - Otherwise, strip index lines and fall back to non-3-way apply.
292
+ //
293
+ // FIX: Do not strip index lines if patch is binary, as it corrupts the binary payload.
294
+ const isBinary = /(^|\n)GIT binary patch(\r?\n|$)/.test(diffText) ||
295
+ /(^|\n)(literal|delta) \d+(\r?\n|$)/.test(diffText) ||
296
+ /(^|\n)Binary files .* differ(\r?\n|$)/.test(diffText);
297
+ const extractOldBlobIds = (text) => {
298
+ const ids = new Set();
299
+ const lines = text.split(/\r?\n/);
300
+ for (const line of lines) {
301
+ const m = line.match(/^\s*index\s+([0-9a-f]{7,40})\.\.[0-9a-f]{7,40}(?:\s+\d+)?\s*$/i);
302
+ if (m?.[1])
303
+ ids.add(m[1]);
304
+ }
305
+ return Array.from(ids);
306
+ };
307
+ const blobExists = async (sha) => {
308
+ // `git cat-file -e <sha>` exits 0 if the object exists.
309
+ const res = await this.execRaw(['cat-file', '-e', sha], { allowError: true });
310
+ return res.code === 0;
311
+ };
312
+ let useThreeWay = Boolean(options.threeWay);
313
+ let preserveIndexLines = Boolean(options.preserveIndexLines) || isBinary;
314
+ if (useThreeWay && !preserveIndexLines) {
315
+ const oldIds = extractOldBlobIds(diffText).filter((id) => !/^0+$/.test(id));
316
+ if (oldIds.length === 0) {
317
+ // No index lines means -3 is not possible; fall back to direct apply.
318
+ useThreeWay = false;
319
+ }
320
+ else {
321
+ for (const id of oldIds) {
322
+ const exists = await blobExists(id);
323
+ if (!exists) {
324
+ useThreeWay = false;
325
+ break;
326
+ }
327
+ }
328
+ // Only preserve index lines if we can actually do 3-way.
329
+ preserveIndexLines = useThreeWay;
330
+ }
331
+ }
332
+ let cleanedDiff = diffText;
333
+ if (!preserveIndexLines) {
334
+ cleanedDiff = diffText
335
+ .split(/\r?\n/)
336
+ .filter((l) => {
337
+ const trimmedStart = l.trimStart();
338
+ const lower = trimmedStart.toLowerCase();
339
+ return !(lower.startsWith('index ') || lower.startsWith('index\t'));
340
+ })
341
+ .join('\n');
342
+ }
343
+ const tempFile = path.join(tmpdir(), `salmon-patch-${Date.now()}-${randomBytes(4).toString('hex')}.patch`);
344
+ await fs.writeFile(tempFile, cleanedDiff, 'utf8');
345
+ try {
346
+ const args = ['apply', '--recount'];
347
+ if (useThreeWay)
348
+ args.push('-3');
349
+ if (options.ignoreWhitespace)
350
+ args.push('--ignore-whitespace');
351
+ if (options.contextLines)
352
+ args.push(`-C${options.contextLines}`);
353
+ args.push(tempFile);
354
+ await this.exec(args, { env: options.env });
355
+ }
356
+ finally {
357
+ await fs
358
+ .unlink(tempFile)
359
+ .catch((error) => logIgnoredError(`[GitAdapter] cleanup ${tempFile}`, error));
360
+ }
361
+ }
362
+ finally {
363
+ await this.lockManager.releaseLock(this.repoPath);
364
+ }
365
+ }
366
+ /**
367
+ * Precision rollback protecting staged changes.
368
+ */
369
+ async rollbackFiles(paths, ref) {
370
+ const safePaths = this.sanitizePaths(paths);
371
+ if (safePaths.length === 0)
372
+ return;
373
+ await this.lockManager.acquireLock(this.repoPath);
374
+ try {
375
+ // CRITICAL SAFETY: Restores from Index to Worktree to preserve user's staged changes.
376
+ const base = ['checkout'];
377
+ if (ref)
378
+ base.push(ref);
379
+ const batches = splitPathsByCharBudget([...base, '--'], safePaths, LIMITS.gitArgMaxChars);
380
+ if (batches.length <= 1) {
381
+ await this.exec([...base, '--', ...safePaths]);
382
+ return;
383
+ }
384
+ // Avoid ARG_MAX and reduce partial-rollback risk by using a single checkout invocation.
385
+ const tempFile = path.join(tmpdir(), `salmon-pathspec-${Date.now()}-${randomBytes(4).toString('hex')}.txt`);
386
+ await fs.writeFile(tempFile, joinNulTerminated(safePaths));
387
+ try {
388
+ await this.exec([...base, '--pathspec-from-file', tempFile, '--pathspec-file-nul']);
389
+ }
390
+ catch (error) {
391
+ // Fallback for older Git versions without pathspec-from-file support.
392
+ const msg = error instanceof Error
393
+ ? error instanceof Error
394
+ ? error.message
395
+ : String(error)
396
+ : String(error);
397
+ if (!/pathspec-from-file/i.test(msg))
398
+ throw error;
399
+ for (const batch of batches) {
400
+ await this.exec([...base, '--', ...batch]);
401
+ }
402
+ }
403
+ finally {
404
+ await fs
405
+ .unlink(tempFile)
406
+ .catch((error) => logIgnoredError(`[GitAdapter] cleanup ${tempFile}`, error));
407
+ }
408
+ }
409
+ catch (error) {
410
+ try {
411
+ await this.resolveConflicts();
412
+ }
413
+ catch (cleanupError) {
414
+ const cleanupMessage = cleanupError instanceof Error
415
+ ? cleanupError instanceof Error
416
+ ? cleanupError.message
417
+ : String(cleanupError)
418
+ : String(cleanupError);
419
+ const rollbackMessage = error instanceof Error
420
+ ? error instanceof Error
421
+ ? error.message
422
+ : String(error)
423
+ : String(error);
424
+ throw new GitError(`${cleanupMessage}; original rollback error: ${rollbackMessage}`, 'rollbackFiles', cleanupMessage);
425
+ }
426
+ throw error;
427
+ }
428
+ finally {
429
+ await this.lockManager.releaseLock(this.repoPath);
430
+ }
431
+ }
432
+ /**
433
+ * Compatibility alias for rollbackFiles.
434
+ * If paths is a string (legacy call), it treats it as a single file rollback or handles it gracefully.
435
+ */
436
+ async safeRollback(paths, ref) {
437
+ const pathArray = Array.isArray(paths) ? paths : [paths];
438
+ return this.rollbackFiles(pathArray, ref);
439
+ }
440
+ sanitizePaths(paths) {
441
+ return paths
442
+ .map((p) => p.trim().replace(/\\/g, '/'))
443
+ .filter((p) => p && !p.startsWith('/') && !p.includes('..'));
444
+ }
445
+ assertQueryAllowed(args) {
446
+ const cmd = args[0];
447
+ if (!cmd)
448
+ throw new Error(text.git.securityViolation(String(cmd)));
449
+ const allowed = new Set([
450
+ 'diff',
451
+ 'for-each-ref',
452
+ 'log',
453
+ 'ls-files',
454
+ 'ls-tree',
455
+ 'read-tree',
456
+ 'rev-parse',
457
+ 'show',
458
+ 'status',
459
+ 'update-index',
460
+ 'update-ref',
461
+ 'worktree',
462
+ 'write-tree',
463
+ ]);
464
+ if (!allowed.has(cmd))
465
+ throw new Error(text.git.securityViolation(cmd));
466
+ if (cmd === 'diff') {
467
+ if (args.includes('--no-index'))
468
+ throw new Error(text.git.securityViolation(cmd));
469
+ }
470
+ if (cmd === 'write-tree') {
471
+ if (args.length !== 1)
472
+ throw new Error(text.git.securityViolation(cmd));
473
+ }
474
+ if (cmd === 'read-tree') {
475
+ if (args.length !== 2 || !isShaLike(args[1])) {
476
+ throw new Error(text.git.securityViolation(cmd));
477
+ }
478
+ }
479
+ if (cmd === 'update-index') {
480
+ const ok = args.length === 3 && args[1] === '-q' && args[2] === '--refresh';
481
+ if (!ok)
482
+ throw new Error(text.git.securityViolation(cmd));
483
+ }
484
+ if (cmd === 'update-ref') {
485
+ const hasMessage = args.length === 5 && args[1] === '-m';
486
+ if (!hasMessage)
487
+ throw new Error(text.git.securityViolation(cmd));
488
+ const refName = args[3];
489
+ const newValue = args[4];
490
+ if (!refName.startsWith('refs/s8p/'))
491
+ throw new Error(text.git.securityViolation(cmd));
492
+ if (!isShaLike(newValue))
493
+ throw new Error(text.git.securityViolation(cmd));
494
+ }
495
+ if (cmd === 'for-each-ref') {
496
+ const refPrefix = args[args.length - 1];
497
+ if (!refPrefix || !refPrefix.startsWith('refs/s8p/snapshots/')) {
498
+ throw new Error(text.git.securityViolation(cmd));
499
+ }
500
+ const allowedPrefixes = ['--sort=', '--format=', '--count='];
501
+ for (const token of args.slice(1, -1)) {
502
+ if (!allowedPrefixes.some((p) => token.startsWith(p))) {
503
+ throw new Error(text.git.securityViolation(cmd));
504
+ }
505
+ }
506
+ }
507
+ if (cmd === 'worktree') {
508
+ const sub = args[1];
509
+ const shadowRoot = GitAdapter.resolveShadowRoot();
510
+ if (sub === 'list') {
511
+ const ok = args.length === 3 && args[2] === '--porcelain';
512
+ if (!ok)
513
+ throw new Error(text.git.securityViolation(cmd));
514
+ return;
515
+ }
516
+ if (sub === 'add') {
517
+ const allowedFlags = new Set(['--quiet', '--detach']);
518
+ const flags = new Set();
519
+ let i = 2;
520
+ for (; i < args.length && args[i]?.startsWith('-'); i++) {
521
+ const token = args[i];
522
+ if (!allowedFlags.has(token))
523
+ throw new Error(text.git.securityViolation(cmd));
524
+ flags.add(token);
525
+ }
526
+ if (!flags.has('--detach'))
527
+ throw new Error(text.git.securityViolation(cmd));
528
+ if (args.length - i !== 2)
529
+ throw new Error(text.git.securityViolation(cmd));
530
+ const worktreePath = path.resolve(args[i]);
531
+ const baseRef = args[i + 1];
532
+ const parityRoot = GitAdapter.resolveParityShadowRoot(this.repoPath);
533
+ const allowed = [shadowRoot, parityRoot].some((root) => isPathWithinDirectory(root, worktreePath, { allowEqual: false }));
534
+ if (!allowed) {
535
+ throw new Error(text.git.securityViolation(cmd));
536
+ }
537
+ if (!baseRef || baseRef.includes('..'))
538
+ throw new Error(text.git.securityViolation(cmd));
539
+ return;
540
+ }
541
+ if (sub === 'remove') {
542
+ const allowedFlags = new Set(['--force']);
543
+ const flags = new Set();
544
+ let i = 2;
545
+ for (; i < args.length && args[i]?.startsWith('-'); i++) {
546
+ const token = args[i];
547
+ if (!allowedFlags.has(token))
548
+ throw new Error(text.git.securityViolation(cmd));
549
+ flags.add(token);
550
+ }
551
+ if (!flags.has('--force'))
552
+ throw new Error(text.git.securityViolation(cmd));
553
+ if (args.length - i !== 1)
554
+ throw new Error(text.git.securityViolation(cmd));
555
+ const worktreePath = path.resolve(args[i]);
556
+ const parityRoot = GitAdapter.resolveParityShadowRoot(this.repoPath);
557
+ const allowed = [shadowRoot, parityRoot].some((root) => isPathWithinDirectory(root, worktreePath, { allowEqual: false }));
558
+ if (!allowed) {
559
+ throw new Error(text.git.securityViolation(cmd));
560
+ }
561
+ return;
562
+ }
563
+ throw new Error(text.git.securityViolation(cmd));
564
+ }
565
+ }
566
+ /**
567
+ * Resolves the canonical path to the shadow worktree root directory.
568
+ *
569
+ * SECURITY: This method implements DOUBLE realpath resolution to prevent attacks:
570
+ * 1. Prevents symlink attacks: Even if tmpdir() is a symlink, we resolve to the real path
571
+ * 2. Prevents TMPDIR pollution: Attackers cannot trick the system by manipulating TMPDIR env var
572
+ *
573
+ * Why this matters:
574
+ * - Shadow worktrees are the ONLY safe place for destructive operations (reset --hard, clean -fd)
575
+ * - If an attacker could bypass this check, they could trigger data loss in the main repository
576
+ * - Using realpathSync ensures we compare canonical paths, not attacker-controlled symlinks
577
+ *
578
+ * @returns Canonical shadow root path (e.g., "/tmp/s8p-wt")
579
+ */
580
+ static resolveShadowRoot() {
581
+ const tmpResolved = path.resolve(tmpdir());
582
+ let tmpReal = tmpResolved;
583
+ try {
584
+ // CRITICAL: Resolve symlinks in tmpdir() itself
585
+ // Example: /tmp -> /private/tmp on macOS
586
+ tmpReal = realpathSync(tmpResolved);
587
+ }
588
+ catch {
589
+ // Fall back to resolved path. If tmp is not realpath-resolvable, prefer denying shadow checks elsewhere.
590
+ tmpReal = tmpResolved;
591
+ }
592
+ return path.join(tmpReal, 's8p-wt');
593
+ }
594
+ static resolveParityShadowRoot(repoPath) {
595
+ const repoResolved = path.resolve(repoPath);
596
+ let repoReal = repoResolved;
597
+ try {
598
+ repoReal = realpathSync(repoResolved);
599
+ }
600
+ catch {
601
+ repoReal = repoResolved;
602
+ }
603
+ const parent = path.dirname(repoReal);
604
+ return path.join(parent, '.salmonloop', 'worktrees');
605
+ }
606
+ static resolveParityShadowRootFromPath(repoPath) {
607
+ const parsed = path.parse(repoPath);
608
+ const rel = repoPath.slice(parsed.root.length);
609
+ const parts = rel.split(path.sep).filter((part) => part.length > 0);
610
+ for (let i = 0; i < parts.length - 1; i += 1) {
611
+ if (parts[i] === '.salmonloop' && parts[i + 1] === 'worktrees') {
612
+ return path.join(parsed.root, ...parts.slice(0, i + 2));
613
+ }
614
+ }
615
+ return null;
616
+ }
617
+ /**
618
+ * Verifies if the current GitAdapter instance points to a shadow worktree.
619
+ *
620
+ * SECURITY: Multi-layer defense against path traversal and symlink attacks:
621
+ * 1. Both shadowRoot AND repoPath are resolved via realpathSync
622
+ * 2. Directory-aware containment check prevents partial matches (e.g., /tmp/s8p-wt-evil)
623
+ * 3. String prefix pitfalls are avoided by path.relative semantics
624
+ *
625
+ * Why this check is CRITICAL:
626
+ * - Operations like resolveConflicts() execute `git reset --hard HEAD` and `git clean -fd`
627
+ * - These commands PERMANENTLY DELETE uncommitted changes and untracked files
628
+ * - This check ensures such operations ONLY run in disposable shadow worktrees
629
+ * - The main repository is NEVER touched by destructive cleanup operations
630
+ *
631
+ * Attack scenarios prevented:
632
+ * - Symlink injection: realpathSync resolves links before comparison
633
+ * - Path traversal: strict prefix check prevents escape via ../
634
+ * - Partial path matching: trailing separator prevents /tmp/s8p-wt-malicious from matching
635
+ *
636
+ * @returns true if this.repoPath is inside the shadow worktree root, false otherwise
637
+ */
638
+ isShadowWorktreePath() {
639
+ const expectedRoot = GitAdapter.resolveShadowRoot();
640
+ const repoResolved = path.resolve(this.repoPath);
641
+ let repo = repoResolved;
642
+ try {
643
+ // CRITICAL: Resolve symlinks in the repo path being checked
644
+ // Prevents attacker from creating a symlink to main repo inside shadow root
645
+ repo = realpathSync(repoResolved);
646
+ }
647
+ catch {
648
+ repo = repoResolved;
649
+ }
650
+ if (isPathWithinDirectory(expectedRoot, repo, { allowEqual: false }))
651
+ return true;
652
+ const parityRoot = GitAdapter.resolveParityShadowRootFromPath(repo);
653
+ if (!parityRoot)
654
+ return false;
655
+ return isPathWithinDirectory(parityRoot, repo, { allowEqual: false });
656
+ }
657
+ /**
658
+ * Aggressively cleans the shadow worktree to resolve merge conflicts or corrupted state.
659
+ *
660
+ * ⚠️ DANGER: This method runs DESTRUCTIVE Git operations:
661
+ * - `git reset --hard HEAD`: Discards ALL uncommitted changes
662
+ * - `git clean -fd`: Deletes ALL untracked files and directories
663
+ *
664
+ * WHY THIS IS SAFE (not a data loss risk):
665
+ * 1. Protected by isShadowWorktreePath() check - throws error if not in shadow
666
+ * 2. Shadow worktrees are DISPOSABLE temporary directories (e.g., /tmp/s8p-wt/...)
667
+ * 3. User's main repository is NEVER touched - it remains in read-only state
668
+ * 4. Original state is preserved in snapshot commits (refs/s8p/snapshots/*)
669
+ * 5. Apply-back process is transactional - failures don't corrupt main workspace
670
+ *
671
+ * Design Intent (see docs/design/checkpoint.md):
672
+ * - "AI modifications run in a disposable 'Shadow Worktree', never polluting
673
+ * the user's primary workspace until verified"
674
+ *
675
+ * Common Misunderstanding:
676
+ * ❌ "reset --hard will lose user data"
677
+ * ✅ Correct: It only affects the temporary shadow, which is recreated from snapshots
678
+ *
679
+ * Error Handling:
680
+ * - allowError: true on stash - may have nothing to stash, that's fine
681
+ * - Catch block ignores errors - this is best-effort cleanup in a disposable environment
682
+ * - Even if cleanup fails, shadow worktree is deleted during teardown anyway
683
+ *
684
+ * @throws GitError if called on main repository (safety violation)
685
+ */
686
+ async resolveConflicts() {
687
+ // SAFETY BARRIER: Absolutely refuse to run destructive operations outside shadow
688
+ if (!this.isShadowWorktreePath()) {
689
+ throw new GitError(text.git.conflictResolutionDenied, 'resolveConflicts', 'Safety Check Failed');
690
+ }
691
+ try {
692
+ // Best-effort cleanup sequence for disposable shadow worktree
693
+ await this.exec(['stash'], { allowError: true });
694
+ await this.exec(['reset', '--hard', 'HEAD']);
695
+ await this.exec(['clean', '-fd']);
696
+ }
697
+ catch (_e) {
698
+ // Best-effort cleanup, ignore errors
699
+ // Rationale: Shadow worktree will be deleted during teardown anyway
700
+ // Logging errors here would just create noise for expected edge cases
701
+ }
702
+ }
703
+ }
704
+ //# sourceMappingURL=git-adapter.js.map