@lumenflow/cli 3.1.2 → 3.1.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 (389) hide show
  1. package/README.md +36 -35
  2. package/dist/agent-issues-query.js +13 -8
  3. package/dist/agent-log-issue.js +15 -4
  4. package/dist/agent-session-end.js +15 -4
  5. package/dist/agent-session.js +18 -6
  6. package/dist/backlog-prune.js +1 -1
  7. package/dist/commands/integrate.js +32 -18
  8. package/dist/config-get.js +27 -15
  9. package/dist/config-set.js +104 -37
  10. package/dist/delegation-list.js +1 -1
  11. package/dist/doctor.js +19 -13
  12. package/dist/file-delete.js +1 -1
  13. package/dist/file-edit.js +1 -1
  14. package/dist/file-read.js +1 -1
  15. package/dist/file-write.js +1 -1
  16. package/dist/flow-bottlenecks.js +1 -1
  17. package/dist/flow-report.js +10 -9
  18. package/dist/gates.js +3 -2
  19. package/dist/git-branch.js +1 -1
  20. package/dist/git-diff.js +1 -1
  21. package/dist/git-log.js +1 -1
  22. package/dist/init.js +238 -42
  23. package/dist/initiative-add-wu.js +1 -1
  24. package/dist/initiative-bulk-assign-wus.js +1 -1
  25. package/dist/initiative-create.js +2 -2
  26. package/dist/initiative-edit.js +1 -1
  27. package/dist/initiative-list.js +1 -1
  28. package/dist/initiative-plan.js +1 -3
  29. package/dist/initiative-status.js +47 -6
  30. package/dist/lane-edit.js +19 -10
  31. package/dist/lane-health.js +13 -24
  32. package/dist/lane-lock.js +4 -5
  33. package/dist/lane-setup.js +5 -5
  34. package/dist/lane-status.js +4 -5
  35. package/dist/lane-suggest.js +9 -7
  36. package/dist/lane-validate.js +4 -5
  37. package/dist/lumenflow-upgrade.js +17 -11
  38. package/dist/mem-checkpoint.js +1 -1
  39. package/dist/mem-cleanup.js +6 -23
  40. package/dist/mem-context.js +1 -1
  41. package/dist/mem-create.js +1 -1
  42. package/dist/mem-delete.js +1 -1
  43. package/dist/mem-export.js +1 -1
  44. package/dist/mem-inbox.js +1 -1
  45. package/dist/mem-init.js +1 -1
  46. package/dist/mem-ready.js +1 -1
  47. package/dist/mem-recover.js +1 -1
  48. package/dist/mem-signal.js +1 -1
  49. package/dist/mem-start.js +1 -1
  50. package/dist/mem-summarize.js +8 -7
  51. package/dist/mem-triage.js +7 -5
  52. package/dist/metrics-cli.js +1 -1
  53. package/dist/metrics-snapshot.js +1 -1
  54. package/dist/onboard.js +295 -120
  55. package/dist/orchestrate-init-status.js +12 -7
  56. package/dist/orchestrate-initiative.js +23 -12
  57. package/dist/orchestrate-monitor.js +20 -8
  58. package/dist/pack-scaffold.js +1 -1
  59. package/dist/plan-create.js +1 -3
  60. package/dist/plan-edit.js +1 -3
  61. package/dist/plan-link.js +1 -3
  62. package/dist/plan-promote.js +1 -3
  63. package/dist/release.js +1 -3
  64. package/dist/signal-cleanup.js +4 -18
  65. package/dist/state-bootstrap.js +11 -8
  66. package/dist/state-cleanup.js +5 -19
  67. package/dist/state-doctor.js +213 -9
  68. package/dist/task-claim.js +1 -1
  69. package/dist/validate.js +1 -1
  70. package/dist/workspace-init.js +61 -61
  71. package/dist/wu-block.js +1 -1
  72. package/dist/wu-brief.js +1 -1
  73. package/dist/wu-claim.js +1 -1
  74. package/dist/wu-cleanup.js +1 -1
  75. package/dist/wu-create.js +3 -3
  76. package/dist/wu-delegate.js +1 -1
  77. package/dist/wu-deps.js +1 -1
  78. package/dist/wu-done.js +66 -34
  79. package/dist/wu-edit.js +1 -1
  80. package/dist/wu-infer-lane.js +1 -1
  81. package/dist/wu-preflight.js +1 -1
  82. package/dist/wu-prep.js +1 -1
  83. package/dist/wu-proto.js +1 -1
  84. package/dist/wu-prune.js +1 -1
  85. package/dist/wu-recover.js +1 -1
  86. package/dist/wu-release.js +1 -1
  87. package/dist/wu-repair.js +1 -1
  88. package/dist/wu-sandbox.js +40 -27
  89. package/dist/wu-status.js +1 -1
  90. package/dist/wu-unblock.js +1 -1
  91. package/dist/wu-unlock-lane.js +1 -1
  92. package/dist/wu-validate.js +1 -1
  93. package/package.json +12 -8
  94. package/packs/software-delivery/constants.ts +10 -0
  95. package/packs/software-delivery/extensions.ts +140 -0
  96. package/packs/software-delivery/gate-policies.ts +134 -0
  97. package/packs/software-delivery/index.ts +8 -0
  98. package/packs/software-delivery/manifest-schema.ts +236 -0
  99. package/packs/software-delivery/manifest.ts +417 -0
  100. package/packs/software-delivery/manifest.yaml +711 -0
  101. package/packs/software-delivery/pack-registration.ts +113 -0
  102. package/packs/software-delivery/tool-impl/agent-tools.ts +263 -0
  103. package/packs/software-delivery/tool-impl/delegation-tools.ts +66 -0
  104. package/packs/software-delivery/tool-impl/flow-metrics-tools.ts +219 -0
  105. package/packs/software-delivery/tool-impl/git-runner.ts +113 -0
  106. package/packs/software-delivery/tool-impl/git-tools.ts +316 -0
  107. package/packs/software-delivery/tool-impl/index.ts +15 -0
  108. package/packs/software-delivery/tool-impl/initiative-orchestration-tools.ts +720 -0
  109. package/packs/software-delivery/tool-impl/lane-lock.ts +246 -0
  110. package/packs/software-delivery/tool-impl/memory-tools.ts +415 -0
  111. package/packs/software-delivery/tool-impl/pending-runtime-tools.ts +21 -0
  112. package/packs/software-delivery/tool-impl/runtime-cli-adapter.ts +328 -0
  113. package/packs/software-delivery/tool-impl/runtime-native-tools.ts +687 -0
  114. package/packs/software-delivery/tool-impl/worker-loader.ts +52 -0
  115. package/packs/software-delivery/tool-impl/worktree-tools.ts +46 -0
  116. package/packs/software-delivery/tool-impl/wu-lifecycle-tools.ts +759 -0
  117. package/packs/software-delivery/tools/delegation-tools.ts +23 -0
  118. package/packs/software-delivery/tools/git-tools.ts +55 -0
  119. package/packs/software-delivery/tools/index.ts +8 -0
  120. package/packs/software-delivery/tools/lane-lock-tool.ts +37 -0
  121. package/packs/software-delivery/tools/types.ts +71 -0
  122. package/packs/software-delivery/tools/worktree-tools.ts +49 -0
  123. package/templates/core/LUMENFLOW.md.template +3 -3
  124. package/templates/core/ai/onboarding/agent-invocation-guide.md.template +1 -1
  125. package/templates/core/ai/onboarding/lumenflow-force-usage.md.template +1 -1
  126. package/templates/core/ai/onboarding/quick-ref-commands.md.template +5 -5
  127. package/templates/core/ai/onboarding/starting-prompt.md.template +3 -3
  128. package/templates/core/ai/onboarding/vendor-support.md.template +1 -1
  129. package/templates/core/ai/onboarding/wu-create-checklist.md.template +1 -1
  130. package/dist/agent-issues-query.js.map +0 -1
  131. package/dist/agent-log-issue.js.map +0 -1
  132. package/dist/agent-session-end.js.map +0 -1
  133. package/dist/agent-session.js.map +0 -1
  134. package/dist/backlog-prune.js.map +0 -1
  135. package/dist/cli-entry-point.js +0 -149
  136. package/dist/cli-entry-point.js.map +0 -1
  137. package/dist/commands/integrate.js.map +0 -1
  138. package/dist/commands.js.map +0 -1
  139. package/dist/config-get.js.map +0 -1
  140. package/dist/config-set.js.map +0 -1
  141. package/dist/delegation-list.js.map +0 -1
  142. package/dist/deps-add.js +0 -259
  143. package/dist/deps-add.js.map +0 -1
  144. package/dist/deps-remove.js +0 -105
  145. package/dist/deps-remove.js.map +0 -1
  146. package/dist/docs-sync.js.map +0 -1
  147. package/dist/doctor.js.map +0 -1
  148. package/dist/file-delete.js.map +0 -1
  149. package/dist/file-edit.js.map +0 -1
  150. package/dist/file-read.js.map +0 -1
  151. package/dist/file-write.js.map +0 -1
  152. package/dist/flow-bottlenecks.js.map +0 -1
  153. package/dist/flow-report.js.map +0 -1
  154. package/dist/formatters.js +0 -151
  155. package/dist/formatters.js.map +0 -1
  156. package/dist/gate-defaults.js +0 -131
  157. package/dist/gate-defaults.js.map +0 -1
  158. package/dist/gate-registry.js +0 -73
  159. package/dist/gate-registry.js.map +0 -1
  160. package/dist/gates-graceful-degradation.js +0 -153
  161. package/dist/gates-graceful-degradation.js.map +0 -1
  162. package/dist/gates-plan-resolvers.js +0 -152
  163. package/dist/gates-plan-resolvers.js.map +0 -1
  164. package/dist/gates-runners.js +0 -509
  165. package/dist/gates-runners.js.map +0 -1
  166. package/dist/gates-types.js +0 -4
  167. package/dist/gates-types.js.map +0 -1
  168. package/dist/gates-utils.js +0 -323
  169. package/dist/gates-utils.js.map +0 -1
  170. package/dist/gates.js.map +0 -1
  171. package/dist/git-branch.js.map +0 -1
  172. package/dist/git-diff.js.map +0 -1
  173. package/dist/git-log.js.map +0 -1
  174. package/dist/git-status.js.map +0 -1
  175. package/dist/guard-locked.js +0 -172
  176. package/dist/guard-locked.js.map +0 -1
  177. package/dist/guard-main-branch.js +0 -217
  178. package/dist/guard-main-branch.js.map +0 -1
  179. package/dist/guard-worktree-commit.js +0 -163
  180. package/dist/guard-worktree-commit.js.map +0 -1
  181. package/dist/hooks/auto-checkpoint-utils.js +0 -54
  182. package/dist/hooks/auto-checkpoint-utils.js.map +0 -1
  183. package/dist/hooks/enforcement-checks.js +0 -399
  184. package/dist/hooks/enforcement-checks.js.map +0 -1
  185. package/dist/hooks/enforcement-generator.js +0 -139
  186. package/dist/hooks/enforcement-generator.js.map +0 -1
  187. package/dist/hooks/enforcement-sync.js +0 -385
  188. package/dist/hooks/enforcement-sync.js.map +0 -1
  189. package/dist/hooks/generators/auto-checkpoint.js +0 -125
  190. package/dist/hooks/generators/auto-checkpoint.js.map +0 -1
  191. package/dist/hooks/generators/enforce-worktree.js +0 -190
  192. package/dist/hooks/generators/enforce-worktree.js.map +0 -1
  193. package/dist/hooks/generators/index.js +0 -18
  194. package/dist/hooks/generators/index.js.map +0 -1
  195. package/dist/hooks/generators/pre-compact-checkpoint.js +0 -136
  196. package/dist/hooks/generators/pre-compact-checkpoint.js.map +0 -1
  197. package/dist/hooks/generators/require-wu.js +0 -117
  198. package/dist/hooks/generators/require-wu.js.map +0 -1
  199. package/dist/hooks/generators/session-start-recovery.js +0 -103
  200. package/dist/hooks/generators/session-start-recovery.js.map +0 -1
  201. package/dist/hooks/generators/signal-utils.js +0 -54
  202. package/dist/hooks/generators/signal-utils.js.map +0 -1
  203. package/dist/hooks/generators/warn-incomplete.js +0 -67
  204. package/dist/hooks/generators/warn-incomplete.js.map +0 -1
  205. package/dist/hooks/index.js +0 -10
  206. package/dist/hooks/index.js.map +0 -1
  207. package/dist/index.js.map +0 -1
  208. package/dist/init-detection.js +0 -232
  209. package/dist/init-detection.js.map +0 -1
  210. package/dist/init-lane-validation.js +0 -143
  211. package/dist/init-lane-validation.js.map +0 -1
  212. package/dist/init-scaffolding.js +0 -158
  213. package/dist/init-scaffolding.js.map +0 -1
  214. package/dist/init-templates.js +0 -1982
  215. package/dist/init-templates.js.map +0 -1
  216. package/dist/init.js.map +0 -1
  217. package/dist/initiative-add-wu.js.map +0 -1
  218. package/dist/initiative-bulk-assign-wus.js.map +0 -1
  219. package/dist/initiative-create.js.map +0 -1
  220. package/dist/initiative-edit.js.map +0 -1
  221. package/dist/initiative-list.js.map +0 -1
  222. package/dist/initiative-plan.js.map +0 -1
  223. package/dist/initiative-remove-wu.js.map +0 -1
  224. package/dist/initiative-status.js.map +0 -1
  225. package/dist/lane-edit.js.map +0 -1
  226. package/dist/lane-health.js.map +0 -1
  227. package/dist/lane-lifecycle-process.js +0 -366
  228. package/dist/lane-lifecycle-process.js.map +0 -1
  229. package/dist/lane-lock.js.map +0 -1
  230. package/dist/lane-setup.js.map +0 -1
  231. package/dist/lane-status.js.map +0 -1
  232. package/dist/lane-suggest.js.map +0 -1
  233. package/dist/lane-validate.js.map +0 -1
  234. package/dist/lifecycle-regression-harness.js +0 -181
  235. package/dist/lifecycle-regression-harness.js.map +0 -1
  236. package/dist/lumenflow-upgrade.js.map +0 -1
  237. package/dist/mem-checkpoint.js.map +0 -1
  238. package/dist/mem-cleanup.js.map +0 -1
  239. package/dist/mem-context.js.map +0 -1
  240. package/dist/mem-create.js.map +0 -1
  241. package/dist/mem-delete.js.map +0 -1
  242. package/dist/mem-export.js.map +0 -1
  243. package/dist/mem-inbox.js.map +0 -1
  244. package/dist/mem-index.js +0 -214
  245. package/dist/mem-index.js.map +0 -1
  246. package/dist/mem-init.js.map +0 -1
  247. package/dist/mem-profile.js +0 -210
  248. package/dist/mem-profile.js.map +0 -1
  249. package/dist/mem-promote.js +0 -257
  250. package/dist/mem-promote.js.map +0 -1
  251. package/dist/mem-ready.js.map +0 -1
  252. package/dist/mem-recover.js.map +0 -1
  253. package/dist/mem-signal.js.map +0 -1
  254. package/dist/mem-start.js.map +0 -1
  255. package/dist/mem-summarize.js.map +0 -1
  256. package/dist/mem-triage.js.map +0 -1
  257. package/dist/merge-block.js +0 -225
  258. package/dist/merge-block.js.map +0 -1
  259. package/dist/metrics-cli.js.map +0 -1
  260. package/dist/metrics-snapshot.js.map +0 -1
  261. package/dist/onboard.js.map +0 -1
  262. package/dist/onboarding-smoke-test.js +0 -418
  263. package/dist/onboarding-smoke-test.js.map +0 -1
  264. package/dist/orchestrate-init-status.js.map +0 -1
  265. package/dist/orchestrate-initiative.js.map +0 -1
  266. package/dist/orchestrate-monitor.js.map +0 -1
  267. package/dist/pack-author.js.map +0 -1
  268. package/dist/pack-hash.js.map +0 -1
  269. package/dist/pack-install.js.map +0 -1
  270. package/dist/pack-publish.js.map +0 -1
  271. package/dist/pack-scaffold.js.map +0 -1
  272. package/dist/pack-search.js.map +0 -1
  273. package/dist/pack-validate.js.map +0 -1
  274. package/dist/plan-create.js.map +0 -1
  275. package/dist/plan-edit.js.map +0 -1
  276. package/dist/plan-link.js.map +0 -1
  277. package/dist/plan-promote.js.map +0 -1
  278. package/dist/public-manifest.js +0 -920
  279. package/dist/public-manifest.js.map +0 -1
  280. package/dist/release.js.map +0 -1
  281. package/dist/rotate-progress.js +0 -253
  282. package/dist/rotate-progress.js.map +0 -1
  283. package/dist/session-coordinator.js +0 -303
  284. package/dist/session-coordinator.js.map +0 -1
  285. package/dist/shared-validators.js +0 -81
  286. package/dist/shared-validators.js.map +0 -1
  287. package/dist/signal-cleanup.js.map +0 -1
  288. package/dist/state-bootstrap.js.map +0 -1
  289. package/dist/state-cleanup.js.map +0 -1
  290. package/dist/state-doctor-fix.js +0 -226
  291. package/dist/state-doctor-fix.js.map +0 -1
  292. package/dist/state-doctor-stamps.js +0 -23
  293. package/dist/state-doctor-stamps.js.map +0 -1
  294. package/dist/state-doctor.js.map +0 -1
  295. package/dist/strict-progress.js +0 -255
  296. package/dist/strict-progress.js.map +0 -1
  297. package/dist/sync-templates.js.map +0 -1
  298. package/dist/task-claim.js.map +0 -1
  299. package/dist/trace-gen.js +0 -401
  300. package/dist/trace-gen.js.map +0 -1
  301. package/dist/validate-agent-skills.js +0 -223
  302. package/dist/validate-agent-skills.js.map +0 -1
  303. package/dist/validate-agent-sync.js +0 -151
  304. package/dist/validate-agent-sync.js.map +0 -1
  305. package/dist/validate-backlog-sync.js +0 -77
  306. package/dist/validate-backlog-sync.js.map +0 -1
  307. package/dist/validate-skills-spec.js +0 -211
  308. package/dist/validate-skills-spec.js.map +0 -1
  309. package/dist/validate.js.map +0 -1
  310. package/dist/validator-defaults.js +0 -107
  311. package/dist/validator-defaults.js.map +0 -1
  312. package/dist/validator-registry.js +0 -71
  313. package/dist/validator-registry.js.map +0 -1
  314. package/dist/workspace-init.js.map +0 -1
  315. package/dist/wu-block.js.map +0 -1
  316. package/dist/wu-brief.js.map +0 -1
  317. package/dist/wu-claim-branch.js +0 -123
  318. package/dist/wu-claim-branch.js.map +0 -1
  319. package/dist/wu-claim-cloud.js +0 -79
  320. package/dist/wu-claim-cloud.js.map +0 -1
  321. package/dist/wu-claim-mode.js +0 -82
  322. package/dist/wu-claim-mode.js.map +0 -1
  323. package/dist/wu-claim-output.js +0 -85
  324. package/dist/wu-claim-output.js.map +0 -1
  325. package/dist/wu-claim-repair-guidance.js +0 -12
  326. package/dist/wu-claim-repair-guidance.js.map +0 -1
  327. package/dist/wu-claim-resume-handler.js +0 -87
  328. package/dist/wu-claim-resume-handler.js.map +0 -1
  329. package/dist/wu-claim-state.js +0 -581
  330. package/dist/wu-claim-state.js.map +0 -1
  331. package/dist/wu-claim-validation.js +0 -457
  332. package/dist/wu-claim-validation.js.map +0 -1
  333. package/dist/wu-claim-worktree.js +0 -223
  334. package/dist/wu-claim-worktree.js.map +0 -1
  335. package/dist/wu-claim.js.map +0 -1
  336. package/dist/wu-cleanup-cloud.js +0 -78
  337. package/dist/wu-cleanup-cloud.js.map +0 -1
  338. package/dist/wu-cleanup.js.map +0 -1
  339. package/dist/wu-code-path-coverage.js +0 -83
  340. package/dist/wu-code-path-coverage.js.map +0 -1
  341. package/dist/wu-create-cloud.js +0 -30
  342. package/dist/wu-create-cloud.js.map +0 -1
  343. package/dist/wu-create-content.js +0 -264
  344. package/dist/wu-create-content.js.map +0 -1
  345. package/dist/wu-create-readiness.js +0 -59
  346. package/dist/wu-create-readiness.js.map +0 -1
  347. package/dist/wu-create-validation.js +0 -128
  348. package/dist/wu-create-validation.js.map +0 -1
  349. package/dist/wu-create.js.map +0 -1
  350. package/dist/wu-delegate.js.map +0 -1
  351. package/dist/wu-delete.js.map +0 -1
  352. package/dist/wu-deps.js.map +0 -1
  353. package/dist/wu-done-auto-cleanup.js +0 -203
  354. package/dist/wu-done-auto-cleanup.js.map +0 -1
  355. package/dist/wu-done-check.js +0 -38
  356. package/dist/wu-done-check.js.map +0 -1
  357. package/dist/wu-done-cloud.js +0 -48
  358. package/dist/wu-done-cloud.js.map +0 -1
  359. package/dist/wu-done-decay.js +0 -86
  360. package/dist/wu-done-decay.js.map +0 -1
  361. package/dist/wu-done.js.map +0 -1
  362. package/dist/wu-edit-operations.js +0 -399
  363. package/dist/wu-edit-operations.js.map +0 -1
  364. package/dist/wu-edit-validators.js +0 -282
  365. package/dist/wu-edit-validators.js.map +0 -1
  366. package/dist/wu-edit.js.map +0 -1
  367. package/dist/wu-infer-lane.js.map +0 -1
  368. package/dist/wu-preflight.js.map +0 -1
  369. package/dist/wu-prep.js.map +0 -1
  370. package/dist/wu-proto.js.map +0 -1
  371. package/dist/wu-prune.js.map +0 -1
  372. package/dist/wu-recover.js.map +0 -1
  373. package/dist/wu-release.js.map +0 -1
  374. package/dist/wu-repair.js.map +0 -1
  375. package/dist/wu-sandbox.js.map +0 -1
  376. package/dist/wu-spawn-completion.js +0 -33
  377. package/dist/wu-spawn-completion.js.map +0 -1
  378. package/dist/wu-spawn-prompt-builders.js +0 -1197
  379. package/dist/wu-spawn-prompt-builders.js.map +0 -1
  380. package/dist/wu-spawn-strategy-resolver.js +0 -322
  381. package/dist/wu-spawn-strategy-resolver.js.map +0 -1
  382. package/dist/wu-spawn.js +0 -59
  383. package/dist/wu-spawn.js.map +0 -1
  384. package/dist/wu-state-cloud.js +0 -41
  385. package/dist/wu-state-cloud.js.map +0 -1
  386. package/dist/wu-status.js.map +0 -1
  387. package/dist/wu-unblock.js.map +0 -1
  388. package/dist/wu-unlock-lane.js.map +0 -1
  389. package/dist/wu-validate.js.map +0 -1
