@probelabs/visor 0.1.107 → 0.1.111

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 (235) hide show
  1. package/README.md +6 -0
  2. package/defaults/task-refinement.yaml +7 -3
  3. package/defaults/visor.tests.yaml +13 -2
  4. package/defaults/visor.yaml +1 -0
  5. package/dist/663.index.js +3 -2
  6. package/dist/80.index.js +3 -2
  7. package/dist/ai-review-service.d.ts +13 -9
  8. package/dist/ai-review-service.d.ts.map +1 -1
  9. package/dist/cli-main.d.ts.map +1 -1
  10. package/dist/cli.d.ts.map +1 -1
  11. package/dist/config.d.ts.map +1 -1
  12. package/dist/debug-visualizer/ws-server.d.ts +7 -1
  13. package/dist/debug-visualizer/ws-server.d.ts.map +1 -1
  14. package/dist/defaults/task-refinement.yaml +7 -3
  15. package/dist/defaults/visor.tests.yaml +13 -2
  16. package/dist/defaults/visor.yaml +1 -0
  17. package/dist/docs/advanced-ai.md +60 -1
  18. package/dist/docs/ai-configuration.md +67 -0
  19. package/dist/docs/ai-custom-tools-usage.md +261 -0
  20. package/dist/docs/ai-custom-tools.md +392 -0
  21. package/dist/docs/bot-transports-rfc.md +23 -0
  22. package/dist/docs/configuration.md +21 -0
  23. package/dist/docs/engine-pause-resume-rfc.md +192 -0
  24. package/dist/docs/lifecycle-hooks.md +253 -0
  25. package/dist/docs/liquid-templates.md +143 -0
  26. package/dist/docs/providers/git-checkout.md +589 -0
  27. package/dist/docs/recipes.md +458 -5
  28. package/dist/docs/rfc/git-checkout-step.md +601 -0
  29. package/dist/docs/rfc/on_init-hook.md +1294 -0
  30. package/dist/docs/rfc/workspace-isolation.md +216 -0
  31. package/dist/docs/router-patterns.md +339 -0
  32. package/dist/event-bus/types.d.ts +14 -0
  33. package/dist/event-bus/types.d.ts.map +1 -1
  34. package/dist/examples/ai-custom-tools-example.yaml +206 -0
  35. package/dist/examples/ai-custom-tools-simple.yaml +76 -0
  36. package/dist/examples/git-checkout-basic.yaml +32 -0
  37. package/dist/examples/git-checkout-compare.yaml +59 -0
  38. package/dist/examples/git-checkout-cross-repo.yaml +76 -0
  39. package/dist/examples/on-init-import-demo.yaml +179 -0
  40. package/dist/examples/reusable-tools.yaml +92 -0
  41. package/dist/examples/reusable-workflows.yaml +88 -0
  42. package/dist/examples/session-reuse-self.yaml +81 -0
  43. package/dist/examples/slack-simple-chat.yaml +775 -0
  44. package/dist/failure-condition-evaluator.d.ts +2 -0
  45. package/dist/failure-condition-evaluator.d.ts.map +1 -1
  46. package/dist/frontends/github-frontend.d.ts +20 -0
  47. package/dist/frontends/github-frontend.d.ts.map +1 -1
  48. package/dist/frontends/host.d.ts +4 -0
  49. package/dist/frontends/host.d.ts.map +1 -1
  50. package/dist/frontends/slack-frontend.d.ts +58 -0
  51. package/dist/frontends/slack-frontend.d.ts.map +1 -0
  52. package/dist/generated/config-schema.d.ts +409 -41
  53. package/dist/generated/config-schema.d.ts.map +1 -1
  54. package/dist/generated/config-schema.json +436 -47
  55. package/dist/github-comments.d.ts +2 -0
  56. package/dist/github-comments.d.ts.map +1 -1
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +83587 -56085
  59. package/dist/liquid-extensions.d.ts.map +1 -1
  60. package/dist/logger.d.ts +1 -0
  61. package/dist/logger.d.ts.map +1 -1
  62. package/dist/output/traces/{run-2025-11-21T11-50-46-505Z.ndjson → run-2026-01-20T19-22-58-043Z.ndjson} +91 -91
  63. package/dist/output/traces/run-2026-01-20T19-23-52-175Z.ndjson +1067 -0
  64. package/dist/output-formatters.d.ts.map +1 -1
  65. package/dist/providers/ai-check-provider.d.ts +12 -0
  66. package/dist/providers/ai-check-provider.d.ts.map +1 -1
  67. package/dist/providers/check-provider-registry.d.ts.map +1 -1
  68. package/dist/providers/check-provider.interface.d.ts +9 -0
  69. package/dist/providers/check-provider.interface.d.ts.map +1 -1
  70. package/dist/providers/command-check-provider.d.ts.map +1 -1
  71. package/dist/providers/custom-tool-executor.d.ts.map +1 -1
  72. package/dist/providers/git-checkout-provider.d.ts +25 -0
  73. package/dist/providers/git-checkout-provider.d.ts.map +1 -0
  74. package/dist/providers/http-client-provider.d.ts +3 -0
  75. package/dist/providers/http-client-provider.d.ts.map +1 -1
  76. package/dist/providers/human-input-check-provider.d.ts +2 -0
  77. package/dist/providers/human-input-check-provider.d.ts.map +1 -1
  78. package/dist/providers/log-check-provider.d.ts.map +1 -1
  79. package/dist/providers/mcp-check-provider.d.ts +1 -1
  80. package/dist/providers/mcp-check-provider.d.ts.map +1 -1
  81. package/dist/providers/mcp-custom-sse-server.d.ts +66 -0
  82. package/dist/providers/mcp-custom-sse-server.d.ts.map +1 -0
  83. package/dist/providers/memory-check-provider.d.ts.map +1 -1
  84. package/dist/providers/script-check-provider.d.ts.map +1 -1
  85. package/dist/providers/workflow-check-provider.d.ts.map +1 -1
  86. package/dist/reviewer.d.ts.map +1 -1
  87. package/dist/sdk/check-provider-registry-534KL5HT.mjs +27 -0
  88. package/dist/sdk/chunk-23L3QRYX.mjs +16872 -0
  89. package/dist/sdk/chunk-23L3QRYX.mjs.map +1 -0
  90. package/dist/sdk/{chunk-OOZITMRU.mjs → chunk-3OMWVM6J.mjs} +11 -1
  91. package/dist/sdk/{chunk-OOZITMRU.mjs.map → chunk-3OMWVM6J.mjs.map} +1 -1
  92. package/dist/sdk/{chunk-37ZSCMFC.mjs → chunk-7UK3NIIT.mjs} +2 -2
  93. package/dist/sdk/{chunk-VMPLF6FT.mjs → chunk-AGIZJ4UZ.mjs} +50 -4
  94. package/dist/sdk/chunk-AGIZJ4UZ.mjs.map +1 -0
  95. package/dist/sdk/{chunk-IEO6CFLG.mjs → chunk-AIVFBIS4.mjs} +161 -5
  96. package/dist/sdk/chunk-AIVFBIS4.mjs.map +1 -0
  97. package/dist/sdk/chunk-AK6BVWIT.mjs +426 -0
  98. package/dist/sdk/chunk-AK6BVWIT.mjs.map +1 -0
  99. package/dist/sdk/chunk-AUT26LHW.mjs +139 -0
  100. package/dist/sdk/chunk-AUT26LHW.mjs.map +1 -0
  101. package/dist/sdk/chunk-BOVFH3LI.mjs +232 -0
  102. package/dist/sdk/chunk-BOVFH3LI.mjs.map +1 -0
  103. package/dist/sdk/chunk-HTOKWMPO.mjs +157 -0
  104. package/dist/sdk/chunk-HTOKWMPO.mjs.map +1 -0
  105. package/dist/sdk/{chunk-6Y4YTKCF.mjs → chunk-NAW3DB3I.mjs} +2 -2
  106. package/dist/sdk/{chunk-OWUVOILT.mjs → chunk-QR7MOMJH.mjs} +4 -3
  107. package/dist/sdk/{chunk-OWUVOILT.mjs.map → chunk-QR7MOMJH.mjs.map} +1 -1
  108. package/dist/sdk/{chunk-PTL3K3PN.mjs → chunk-QY2XYPEV.mjs} +488 -60
  109. package/dist/sdk/chunk-QY2XYPEV.mjs.map +1 -0
  110. package/dist/sdk/{chunk-OZJ263FM.mjs → chunk-SIWNBRTK.mjs} +29 -215
  111. package/dist/sdk/chunk-SIWNBRTK.mjs.map +1 -0
  112. package/dist/sdk/command-executor-TYUV6HUS.mjs +14 -0
  113. package/dist/sdk/{config-M4ZNO6NU.mjs → config-YNC2EOOT.mjs} +5 -3
  114. package/dist/sdk/{failure-condition-evaluator-NBO5YRXW.mjs → failure-condition-evaluator-YGTF2GHG.mjs} +6 -5
  115. package/dist/sdk/{github-frontend-4AWRJT7D.mjs → github-frontend-SIAEOCON.mjs} +190 -12
  116. package/dist/sdk/github-frontend-SIAEOCON.mjs.map +1 -0
  117. package/dist/sdk/{host-7GBC3S7L.mjs → host-DXUYTNMU.mjs} +5 -2
  118. package/dist/sdk/host-DXUYTNMU.mjs.map +1 -0
  119. package/dist/sdk/{liquid-extensions-C7EG3YKH.mjs → liquid-extensions-PKWCKK7E.mjs} +5 -4
  120. package/dist/sdk/memory-store-XGBB7LX7.mjs +12 -0
  121. package/dist/sdk/prompt-state-YRJY6QAL.mjs +16 -0
  122. package/dist/sdk/{renderer-schema-6RF26VUS.mjs → renderer-schema-LPKN5UJS.mjs} +3 -2
  123. package/dist/sdk/{renderer-schema-6RF26VUS.mjs.map → renderer-schema-LPKN5UJS.mjs.map} +1 -1
  124. package/dist/sdk/{routing-RP56JTV2.mjs → routing-6N45MJ4F.mjs} +7 -6
  125. package/dist/sdk/sdk.d.mts +219 -5
  126. package/dist/sdk/sdk.d.ts +219 -5
  127. package/dist/sdk/sdk.js +21329 -14908
  128. package/dist/sdk/sdk.js.map +1 -1
  129. package/dist/sdk/sdk.mjs +407 -12874
  130. package/dist/sdk/sdk.mjs.map +1 -1
  131. package/dist/sdk/{session-registry-N5FFYFTM.mjs → session-registry-4E6YRQ77.mjs} +2 -2
  132. package/dist/sdk/session-registry-4E6YRQ77.mjs.map +1 -0
  133. package/dist/sdk/slack-frontend-BVKW3GD5.mjs +735 -0
  134. package/dist/sdk/slack-frontend-BVKW3GD5.mjs.map +1 -0
  135. package/dist/sdk/{tracer-init-WP4X46IF.mjs → tracer-init-GSLPPLCD.mjs} +2 -2
  136. package/dist/sdk/tracer-init-GSLPPLCD.mjs.map +1 -0
  137. package/dist/sdk/workflow-registry-R6KSACFR.mjs +12 -0
  138. package/dist/sdk/workflow-registry-R6KSACFR.mjs.map +1 -0
  139. package/dist/slack/adapter.d.ts +36 -0
  140. package/dist/slack/adapter.d.ts.map +1 -0
  141. package/dist/slack/cache-prewarmer.d.ts +31 -0
  142. package/dist/slack/cache-prewarmer.d.ts.map +1 -0
  143. package/dist/slack/client.d.ts +77 -0
  144. package/dist/slack/client.d.ts.map +1 -0
  145. package/dist/slack/markdown.d.ts +45 -0
  146. package/dist/slack/markdown.d.ts.map +1 -0
  147. package/dist/slack/prompt-state.d.ts +33 -0
  148. package/dist/slack/prompt-state.d.ts.map +1 -0
  149. package/dist/slack/rate-limiter.d.ts +56 -0
  150. package/dist/slack/rate-limiter.d.ts.map +1 -0
  151. package/dist/slack/signature.d.ts +2 -0
  152. package/dist/slack/signature.d.ts.map +1 -0
  153. package/dist/slack/socket-runner.d.ts +42 -0
  154. package/dist/slack/socket-runner.d.ts.map +1 -0
  155. package/dist/slack/thread-cache.d.ts +51 -0
  156. package/dist/slack/thread-cache.d.ts.map +1 -0
  157. package/dist/state-machine/context/build-engine-context.d.ts +8 -0
  158. package/dist/state-machine/context/build-engine-context.d.ts.map +1 -1
  159. package/dist/state-machine/dispatch/execution-invoker.d.ts.map +1 -1
  160. package/dist/state-machine/dispatch/foreach-processor.d.ts.map +1 -1
  161. package/dist/state-machine/dispatch/on-init-handlers.d.ts +43 -0
  162. package/dist/state-machine/dispatch/on-init-handlers.d.ts.map +1 -0
  163. package/dist/state-machine/dispatch/stats-manager.d.ts.map +1 -1
  164. package/dist/state-machine/dispatch/template-renderer.d.ts.map +1 -1
  165. package/dist/state-machine/runner.d.ts +6 -0
  166. package/dist/state-machine/runner.d.ts.map +1 -1
  167. package/dist/state-machine/states/level-dispatch.d.ts.map +1 -1
  168. package/dist/state-machine/states/plan-ready.d.ts.map +1 -1
  169. package/dist/state-machine/states/routing.d.ts.map +1 -1
  170. package/dist/state-machine/states/wave-planning.d.ts.map +1 -1
  171. package/dist/state-machine/workflow-projection.d.ts.map +1 -1
  172. package/dist/state-machine-execution-engine.d.ts +21 -9
  173. package/dist/state-machine-execution-engine.d.ts.map +1 -1
  174. package/dist/telemetry/state-capture.d.ts +5 -0
  175. package/dist/telemetry/state-capture.d.ts.map +1 -1
  176. package/dist/test-runner/core/flow-stage.d.ts.map +1 -1
  177. package/dist/test-runner/core/test-execution-wrapper.d.ts.map +1 -1
  178. package/dist/test-runner/evaluators.d.ts +37 -4
  179. package/dist/test-runner/evaluators.d.ts.map +1 -1
  180. package/dist/test-runner/index.d.ts +7 -0
  181. package/dist/test-runner/index.d.ts.map +1 -1
  182. package/dist/test-runner/recorders/slack-recorder.d.ts +17 -0
  183. package/dist/test-runner/recorders/slack-recorder.d.ts.map +1 -0
  184. package/dist/test-runner/validator.d.ts.map +1 -1
  185. package/dist/traces/{run-2025-11-21T11-50-46-505Z.ndjson → run-2026-01-20T19-22-58-043Z.ndjson} +91 -91
  186. package/dist/traces/run-2026-01-20T19-23-52-175Z.ndjson +1067 -0
  187. package/dist/types/bot.d.ts +109 -0
  188. package/dist/types/bot.d.ts.map +1 -0
  189. package/dist/types/cli.d.ts +4 -0
  190. package/dist/types/cli.d.ts.map +1 -1
  191. package/dist/types/config.d.ts +182 -5
  192. package/dist/types/config.d.ts.map +1 -1
  193. package/dist/types/engine.d.ts +5 -0
  194. package/dist/types/engine.d.ts.map +1 -1
  195. package/dist/types/git-checkout.d.ts +76 -0
  196. package/dist/types/git-checkout.d.ts.map +1 -0
  197. package/dist/utils/json-text-extractor.d.ts +17 -0
  198. package/dist/utils/json-text-extractor.d.ts.map +1 -0
  199. package/dist/utils/sandbox.d.ts +10 -0
  200. package/dist/utils/sandbox.d.ts.map +1 -1
  201. package/dist/utils/template-context.d.ts +1 -0
  202. package/dist/utils/template-context.d.ts.map +1 -1
  203. package/dist/utils/tracer-init.d.ts.map +1 -1
  204. package/dist/utils/workspace-manager.d.ts +118 -0
  205. package/dist/utils/workspace-manager.d.ts.map +1 -0
  206. package/dist/utils/worktree-cleanup.d.ts +33 -0
  207. package/dist/utils/worktree-cleanup.d.ts.map +1 -0
  208. package/dist/utils/worktree-manager.d.ts +153 -0
  209. package/dist/utils/worktree-manager.d.ts.map +1 -0
  210. package/dist/webhook-server.d.ts.map +1 -1
  211. package/dist/workflow-executor.d.ts.map +1 -1
  212. package/dist/workflow-registry.d.ts.map +1 -1
  213. package/package.json +4 -2
  214. package/dist/output/traces/run-2025-11-21T11-51-33-674Z.ndjson +0 -839
  215. package/dist/sdk/chunk-IEO6CFLG.mjs.map +0 -1
  216. package/dist/sdk/chunk-JEHPDJIF.mjs +0 -223
  217. package/dist/sdk/chunk-JEHPDJIF.mjs.map +0 -1
  218. package/dist/sdk/chunk-OZJ263FM.mjs.map +0 -1
  219. package/dist/sdk/chunk-PTL3K3PN.mjs.map +0 -1
  220. package/dist/sdk/chunk-VMPLF6FT.mjs.map +0 -1
  221. package/dist/sdk/github-frontend-4AWRJT7D.mjs.map +0 -1
  222. package/dist/sdk/host-7GBC3S7L.mjs.map +0 -1
  223. package/dist/sdk/memory-store-GJACZC2A.mjs +0 -11
  224. package/dist/sdk/workflow-registry-2YIIXQCK.mjs +0 -11
  225. package/dist/traces/run-2025-11-21T11-51-33-674Z.ndjson +0 -839
  226. /package/dist/sdk/{config-M4ZNO6NU.mjs.map → check-provider-registry-534KL5HT.mjs.map} +0 -0
  227. /package/dist/sdk/{chunk-37ZSCMFC.mjs.map → chunk-7UK3NIIT.mjs.map} +0 -0
  228. /package/dist/sdk/{chunk-6Y4YTKCF.mjs.map → chunk-NAW3DB3I.mjs.map} +0 -0
  229. /package/dist/sdk/{failure-condition-evaluator-NBO5YRXW.mjs.map → command-executor-TYUV6HUS.mjs.map} +0 -0
  230. /package/dist/sdk/{liquid-extensions-C7EG3YKH.mjs.map → config-YNC2EOOT.mjs.map} +0 -0
  231. /package/dist/sdk/{memory-store-GJACZC2A.mjs.map → failure-condition-evaluator-YGTF2GHG.mjs.map} +0 -0
  232. /package/dist/sdk/{routing-RP56JTV2.mjs.map → liquid-extensions-PKWCKK7E.mjs.map} +0 -0
  233. /package/dist/sdk/{session-registry-N5FFYFTM.mjs.map → memory-store-XGBB7LX7.mjs.map} +0 -0
  234. /package/dist/sdk/{tracer-init-WP4X46IF.mjs.map → prompt-state-YRJY6QAL.mjs.map} +0 -0
  235. /package/dist/sdk/{workflow-registry-2YIIXQCK.mjs.map → routing-6N45MJ4F.mjs.map} +0 -0
