@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.
- package/README.md +6 -0
- package/defaults/task-refinement.yaml +7 -3
- package/defaults/visor.tests.yaml +13 -2
- package/defaults/visor.yaml +1 -0
- package/dist/663.index.js +3 -2
- package/dist/80.index.js +3 -2
- package/dist/ai-review-service.d.ts +13 -9
- package/dist/ai-review-service.d.ts.map +1 -1
- package/dist/cli-main.d.ts.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/debug-visualizer/ws-server.d.ts +7 -1
- package/dist/debug-visualizer/ws-server.d.ts.map +1 -1
- package/dist/defaults/task-refinement.yaml +7 -3
- package/dist/defaults/visor.tests.yaml +13 -2
- package/dist/defaults/visor.yaml +1 -0
- package/dist/docs/advanced-ai.md +60 -1
- package/dist/docs/ai-configuration.md +67 -0
- package/dist/docs/ai-custom-tools-usage.md +261 -0
- package/dist/docs/ai-custom-tools.md +392 -0
- package/dist/docs/bot-transports-rfc.md +23 -0
- package/dist/docs/configuration.md +21 -0
- package/dist/docs/engine-pause-resume-rfc.md +192 -0
- package/dist/docs/lifecycle-hooks.md +253 -0
- package/dist/docs/liquid-templates.md +143 -0
- package/dist/docs/providers/git-checkout.md +589 -0
- package/dist/docs/recipes.md +458 -5
- package/dist/docs/rfc/git-checkout-step.md +601 -0
- package/dist/docs/rfc/on_init-hook.md +1294 -0
- package/dist/docs/rfc/workspace-isolation.md +216 -0
- package/dist/docs/router-patterns.md +339 -0
- package/dist/event-bus/types.d.ts +14 -0
- package/dist/event-bus/types.d.ts.map +1 -1
- package/dist/examples/ai-custom-tools-example.yaml +206 -0
- package/dist/examples/ai-custom-tools-simple.yaml +76 -0
- package/dist/examples/git-checkout-basic.yaml +32 -0
- package/dist/examples/git-checkout-compare.yaml +59 -0
- package/dist/examples/git-checkout-cross-repo.yaml +76 -0
- package/dist/examples/on-init-import-demo.yaml +179 -0
- package/dist/examples/reusable-tools.yaml +92 -0
- package/dist/examples/reusable-workflows.yaml +88 -0
- package/dist/examples/session-reuse-self.yaml +81 -0
- package/dist/examples/slack-simple-chat.yaml +775 -0
- package/dist/failure-condition-evaluator.d.ts +2 -0
- package/dist/failure-condition-evaluator.d.ts.map +1 -1
- package/dist/frontends/github-frontend.d.ts +20 -0
- package/dist/frontends/github-frontend.d.ts.map +1 -1
- package/dist/frontends/host.d.ts +4 -0
- package/dist/frontends/host.d.ts.map +1 -1
- package/dist/frontends/slack-frontend.d.ts +58 -0
- package/dist/frontends/slack-frontend.d.ts.map +1 -0
- package/dist/generated/config-schema.d.ts +409 -41
- package/dist/generated/config-schema.d.ts.map +1 -1
- package/dist/generated/config-schema.json +436 -47
- package/dist/github-comments.d.ts +2 -0
- package/dist/github-comments.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +83587 -56085
- package/dist/liquid-extensions.d.ts.map +1 -1
- package/dist/logger.d.ts +1 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/output/traces/{run-2025-11-21T11-50-46-505Z.ndjson → run-2026-01-20T19-22-58-043Z.ndjson} +91 -91
- package/dist/output/traces/run-2026-01-20T19-23-52-175Z.ndjson +1067 -0
- package/dist/output-formatters.d.ts.map +1 -1
- package/dist/providers/ai-check-provider.d.ts +12 -0
- package/dist/providers/ai-check-provider.d.ts.map +1 -1
- package/dist/providers/check-provider-registry.d.ts.map +1 -1
- package/dist/providers/check-provider.interface.d.ts +9 -0
- package/dist/providers/check-provider.interface.d.ts.map +1 -1
- package/dist/providers/command-check-provider.d.ts.map +1 -1
- package/dist/providers/custom-tool-executor.d.ts.map +1 -1
- package/dist/providers/git-checkout-provider.d.ts +25 -0
- package/dist/providers/git-checkout-provider.d.ts.map +1 -0
- package/dist/providers/http-client-provider.d.ts +3 -0
- package/dist/providers/http-client-provider.d.ts.map +1 -1
- package/dist/providers/human-input-check-provider.d.ts +2 -0
- package/dist/providers/human-input-check-provider.d.ts.map +1 -1
- package/dist/providers/log-check-provider.d.ts.map +1 -1
- package/dist/providers/mcp-check-provider.d.ts +1 -1
- package/dist/providers/mcp-check-provider.d.ts.map +1 -1
- package/dist/providers/mcp-custom-sse-server.d.ts +66 -0
- package/dist/providers/mcp-custom-sse-server.d.ts.map +1 -0
- package/dist/providers/memory-check-provider.d.ts.map +1 -1
- package/dist/providers/script-check-provider.d.ts.map +1 -1
- package/dist/providers/workflow-check-provider.d.ts.map +1 -1
- package/dist/reviewer.d.ts.map +1 -1
- package/dist/sdk/check-provider-registry-534KL5HT.mjs +27 -0
- package/dist/sdk/chunk-23L3QRYX.mjs +16872 -0
- package/dist/sdk/chunk-23L3QRYX.mjs.map +1 -0
- package/dist/sdk/{chunk-OOZITMRU.mjs → chunk-3OMWVM6J.mjs} +11 -1
- package/dist/sdk/{chunk-OOZITMRU.mjs.map → chunk-3OMWVM6J.mjs.map} +1 -1
- package/dist/sdk/{chunk-37ZSCMFC.mjs → chunk-7UK3NIIT.mjs} +2 -2
- package/dist/sdk/{chunk-VMPLF6FT.mjs → chunk-AGIZJ4UZ.mjs} +50 -4
- package/dist/sdk/chunk-AGIZJ4UZ.mjs.map +1 -0
- package/dist/sdk/{chunk-IEO6CFLG.mjs → chunk-AIVFBIS4.mjs} +161 -5
- package/dist/sdk/chunk-AIVFBIS4.mjs.map +1 -0
- package/dist/sdk/chunk-AK6BVWIT.mjs +426 -0
- package/dist/sdk/chunk-AK6BVWIT.mjs.map +1 -0
- package/dist/sdk/chunk-AUT26LHW.mjs +139 -0
- package/dist/sdk/chunk-AUT26LHW.mjs.map +1 -0
- package/dist/sdk/chunk-BOVFH3LI.mjs +232 -0
- package/dist/sdk/chunk-BOVFH3LI.mjs.map +1 -0
- package/dist/sdk/chunk-HTOKWMPO.mjs +157 -0
- package/dist/sdk/chunk-HTOKWMPO.mjs.map +1 -0
- package/dist/sdk/{chunk-6Y4YTKCF.mjs → chunk-NAW3DB3I.mjs} +2 -2
- package/dist/sdk/{chunk-OWUVOILT.mjs → chunk-QR7MOMJH.mjs} +4 -3
- package/dist/sdk/{chunk-OWUVOILT.mjs.map → chunk-QR7MOMJH.mjs.map} +1 -1
- package/dist/sdk/{chunk-PTL3K3PN.mjs → chunk-QY2XYPEV.mjs} +488 -60
- package/dist/sdk/chunk-QY2XYPEV.mjs.map +1 -0
- package/dist/sdk/{chunk-OZJ263FM.mjs → chunk-SIWNBRTK.mjs} +29 -215
- package/dist/sdk/chunk-SIWNBRTK.mjs.map +1 -0
- package/dist/sdk/command-executor-TYUV6HUS.mjs +14 -0
- package/dist/sdk/{config-M4ZNO6NU.mjs → config-YNC2EOOT.mjs} +5 -3
- package/dist/sdk/{failure-condition-evaluator-NBO5YRXW.mjs → failure-condition-evaluator-YGTF2GHG.mjs} +6 -5
- package/dist/sdk/{github-frontend-4AWRJT7D.mjs → github-frontend-SIAEOCON.mjs} +190 -12
- package/dist/sdk/github-frontend-SIAEOCON.mjs.map +1 -0
- package/dist/sdk/{host-7GBC3S7L.mjs → host-DXUYTNMU.mjs} +5 -2
- package/dist/sdk/host-DXUYTNMU.mjs.map +1 -0
- package/dist/sdk/{liquid-extensions-C7EG3YKH.mjs → liquid-extensions-PKWCKK7E.mjs} +5 -4
- package/dist/sdk/memory-store-XGBB7LX7.mjs +12 -0
- package/dist/sdk/prompt-state-YRJY6QAL.mjs +16 -0
- package/dist/sdk/{renderer-schema-6RF26VUS.mjs → renderer-schema-LPKN5UJS.mjs} +3 -2
- package/dist/sdk/{renderer-schema-6RF26VUS.mjs.map → renderer-schema-LPKN5UJS.mjs.map} +1 -1
- package/dist/sdk/{routing-RP56JTV2.mjs → routing-6N45MJ4F.mjs} +7 -6
- package/dist/sdk/sdk.d.mts +219 -5
- package/dist/sdk/sdk.d.ts +219 -5
- package/dist/sdk/sdk.js +21329 -14908
- package/dist/sdk/sdk.js.map +1 -1
- package/dist/sdk/sdk.mjs +407 -12874
- package/dist/sdk/sdk.mjs.map +1 -1
- package/dist/sdk/{session-registry-N5FFYFTM.mjs → session-registry-4E6YRQ77.mjs} +2 -2
- package/dist/sdk/session-registry-4E6YRQ77.mjs.map +1 -0
- package/dist/sdk/slack-frontend-BVKW3GD5.mjs +735 -0
- package/dist/sdk/slack-frontend-BVKW3GD5.mjs.map +1 -0
- package/dist/sdk/{tracer-init-WP4X46IF.mjs → tracer-init-GSLPPLCD.mjs} +2 -2
- package/dist/sdk/tracer-init-GSLPPLCD.mjs.map +1 -0
- package/dist/sdk/workflow-registry-R6KSACFR.mjs +12 -0
- package/dist/sdk/workflow-registry-R6KSACFR.mjs.map +1 -0
- package/dist/slack/adapter.d.ts +36 -0
- package/dist/slack/adapter.d.ts.map +1 -0
- package/dist/slack/cache-prewarmer.d.ts +31 -0
- package/dist/slack/cache-prewarmer.d.ts.map +1 -0
- package/dist/slack/client.d.ts +77 -0
- package/dist/slack/client.d.ts.map +1 -0
- package/dist/slack/markdown.d.ts +45 -0
- package/dist/slack/markdown.d.ts.map +1 -0
- package/dist/slack/prompt-state.d.ts +33 -0
- package/dist/slack/prompt-state.d.ts.map +1 -0
- package/dist/slack/rate-limiter.d.ts +56 -0
- package/dist/slack/rate-limiter.d.ts.map +1 -0
- package/dist/slack/signature.d.ts +2 -0
- package/dist/slack/signature.d.ts.map +1 -0
- package/dist/slack/socket-runner.d.ts +42 -0
- package/dist/slack/socket-runner.d.ts.map +1 -0
- package/dist/slack/thread-cache.d.ts +51 -0
- package/dist/slack/thread-cache.d.ts.map +1 -0
- package/dist/state-machine/context/build-engine-context.d.ts +8 -0
- package/dist/state-machine/context/build-engine-context.d.ts.map +1 -1
- package/dist/state-machine/dispatch/execution-invoker.d.ts.map +1 -1
- package/dist/state-machine/dispatch/foreach-processor.d.ts.map +1 -1
- package/dist/state-machine/dispatch/on-init-handlers.d.ts +43 -0
- package/dist/state-machine/dispatch/on-init-handlers.d.ts.map +1 -0
- package/dist/state-machine/dispatch/stats-manager.d.ts.map +1 -1
- package/dist/state-machine/dispatch/template-renderer.d.ts.map +1 -1
- package/dist/state-machine/runner.d.ts +6 -0
- package/dist/state-machine/runner.d.ts.map +1 -1
- package/dist/state-machine/states/level-dispatch.d.ts.map +1 -1
- package/dist/state-machine/states/plan-ready.d.ts.map +1 -1
- package/dist/state-machine/states/routing.d.ts.map +1 -1
- package/dist/state-machine/states/wave-planning.d.ts.map +1 -1
- package/dist/state-machine/workflow-projection.d.ts.map +1 -1
- package/dist/state-machine-execution-engine.d.ts +21 -9
- package/dist/state-machine-execution-engine.d.ts.map +1 -1
- package/dist/telemetry/state-capture.d.ts +5 -0
- package/dist/telemetry/state-capture.d.ts.map +1 -1
- package/dist/test-runner/core/flow-stage.d.ts.map +1 -1
- package/dist/test-runner/core/test-execution-wrapper.d.ts.map +1 -1
- package/dist/test-runner/evaluators.d.ts +37 -4
- package/dist/test-runner/evaluators.d.ts.map +1 -1
- package/dist/test-runner/index.d.ts +7 -0
- package/dist/test-runner/index.d.ts.map +1 -1
- package/dist/test-runner/recorders/slack-recorder.d.ts +17 -0
- package/dist/test-runner/recorders/slack-recorder.d.ts.map +1 -0
- package/dist/test-runner/validator.d.ts.map +1 -1
- package/dist/traces/{run-2025-11-21T11-50-46-505Z.ndjson → run-2026-01-20T19-22-58-043Z.ndjson} +91 -91
- package/dist/traces/run-2026-01-20T19-23-52-175Z.ndjson +1067 -0
- package/dist/types/bot.d.ts +109 -0
- package/dist/types/bot.d.ts.map +1 -0
- package/dist/types/cli.d.ts +4 -0
- package/dist/types/cli.d.ts.map +1 -1
- package/dist/types/config.d.ts +182 -5
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/engine.d.ts +5 -0
- package/dist/types/engine.d.ts.map +1 -1
- package/dist/types/git-checkout.d.ts +76 -0
- package/dist/types/git-checkout.d.ts.map +1 -0
- package/dist/utils/json-text-extractor.d.ts +17 -0
- package/dist/utils/json-text-extractor.d.ts.map +1 -0
- package/dist/utils/sandbox.d.ts +10 -0
- package/dist/utils/sandbox.d.ts.map +1 -1
- package/dist/utils/template-context.d.ts +1 -0
- package/dist/utils/template-context.d.ts.map +1 -1
- package/dist/utils/tracer-init.d.ts.map +1 -1
- package/dist/utils/workspace-manager.d.ts +118 -0
- package/dist/utils/workspace-manager.d.ts.map +1 -0
- package/dist/utils/worktree-cleanup.d.ts +33 -0
- package/dist/utils/worktree-cleanup.d.ts.map +1 -0
- package/dist/utils/worktree-manager.d.ts +153 -0
- package/dist/utils/worktree-manager.d.ts.map +1 -0
- package/dist/webhook-server.d.ts.map +1 -1
- package/dist/workflow-executor.d.ts.map +1 -1
- package/dist/workflow-registry.d.ts.map +1 -1
- package/package.json +4 -2
- package/dist/output/traces/run-2025-11-21T11-51-33-674Z.ndjson +0 -839
- package/dist/sdk/chunk-IEO6CFLG.mjs.map +0 -1
- package/dist/sdk/chunk-JEHPDJIF.mjs +0 -223
- package/dist/sdk/chunk-JEHPDJIF.mjs.map +0 -1
- package/dist/sdk/chunk-OZJ263FM.mjs.map +0 -1
- package/dist/sdk/chunk-PTL3K3PN.mjs.map +0 -1
- package/dist/sdk/chunk-VMPLF6FT.mjs.map +0 -1
- package/dist/sdk/github-frontend-4AWRJT7D.mjs.map +0 -1
- package/dist/sdk/host-7GBC3S7L.mjs.map +0 -1
- package/dist/sdk/memory-store-GJACZC2A.mjs +0 -11
- package/dist/sdk/workflow-registry-2YIIXQCK.mjs +0 -11
- package/dist/traces/run-2025-11-21T11-51-33-674Z.ndjson +0 -839
- /package/dist/sdk/{config-M4ZNO6NU.mjs.map → check-provider-registry-534KL5HT.mjs.map} +0 -0
- /package/dist/sdk/{chunk-37ZSCMFC.mjs.map → chunk-7UK3NIIT.mjs.map} +0 -0
- /package/dist/sdk/{chunk-6Y4YTKCF.mjs.map → chunk-NAW3DB3I.mjs.map} +0 -0
- /package/dist/sdk/{failure-condition-evaluator-NBO5YRXW.mjs.map → command-executor-TYUV6HUS.mjs.map} +0 -0
- /package/dist/sdk/{liquid-extensions-C7EG3YKH.mjs.map → config-YNC2EOOT.mjs.map} +0 -0
- /package/dist/sdk/{memory-store-GJACZC2A.mjs.map → failure-condition-evaluator-YGTF2GHG.mjs.map} +0 -0
- /package/dist/sdk/{routing-RP56JTV2.mjs.map → liquid-extensions-PKWCKK7E.mjs.map} +0 -0
- /package/dist/sdk/{session-registry-N5FFYFTM.mjs.map → memory-store-XGBB7LX7.mjs.map} +0 -0
- /package/dist/sdk/{tracer-init-WP4X46IF.mjs.map → prompt-state-YRJY6QAL.mjs.map} +0 -0
- /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
|