@@ -0,0 +1,113 @@
1
+ // Copyright (c) 2026 Hellmai Ltd
2
+ // SPDX-License-Identifier: AGPL-3.0-only
3
+
4
+ import { execFileSync } from 'node:child_process';
5
+ import { UTF8_ENCODING } from '../constants.js';
6
+
7
+ const GIT_BINARY_ENV_VAR = 'LUMENFLOW_GIT_BINARY';
8
+ const POSIX_GIT_BINARY = 'git';
9
+ const WINDOWS_GIT_BINARY = 'git.exe';
10
+
11
+ export interface GitCommandResult {
12
+ ok: boolean;
13
+ stdout: string;
14
+ stderr: string;
15
+ status: number;
16
+ }
17
+
18
+ function firstNonEmptyLine(value: unknown): string | null {
19
+ if (typeof value !== 'string') {
20
+ return null;
21
+ }
22
+ const line = value
23
+ .split(/\r?\n/)
24
+ .map((entry) => entry.trim())
25
+ .find((entry) => entry.length > 0);
26
+ return line ?? null;
27
+ }
28
+
29
+ function resolveGitBinaryFromPath(): string | null {
30
+ const lookupCommand = process.platform === 'win32' ? 'where' : 'which';
31
+ const lookupTarget = process.platform === 'win32' ? WINDOWS_GIT_BINARY : POSIX_GIT_BINARY;
32
+ const lookupResult = runCommand(lookupCommand, [lookupTarget], {});
33
+
34
+ if (!lookupResult || lookupResult.status !== 0) {
35
+ return null;
36
+ }
37
+ return firstNonEmptyLine(lookupResult.stdout);
38
+ }
39
+
40
+ export function resolveGitBinary(): string {
41
+ const configured = process.env[GIT_BINARY_ENV_VAR]?.trim();
42
+ if (configured && configured.length > 0) {
43
+ return configured;
44
+ }
45
+ const resolved = resolveGitBinaryFromPath();
46
+ if (resolved) {
47
+ return resolved;
48
+ }
49
+ return process.platform === 'win32' ? WINDOWS_GIT_BINARY : POSIX_GIT_BINARY;
50
+ }
51
+
52
+ export const GIT_BINARY = resolveGitBinary();
53
+
54
+ export function runGit(
55
+ args: string[],
56
+ options: { cwd?: string; gitBinary?: string } = {},
57
+ ): GitCommandResult {
58
+ const result = runCommand(options.gitBinary ?? GIT_BINARY, args, { cwd: options.cwd });
59
+ return {
60
+ ok: result.status === 0,
61
+ stdout: result.stdout,
62
+ stderr: result.stderr,
63
+ status: result.status ?? 1,
64
+ };
65
+ }
66
+
67
+ function runCommand(command: string, args: string[], options: { cwd?: string }): GitCommandResult {
68
+ try {
69
+ const stdout = execFileSync(command, args, {
70
+ cwd: options.cwd,
71
+ encoding: UTF8_ENCODING,
72
+ stdio: ['ignore', 'pipe', 'pipe'],
73
+ });
74
+ return {
75
+ ok: true,
76
+ stdout,
77
+ stderr: '',
78
+ status: 0,
79
+ };
80
+ } catch (error: unknown) {
81
+ if (error && typeof error === 'object') {
82
+ const typedError = error as {
83
+ status?: number;
84
+ stdout?: string | Buffer;
85
+ stderr?: string | Buffer;
86
+ message?: string;
87
+ };
88
+ return {
89
+ ok: false,
90
+ stdout: toCommandOutput(typedError.stdout),
91
+ stderr: toCommandOutput(typedError.stderr) || (typedError.message ?? ''),
92
+ status: typeof typedError.status === 'number' ? typedError.status : 1,
93
+ };
94
+ }
95
+
96
+ return {
97
+ ok: false,
98
+ stdout: '',
99
+ stderr: String(error),
100
+ status: 1,
101
+ };
102
+ }
103
+ }
104
+
105
+ function toCommandOutput(value: string | Buffer | undefined): string {
106
+ if (typeof value === 'string') {
107
+ return value;
108
+ }
109
+ if (value instanceof Buffer) {
110
+ return value.toString(UTF8_ENCODING);
111
+ }
112
+ return '';
113
+ }
@@ -0,0 +1,316 @@
1
+ // Copyright (c) 2026 Hellmai Ltd
2
+ // SPDX-License-Identifier: AGPL-3.0-only
3
+
4
+ import { GIT_BINARY, runGit } from './git-runner.js';
5
+
6
+ export type GitToolName = 'git:add' | 'git:status' | 'git:commit';
7
+
8
+ export interface GitToolContext {
9
+ run_id: string;
10
+ task_id: string;
11
+ session_id: string;
12
+ cwd: string;
13
+ }
14
+
15
+ export interface GitToolOutput {
16
+ success: boolean;
17
+ data?: Record<string, unknown>;
18
+ error?: {
19
+ code: string;
20
+ message: string;
21
+ };
22
+ metadata?: {
23
+ artifacts_written?: string[];
24
+ };
25
+ }
26
+
27
+ export interface ToolCallStartedReceipt {
28
+ schema_version: 1;
29
+ kind: 'tool_call_started';
30
+ run_id: string;
31
+ task_id: string;
32
+ session_id: string;
33
+ tool_name: GitToolName;
34
+ }
35
+
36
+ export interface ToolCallFinishedReceipt {
37
+ schema_version: 1;
38
+ kind: 'tool_call_finished';
39
+ result: 'success' | 'failure';
40
+ artifacts_written: string[];
41
+ }
42
+
43
+ export interface GitToolHostReceipt {
44
+ started: ToolCallStartedReceipt;
45
+ finished: ToolCallFinishedReceipt;
46
+ output: GitToolOutput;
47
+ }
48
+
49
+ interface CommandExecutionResult {
50
+ command: string;
51
+ args: string[];
52
+ stdout: string;
53
+ stderr: string;
54
+ status: number;
55
+ }
56
+
57
+ function isGitBinaryCommand(command: unknown): boolean {
58
+ const normalized = String(command);
59
+ return normalized === 'git' || normalized === GIT_BINARY;
60
+ }
61
+
62
+ async function trySimpleGitStatus(cwd: string): Promise<string | null> {
63
+ try {
64
+ const simpleGitModule = (await import('simple-git')) as {
65
+ simpleGit?: (root: string) => { status: () => Promise<{ files: Array<{ path: string }> }> };
66
+ };
67
+ if (!simpleGitModule.simpleGit) {
68
+ return null;
69
+ }
70
+ const git = simpleGitModule.simpleGit(cwd);
71
+ const status = await git.status();
72
+ return status.files.map((file) => file.path).join('\n');
73
+ } catch {
74
+ return null;
75
+ }
76
+ }
77
+
78
+ function ensureRepository(cwd: string): void {
79
+ const existing = runGit(['rev-parse', '--is-inside-work-tree'], { cwd });
80
+ if (existing.ok) {
81
+ return;
82
+ }
83
+ const init = runGit(['init'], { cwd });
84
+ if (!init.ok) {
85
+ throw new Error(`Failed to initialize git repository: ${init.stderr || init.stdout}`);
86
+ }
87
+ }
88
+
89
+ export async function gitStatusTool(
90
+ input: Record<string, unknown>,
91
+ cwd: string,
92
+ ): Promise<GitToolOutput> {
93
+ ensureRepository(cwd);
94
+
95
+ if (input.init === true) {
96
+ return {
97
+ success: true,
98
+ data: { initialized: true },
99
+ };
100
+ }
101
+
102
+ const commands = Array.isArray(input.commands) ? input.commands : null;
103
+ if (commands) {
104
+ const commandResults: CommandExecutionResult[] = [];
105
+
106
+ for (const commandEntry of commands) {
107
+ if (!Array.isArray(commandEntry) || commandEntry.length === 0) {
108
+ return {
109
+ success: false,
110
+ error: {
111
+ code: 'invalid_command',
112
+ message: 'commands must contain non-empty command arrays.',
113
+ },
114
+ };
115
+ }
116
+
117
+ const command = commandEntry[0];
118
+ if (!isGitBinaryCommand(command)) {
119
+ return {
120
+ success: false,
121
+ error: {
122
+ code: 'invalid_command',
123
+ message: 'git:status commands only allow the git binary.',
124
+ },
125
+ };
126
+ }
127
+
128
+ const args = commandEntry.slice(1).map((arg) => String(arg));
129
+ const result = runGit(args, { cwd });
130
+ if (!result.ok) {
131
+ return {
132
+ success: false,
133
+ error: {
134
+ code: 'command_failed',
135
+ message: result.stderr || result.stdout || 'Command execution failed.',
136
+ },
137
+ };
138
+ }
139
+
140
+ commandResults.push({
141
+ command: String(command),
142
+ args,
143
+ stdout: result.stdout,
144
+ stderr: result.stderr,
145
+ status: result.status,
146
+ });
147
+ }
148
+
149
+ return {
150
+ success: true,
151
+ data: {
152
+ commands_executed: commands.length,
153
+ command_results: commandResults,
154
+ output: commandResults[commandResults.length - 1]?.stdout.trim() ?? '',
155
+ },
156
+ };
157
+ }
158
+
159
+ const simpleGitStatus = await trySimpleGitStatus(cwd);
160
+ if (simpleGitStatus !== null) {
161
+ return {
162
+ success: true,
163
+ data: {
164
+ status: simpleGitStatus,
165
+ source: 'simple-git',
166
+ },
167
+ };
168
+ }
169
+
170
+ const status = runGit(['status', '--short'], { cwd });
171
+ if (!status.ok) {
172
+ return {
173
+ success: false,
174
+ error: {
175
+ code: 'git_status_failed',
176
+ message: status.stderr || status.stdout || 'git status failed.',
177
+ },
178
+ };
179
+ }
180
+
181
+ return {
182
+ success: true,
183
+ data: {
184
+ status: status.stdout.trim(),
185
+ source: 'child_process',
186
+ },
187
+ };
188
+ }
189
+
190
+ export async function gitAddTool(
191
+ input: Record<string, unknown>,
192
+ cwd: string,
193
+ ): Promise<GitToolOutput> {
194
+ ensureRepository(cwd);
195
+ const files = Array.isArray(input.files) ? input.files.map((file) => String(file)) : [];
196
+ const args = ['add', ...(files.length > 0 ? files : ['-A'])];
197
+ const result = runGit(args, { cwd });
198
+ if (!result.ok) {
199
+ return {
200
+ success: false,
201
+ error: {
202
+ code: 'git_add_failed',
203
+ message: result.stderr || result.stdout || 'git add failed.',
204
+ },
205
+ };
206
+ }
207
+
208
+ return {
209
+ success: true,
210
+ data: {
211
+ staged: files,
212
+ },
213
+ metadata: {
214
+ artifacts_written: files,
215
+ },
216
+ };
217
+ }
218
+
219
+ export async function gitCommitTool(
220
+ input: Record<string, unknown>,
221
+ cwd: string,
222
+ ): Promise<GitToolOutput> {
223
+ ensureRepository(cwd);
224
+
225
+ const message =
226
+ typeof input.message === 'string' && input.message.length > 0 ? input.message : null;
227
+ if (!message) {
228
+ return {
229
+ success: false,
230
+ error: {
231
+ code: 'invalid_message',
232
+ message: 'Commit message is required.',
233
+ },
234
+ };
235
+ }
236
+
237
+ const files = Array.isArray(input.files) ? input.files.map((file) => String(file)) : [];
238
+ if (files.length > 0) {
239
+ const stage = runGit(['add', ...files], { cwd });
240
+ if (!stage.ok) {
241
+ return {
242
+ success: false,
243
+ error: {
244
+ code: 'git_add_failed',
245
+ message: stage.stderr || stage.stdout || 'git add failed before commit.',
246
+ },
247
+ };
248
+ }
249
+ }
250
+
251
+ const commit = runGit(['commit', '--no-gpg-sign', '-m', message], { cwd });
252
+ if (!commit.ok) {
253
+ return {
254
+ success: false,
255
+ error: {
256
+ code: 'git_commit_failed',
257
+ message: commit.stderr || commit.stdout || 'git commit failed.',
258
+ },
259
+ metadata: {
260
+ artifacts_written: files,
261
+ },
262
+ };
263
+ }
264
+
265
+ const hash = runGit(['rev-parse', 'HEAD'], { cwd });
266
+ return {
267
+ success: true,
268
+ data: {
269
+ commit: hash.ok ? hash.stdout.trim() : null,
270
+ output: commit.stdout.trim(),
271
+ },
272
+ metadata: {
273
+ artifacts_written: files,
274
+ },
275
+ };
276
+ }
277
+
278
+ export async function runGitToolThroughToolHost(input: {
279
+ toolName: GitToolName;
280
+ input: Record<string, unknown>;
281
+ context: GitToolContext;
282
+ }): Promise<GitToolHostReceipt> {
283
+ const started: ToolCallStartedReceipt = {
284
+ schema_version: 1,
285
+ kind: 'tool_call_started',
286
+ run_id: input.context.run_id,
287
+ task_id: input.context.task_id,
288
+ session_id: input.context.session_id,
289
+ tool_name: input.toolName,
290
+ };
291
+
292
+ let output: GitToolOutput;
293
+ if (input.toolName === 'git:add') {
294
+ output = await gitAddTool(input.input, input.context.cwd);
295
+ } else if (input.toolName === 'git:status') {
296
+ output = await gitStatusTool(input.input, input.context.cwd);
297
+ } else {
298
+ output = await gitCommitTool(input.input, input.context.cwd);
299
+ }
300
+
301
+ const finished: ToolCallFinishedReceipt = {
302
+ schema_version: 1,
303
+ kind: 'tool_call_finished',
304
+ result: output.success ? 'success' : 'failure',
305
+ artifacts_written:
306
+ output.metadata?.artifacts_written && output.metadata.artifacts_written.length > 0
307
+ ? output.metadata.artifacts_written
308
+ : [],
309
+ };
310
+
311
+ return {
312
+ started,
313
+ finished,
314
+ output,
315
+ };
316
+ }
@@ -0,0 +1,15 @@
1
+ // Copyright (c) 2026 Hellmai Ltd
2
+ // SPDX-License-Identifier: AGPL-3.0-only
3
+
4
+ export * from './delegation-tools.js';
5
+ export * from './agent-tools.js';
6
+ export * from './flow-metrics-tools.js';
7
+ export * from './git-runner.js';
8
+ export * from './git-tools.js';
9
+ export * from './initiative-orchestration-tools.js';
10
+ export * from './lane-lock.js';
11
+ export * from './memory-tools.js';
12
+ export * from './runtime-native-tools.js';
13
+ export * from './wu-lifecycle-tools.js';
14
+ export * from './worker-loader.js';
15
+ export * from './worktree-tools.js';