@@ -0,0 +1,601 @@
1
+ # RFC: Git Checkout Step Provider
2
+
3
+ ## Status
4
+ **Accepted** - Implementation in progress
5
+
6
+ ### Decision Record
7
+ - **Date**: 2025-11-21
8
+ - **Decision**: Implement git worktrees from day one
9
+ - **Rationale**: Provides the most scalable solution for parallel workflows, better disk efficiency, and matches our long-term vision. The complexity is manageable and the benefits justify the initial investment.
10
+
11
+ ## Summary
12
+ Add a `git-checkout` check provider that enables workflows to checkout code from git repositories, supporting dynamic branch resolution, git worktrees for efficient multi-workflow execution, and proper cleanup strategies.
13
+
14
+ ## Motivation
15
+
16
+ Currently, Visor workflows operate on the existing codebase in the working directory. To enable more advanced workflows, we need:
17
+
18
+ 1. **Isolated workspaces**: Multiple workflows running in parallel need separate working directories
19
+ 2. **Version flexibility**: Ability to checkout different branches, commits, or PRs
20
+ 3. **Performance**: Reuse git objects across workflows via git worktrees
21
+ 4. **Dynamic branches**: Checkout based on PR context or previous step outputs
22
+ 5. **GitHub Actions parity**: Similar functionality to `actions/checkout@v4`
23
+
24
+ ## Design Goals
25
+
26
+ - **Efficient**: Use git worktrees to share objects between multiple checkouts
27
+ - **Safe**: Proper cleanup on workflow completion, avoid orphaned worktrees
28
+ - **Flexible**: Support dynamic variable resolution for branches, refs, etc.
29
+ - **Compatible**: Work with existing workflow patterns and dependency chains
30
+ - **Configurable**: Allow global worktree cache location configuration
31
+
32
+ ## Detailed Design
33
+
34
+ ### 1. Provider Interface
35
+
36
+ ```typescript
37
+ class GitCheckoutProvider extends CheckProvider {
38
+ getName(): string {
39
+ return 'git-checkout';
40
+ }
41
+
42
+ async execute(
43
+ prInfo: PRInfo,
44
+ config: GitCheckoutConfig,
45
+ dependencyResults?: Map<string, ReviewSummary>,
46
+ context?: ExecutionContext
47
+ ): Promise<ReviewSummary> {
48
+ // Implementation details below
49
+ }
50
+ }
51
+ ```
52
+
53
+ ### 2. Configuration Schema
54
+
55
+ ```yaml
56
+ version: "1.0"
57
+
58
+ # Optional global configuration
59
+ worktree_cache:
60
+ enabled: true
61
+ base_path: .visor/worktrees # Default: .visor/worktrees/ in project root
62
+ cleanup_on_exit: true # Default: true
63
+ max_age_hours: 24 # Cleanup worktrees older than this
64
+
65
+ steps:
66
+ checkout-pr:
67
+ type: git-checkout
68
+
69
+ # Git reference to checkout (supports dynamic variables)
70
+ ref: "{{ pr.head }}" # Can be: branch, tag, commit SHA, or "pr.head"/"pr.base"
71
+
72
+ # Repository configuration
73
+ repository: "" # Default: current repository (from prInfo.repo)
74
+ token: "{{ env.GITHUB_TOKEN }}" # Default: use GITHUB_TOKEN env var
75
+
76
+ # Fetch configuration (similar to actions/checkout)
77
+ fetch_depth: 1 # Default: 1 (shallow clone)
78
+ fetch_tags: false # Default: false
79
+ submodules: false # Default: false, can be: true, false, 'recursive'
80
+
81
+ # Worktree configuration
82
+ working_directory: "" # Default: auto-generated based on ref
83
+ use_worktree: true # Default: true (use worktrees for efficiency)
84
+ clean: true # Default: true (clean working dir before checkout)
85
+
86
+ # Advanced options
87
+ sparse_checkout: [] # Optional: array of paths for sparse checkout
88
+ lfs: false # Default: false (git-lfs support)
89
+
90
+ # Standard check options
91
+ timeout: 60 # Default: 60 seconds
92
+ criticality: internal
93
+ assume: "true"
94
+ guarantee: "output.success == true && output.path != null"
95
+
96
+ # Cleanup behavior
97
+ cleanup_on_failure: true # Default: true
98
+ persist_worktree: false # Default: false (cleanup after workflow)
99
+ ```
100
+
101
+ ### 3. Output Schema
102
+
103
+ The provider returns a `ReviewSummary` with:
104
+
105
+ ```typescript
106
+ {
107
+ issues: [], // Empty on success, contains error issues on failure
108
+ output: {
109
+ success: boolean,
110
+ path: string, // Absolute path to checked out code
111
+ ref: string, // Resolved ref that was checked out
112
+ commit: string, // Full commit SHA
113
+ worktree_id: string, // Unique worktree identifier
114
+ repository: string, // Repository that was checked out
115
+ is_worktree: boolean, // Whether this is a worktree or regular clone
116
+ }
117
+ }
118
+ ```
119
+
120
+ ### 4. Git Worktree Architecture
121
+
122
+ #### 4.1 Worktree Storage Structure
123
+
124
+ By default, worktrees are stored in `.visor/worktrees/` in the project root:
125
+
126
+ ```
127
+ .visor/worktrees/
128
+ ├── repos/
129
+ │ ├── owner-repo1.git/ # Bare repository (shared)
130
+ │ │ ├── objects/ # Git objects (shared across worktrees)
131
+ │ │ ├── refs/
132
+ │ │ └── worktrees/
133
+ │ │ ├── worktree-abc123/ # Worktree metadata
134
+ │ │ └── worktree-def456/
135
+ │ └── owner-repo2.git/
136
+ └── worktrees/
137
+ ├── owner-repo1-abc123/ # Actual working directory
138
+ │ └── .git -> ../repos/owner-repo1.git/worktrees/worktree-abc123/
139
+ └── owner-repo1-def456/
140
+ ```
141
+
142
+ **Benefits of project-local storage:**
143
+ - Worktrees remain with the project
144
+ - Easy to locate and debug
145
+ - Can be excluded from version control (add `.visor/worktrees/` to `.gitignore`)
146
+ - Automatic cleanup when removing the project
147
+ - No pollution of system-wide temp directories
148
+
149
+ **Configuration:**
150
+ - Default: `.visor/worktrees/` (relative to project root)
151
+ - Environment variable: `VISOR_WORKTREE_PATH=/custom/path`
152
+ - Config file: `worktree_cache.base_path: /custom/path`
153
+
154
+ #### 4.2 Worktree Lifecycle
155
+
156
+ 1. **Initialization**:
157
+ - Check if bare repo exists at `${base_path}/repos/${owner}-${repo}.git`
158
+ - If not, create: `git clone --bare ${repo_url} ${bare_repo_path}`
159
+ - If exists, update: `git -C ${bare_repo_path} remote update`
160
+
161
+ 2. **Worktree Creation**:
162
+ - Generate unique worktree ID: `${repo}-${ref_sanitized}-${short_hash}`
163
+ - Create worktree: `git -C ${bare_repo_path} worktree add ${worktree_path} ${ref}`
164
+ - Track in metadata file: `${worktree_path}/.visor-metadata.json`
165
+
166
+ 3. **Worktree Reuse**:
167
+ - Check if worktree for same ref already exists
168
+ - If `clean: true`, reset and clean: `git reset --hard && git clean -fdx`
169
+ - If `clean: false`, reuse as-is
170
+
171
+ 4. **Cleanup**:
172
+ - On workflow completion: Remove worktree unless `persist_worktree: true`
173
+ - On failure: Remove worktree if `cleanup_on_failure: true`
174
+ - Command: `git -C ${bare_repo_path} worktree remove ${worktree_path} --force`
175
+
176
+ #### 4.3 Metadata Tracking
177
+
178
+ Each worktree maintains metadata for tracking and cleanup:
179
+
180
+ ```json
181
+ {
182
+ "worktree_id": "owner-repo-main-abc123",
183
+ "created_at": "2025-11-21T10:00:00Z",
184
+ "workflow_id": "workflow-xyz",
185
+ "ref": "refs/heads/main",
186
+ "commit": "1234567890abcdef",
187
+ "repository": "owner/repo",
188
+ "pid": 12345,
189
+ "cleanup_on_exit": true
190
+ }
191
+ ```
192
+
193
+ ### 5. Dynamic Variable Resolution
194
+
195
+ The provider supports Liquid templates for dynamic values:
196
+
197
+ ```yaml
198
+ steps:
199
+ checkout-head:
200
+ type: git-checkout
201
+ ref: "{{ pr.head }}" # Resolves to PR head branch
202
+
203
+ checkout-base:
204
+ type: git-checkout
205
+ ref: "{{ pr.base }}" # Resolves to PR base branch
206
+
207
+ checkout-from-previous:
208
+ type: git-checkout
209
+ depends_on: [determine-branch]
210
+ ref: "{{ outputs['determine-branch'].branch }}" # From previous step
211
+
212
+ checkout-with-depth:
213
+ type: git-checkout
214
+ ref: main
215
+ fetch_depth: "{{ outputs.config.depth | default: 10 }}" # Dynamic depth
216
+ ```
217
+
218
+ ### 6. Cleanup Strategies
219
+
220
+ #### 6.1 Automatic Cleanup (Default)
221
+
222
+ - **On workflow completion**: Remove all worktrees created by workflow
223
+ - **On process exit**: Cleanup handler removes worktrees (via `process.on('exit')`)
224
+ - **Stale worktree cleanup**: Background task removes worktrees older than `max_age_hours`
225
+
226
+ #### 6.2 Manual Cleanup
227
+
228
+ - **CLI command**: `visor worktree cleanup [--all] [--repo=owner/repo]`
229
+ - **Config option**: `persist_worktree: true` to keep worktree after workflow
230
+
231
+ #### 6.3 Cleanup Safety
232
+
233
+ - **Lock files**: Use lock files to prevent cleanup of active worktrees
234
+ - **PID tracking**: Check if PID in metadata is still alive before cleanup
235
+ - **Graceful degradation**: If cleanup fails, log warning but don't fail workflow
236
+
237
+ ### 7. Error Handling
238
+
239
+ ```typescript
240
+ // Timeout handling
241
+ if (timeoutExceeded) {
242
+ return {
243
+ issues: [{
244
+ file: 'git-checkout',
245
+ line: 0,
246
+ ruleId: 'git-checkout/timeout',
247
+ message: `Checkout timed out after ${timeout}s`,
248
+ severity: 'error',
249
+ category: 'logic',
250
+ }],
251
+ output: { success: false, error: 'timeout' }
252
+ };
253
+ }
254
+
255
+ // Git command failures
256
+ if (exitCode !== 0) {
257
+ return {
258
+ issues: [{
259
+ file: 'git-checkout',
260
+ line: 0,
261
+ ruleId: 'git-checkout/git_error',
262
+ message: `Git checkout failed: ${stderr}`,
263
+ severity: 'error',
264
+ category: 'logic',
265
+ }],
266
+ output: { success: false, error: stderr }
267
+ };
268
+ }
269
+
270
+ // Invalid ref
271
+ if (refNotFound) {
272
+ return {
273
+ issues: [{
274
+ file: 'git-checkout',
275
+ line: 0,
276
+ ruleId: 'git-checkout/invalid_ref',
277
+ message: `Invalid ref: ${ref}`,
278
+ severity: 'error',
279
+ category: 'logic',
280
+ }],
281
+ output: { success: false, error: 'invalid_ref' }
282
+ };
283
+ }
284
+ ```
285
+
286
+ ### 8. Integration with Existing Providers
287
+
288
+ #### 8.1 Use with Command Provider
289
+
290
+ ```yaml
291
+ steps:
292
+ checkout:
293
+ type: git-checkout
294
+ ref: "{{ pr.head }}"
295
+
296
+ build:
297
+ type: command
298
+ depends_on: [checkout]
299
+ exec: "npm run build"
300
+ working_directory: "{{ outputs.checkout.path }}"
301
+ assume: "outputs.checkout.success"
302
+ ```
303
+
304
+ #### 8.2 Use with MCP Provider
305
+
306
+ ```yaml
307
+ steps:
308
+ checkout:
309
+ type: git-checkout
310
+ ref: main
311
+
312
+ analyze:
313
+ type: mcp
314
+ depends_on: [checkout]
315
+ tool: analyze_codebase
316
+ args:
317
+ path: "{{ outputs.checkout.path }}"
318
+ ```
319
+
320
+ ### 9. GitHub Actions Compatibility
321
+
322
+ Mapping from `actions/checkout@v4` to our provider:
323
+
324
+ | actions/checkout | git-checkout | Notes |
325
+ |-----------------|--------------|-------|
326
+ | `ref` | `ref` | Direct mapping |
327
+ | `repository` | `repository` | Direct mapping |
328
+ | `token` | `token` | Direct mapping |
329
+ | `fetch-depth` | `fetch_depth` | Direct mapping |
330
+ | `fetch-tags` | `fetch_tags` | Direct mapping |
331
+ | `submodules` | `submodules` | Direct mapping |
332
+ | `clean` | `clean` | Direct mapping |
333
+ | `sparse-checkout` | `sparse_checkout` | Direct mapping |
334
+ | `lfs` | `lfs` | Direct mapping |
335
+ | `path` | `working_directory` | Different name |
336
+ | `persist-credentials` | N/A | Always use token |
337
+ | `set-safe-directory` | N/A | Handled automatically |
338
+
339
+ ### 10. Implementation Phases
340
+
341
+ #### Phase 1: Basic Checkout (MVP)
342
+ - Single repository checkout
343
+ - Configurable ref/branch
344
+ - Basic error handling
345
+ - No worktrees (use regular clone)
346
+
347
+ #### Phase 2: Worktree Support
348
+ - Implement worktree architecture
349
+ - Bare repository caching
350
+ - Worktree reuse logic
351
+ - Metadata tracking
352
+
353
+ #### Phase 3: Advanced Features
354
+ - Sparse checkout
355
+ - Submodules support
356
+ - LFS support
357
+ - Parallel workflow safety
358
+
359
+ #### Phase 4: Cleanup & Optimization
360
+ - Automatic cleanup handlers
361
+ - Stale worktree cleanup
362
+ - CLI commands for management
363
+ - Performance optimizations
364
+
365
+ ## Configuration Examples
366
+
367
+ ### Example 1: Simple PR Checkout
368
+
369
+ ```yaml
370
+ version: "1.0"
371
+ steps:
372
+ checkout:
373
+ type: git-checkout
374
+ ref: "{{ pr.head }}"
375
+ ```
376
+
377
+ ### Example 2: Multiple Branch Checkout
378
+
379
+ ```yaml
380
+ version: "1.0"
381
+ steps:
382
+ checkout-head:
383
+ type: git-checkout
384
+ ref: "{{ pr.head }}"
385
+
386
+ checkout-base:
387
+ type: git-checkout
388
+ ref: "{{ pr.base }}"
389
+
390
+ compare:
391
+ type: command
392
+ depends_on: [checkout-head, checkout-base]
393
+ exec: "diff -r {{ outputs['checkout-head'].path }} {{ outputs['checkout-base'].path }}"
394
+ ```
395
+
396
+ ### Example 3: Cross-Repository Checkout
397
+
398
+ ```yaml
399
+ version: "1.0"
400
+ steps:
401
+ checkout-main-repo:
402
+ type: git-checkout
403
+ repository: owner/main-repo
404
+ ref: main
405
+
406
+ checkout-dependency:
407
+ type: git-checkout
408
+ repository: owner/dependency-repo
409
+ ref: v1.0.0
410
+
411
+ integration-test:
412
+ type: command
413
+ depends_on: [checkout-main-repo, checkout-dependency]
414
+ exec: "./run-integration-tests.sh"
415
+ ```
416
+
417
+ ### Example 4: Deep Clone with Submodules
418
+
419
+ ```yaml
420
+ version: "1.0"
421
+ steps:
422
+ checkout-full:
423
+ type: git-checkout
424
+ ref: main
425
+ fetch_depth: 0 # Full history
426
+ fetch_tags: true # Include all tags
427
+ submodules: recursive
428
+ ```
429
+
430
+ ### Example 5: Sparse Checkout
431
+
432
+ ```yaml
433
+ version: "1.0"
434
+ steps:
435
+ checkout-partial:
436
+ type: git-checkout
437
+ ref: main
438
+ sparse_checkout:
439
+ - src/
440
+ - tests/
441
+ - package.json
442
+ ```
443
+
444
+ ## Open Questions
445
+
446
+ 1. **Worktree vs Clone**: Should we default to worktrees or regular clones? Worktrees are more efficient but have complexity.
447
+
448
+ 2. **Cleanup timing**: Should cleanup happen:
449
+ - Immediately after workflow completion?
450
+ - On process exit?
451
+ - Via background cleanup task?
452
+ - All of the above?
453
+
454
+ 3. **Concurrent workflows**: How do we handle multiple workflows trying to use the same worktree?
455
+ - Lock files?
456
+ - Clone per workflow?
457
+ - Reference counting?
458
+
459
+ 4. **Storage limits**: Should we:
460
+ - Limit number of worktrees?
461
+ - Limit total disk usage?
462
+ - Add LRU eviction?
463
+
464
+ 5. **Cross-platform**: How does this work on:
465
+ - Linux (easy)
466
+ - macOS (should work)
467
+ - Windows (git worktrees have issues on older versions)
468
+
469
+ 6. **Authentication**: How to handle:
470
+ - Private repositories?
471
+ - Token expiry?
472
+ - SSH keys vs HTTPS tokens?
473
+
474
+ 7. **Bare repository updates**: ✅ **RESOLVED**
475
+ - **Decision**: Update on every checkout (like GitHub Actions)
476
+ - **Implementation**: `git remote update --prune` runs before each worktree creation
477
+ - **Benefit**: Always get latest code, no stale checkouts
478
+ - **Performance**: ~1-5 seconds for update vs ~30s for full clone
479
+
480
+ 8. **Error recovery**: If worktree is corrupted, should we:
481
+ - Remove and recreate?
482
+ - Fail the workflow?
483
+ - Try to repair?
484
+
485
+ ## Security Considerations
486
+
487
+ 1. **Token handling**: Tokens must be:
488
+ - Stored securely in environment
489
+ - Not logged or exposed in output
490
+ - Redacted from error messages
491
+
492
+ 2. **Path traversal**: Validate `working_directory` to prevent:
493
+ - Path traversal attacks (`../../etc/passwd`)
494
+ - Writing to sensitive directories
495
+
496
+ 3. **Resource exhaustion**: Limit:
497
+ - Number of concurrent checkouts
498
+ - Total disk usage
499
+ - Number of worktrees per repository
500
+
501
+ 4. **Cleanup safety**: Ensure cleanup doesn't:
502
+ - Delete files outside worktree directories
503
+ - Interfere with other processes
504
+ - Remove the bare repository accidentally
505
+
506
+ ## Performance Considerations
507
+
508
+ 1. **Worktree benefits**:
509
+ - Shared objects save disk space
510
+ - Faster checkout (no object download)
511
+ - Better for multiple checkouts of same repo
512
+
513
+ 2. **Worktree overhead**:
514
+ - Initial bare clone is slower
515
+ - Metadata management complexity
516
+ - Cleanup coordination
517
+
518
+ 3. **Optimization opportunities**:
519
+ - Shallow clones for most use cases
520
+ - Reference clones for local development
521
+ - Parallel fetch operations
522
+
523
+ ## Testing Strategy
524
+
525
+ 1. **Unit tests**:
526
+ - Config validation
527
+ - Template resolution
528
+ - Error handling
529
+
530
+ 2. **Integration tests**:
531
+ - Worktree creation/deletion
532
+ - Concurrent workflow handling
533
+ - Cleanup operations
534
+
535
+ 3. **E2E tests**:
536
+ - Full workflow with checkout
537
+ - Multiple repositories
538
+ - Error scenarios
539
+
540
+ 4. **Performance tests**:
541
+ - Checkout speed vs regular clone
542
+ - Concurrent checkout handling
543
+ - Cleanup performance
544
+
545
+ ## Documentation Requirements
546
+
547
+ 1. **User documentation**:
548
+ - Configuration reference
549
+ - Common patterns
550
+ - Troubleshooting guide
551
+
552
+ 2. **Developer documentation**:
553
+ - Architecture overview
554
+ - Worktree management
555
+ - Cleanup strategies
556
+
557
+ 3. **Migration guide**:
558
+ - From regular clones
559
+ - From external checkout steps
560
+
561
+ ## Alternatives Considered
562
+
563
+ ### Alternative 1: No Worktrees, Just Clone
564
+ **Pros**: Simpler implementation, no cleanup complexity
565
+ **Cons**: Slower, wastes disk space, doesn't scale to multiple workflows
566
+
567
+ ### Alternative 2: Use Docker Volumes
568
+ **Pros**: Isolated environments, easy cleanup
569
+ **Cons**: Requires Docker, overhead, not available everywhere
570
+
571
+ ### Alternative 3: Use Existing Checkout Action
572
+ **Pros**: No implementation needed
573
+ **Cons**: Not integrated with workflow system, requires GitHub Actions environment
574
+
575
+ ## Success Metrics
576
+
577
+ 1. **Adoption**: Number of workflows using git-checkout step
578
+ 2. **Performance**: Checkout time compared to regular clone
579
+ 3. **Reliability**: Checkout success rate, cleanup success rate
580
+ 4. **Disk usage**: Average disk savings with worktrees
581
+
582
+ ## References
583
+
584
+ - [GitHub Actions checkout](https://github.com/actions/checkout)
585
+ - [Git worktree documentation](https://git-scm.com/docs/git-worktree)
586
+ - [Git sparse checkout](https://git-scm.com/docs/git-sparse-checkout)
587
+ - Visor check provider architecture (this codebase)
588
+
589
+ ## Feedback Requested
590
+
591
+ 1. Is the worktree approach the right one, or should we start simpler?
592
+ 2. Are the configuration options sufficient? Any missing use cases?
593
+ 3. How important is GitHub Actions compatibility?
594
+ 4. What cleanup strategy feels safest and most intuitive?
595
+ 5. Any concerns about the metadata tracking approach?
596
+
597
+ ---
598
+
599
+ **Author**: Claude (with human guidance)
600
+ **Date**: 2025-11-21
601
+ **Version**: 0.1.0