@samaksh/git-worker 0.1.0 → 0.2.1
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/dist/cli/index.js +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/services/git/reader.js +105 -34
- package/dist/services/workspace/manager.js +1 -1
- package/dist/stages/eligibility.js +38 -14
- package/dist/stages/select.js +46 -37
- package/package.json +11 -1
- package/GIT_WORKER_PROJECT_PLAN.md +0 -499
- package/demo/README.md +0 -58
- package/demo/index.ts +0 -526
- package/src/app.ts +0 -69
- package/src/cli/commands.ts +0 -142
- package/src/cli/index.ts +0 -123
- package/src/config/defaults.ts +0 -46
- package/src/config/load.ts +0 -70
- package/src/config/schema.ts +0 -48
- package/src/core/errors.ts +0 -45
- package/src/core/pipeline.ts +0 -17
- package/src/core/types.ts +0 -188
- package/src/services/editor/index.ts +0 -85
- package/src/services/git/ops.ts +0 -170
- package/src/services/git/reader.ts +0 -148
- package/src/services/report/index.ts +0 -104
- package/src/services/review/index.ts +0 -80
- package/src/services/state/index.ts +0 -77
- package/src/services/template/env.ts +0 -169
- package/src/services/template/interpolator.ts +0 -109
- package/src/services/template/transform.ts +0 -97
- package/src/services/template/validator.ts +0 -75
- package/src/services/workspace/cache.ts +0 -144
- package/src/services/workspace/manager.ts +0 -370
- package/src/stages/apply.ts +0 -194
- package/src/stages/edit-template.ts +0 -227
- package/src/stages/eligibility.ts +0 -67
- package/src/stages/load-template.ts +0 -188
- package/src/stages/plan.ts +0 -362
- package/src/stages/push.ts +0 -120
- package/src/stages/report.ts +0 -126
- package/src/stages/resolve-project.ts +0 -341
- package/src/stages/review.ts +0 -228
- package/src/stages/select.ts +0 -302
- package/src/stages/sync.ts +0 -63
- package/src/utils/hash.ts +0 -15
- package/src/utils/ui.ts +0 -137
- package/src/utils/which.ts +0 -18
- package/tsconfig.json +0 -18
|
@@ -1,499 +0,0 @@
|
|
|
1
|
-
# Git Worker — Implementation Blueprint
|
|
2
|
-
|
|
3
|
-
**Status:** Proposed architecture, based on `REFERENCE.md` and the subsequent design decisions.
|
|
4
|
-
**Goal:** A safe, composable TypeScript CLI/TUI for applying reviewed file changes across many Git branches, with VS Code as the preferred editor/diff tool and Vim as a supported alternative.
|
|
5
|
-
|
|
6
|
-
## 1. Product contract
|
|
7
|
-
|
|
8
|
-
Git Worker lets a developer target a local Git repository or remote URL, select branches and a file, edit a reusable template, preview the exact per-branch changes without checking out branches, approve/reject them, and then commit and optionally push approved changes. It should work with a handful or 100+ branches without requiring one persistent worktree per branch.
|
|
9
|
-
|
|
10
|
-
**Primary design principles**
|
|
11
|
-
|
|
12
|
-
1. **Readable over clever:** small functions, explicit data types, straightforward control flow.
|
|
13
|
-
2. **Functional core, imperative shell:** transformations, validation, planning, and diff decisions are pure; filesystem, Git, editor, and TUI interactions are injected services.
|
|
14
|
-
3. **Pipeline composition:** `pipeline(stage1, stage2, ...)`, where each stage receives the previous stage's context and returns an updated context or a typed failure.
|
|
15
|
-
4. **Inspect without checkout:** use Git object reads (`git show`, `git ls-tree`, `git cat-file`) to plan changes.
|
|
16
|
-
5. **Review before mutation:** collect missing values and build exact diffs before checkout/commit.
|
|
17
|
-
6. **Controlled destructive operations:** reset/clean only inside a verified, Git Worker-owned disposable checkout, never inside a user's original repository.
|
|
18
|
-
7. **Explicit staging and pushes:** stage only intended paths; push only on confirmation or explicit policy.
|
|
19
|
-
8. **Configuration in one place:** no scattered magic defaults, commands, timeouts, paths, or UI preferences.
|
|
20
|
-
9. **Small first release:** `.env` is the first-class transformer; other file formats are extensions, not implied to be fully supported by the `.env` engine.
|
|
21
|
-
|
|
22
|
-
## 2. Decisions settled in discussion
|
|
23
|
-
|
|
24
|
-
| Topic | Final decision |
|
|
25
|
-
|---|---|
|
|
26
|
-
| Static `.env` entries | `DB_PORT=54331` enforces that value on every selected branch. |
|
|
27
|
-
| Dynamic `.env` entries | `SERVICE_NAME={SERVICE_NAME}` takes the existing value from each branch. |
|
|
28
|
-
| Missing dynamic key | Ask for a value for **each** affected branch, individually. |
|
|
29
|
-
| Empty existing value | Empty is present and is preserved; do not prompt. |
|
|
30
|
-
| Prompt timing | During planning/staging, before review and before any commits. |
|
|
31
|
-
| Unmanaged keys | Preserve keys not mentioned in the template. |
|
|
32
|
-
| Template persistence | Save the last **successfully applied** template locally for next run. |
|
|
33
|
-
| Branch-specific binding persistence | Not necessary; Git branch contents are the source of truth. |
|
|
34
|
-
| Drift behavior | Static values are re-enforced on each run; dynamic values are read fresh from each branch. No separate drift subsystem for MVP. |
|
|
35
|
-
| Cleanup | Keep reset/clean before and after checkout, **only in a verified managed disposable checkout**. |
|
|
36
|
-
| Editing/diffing | VS Code (`code --wait`, `code --diff`) preferred; Vim supported. |
|
|
37
|
-
| Execution | Per-branch fault isolation; one branch failure does not silently corrupt another. |
|
|
38
|
-
| Push | Prompt by default; `always` and `never` configurable. |
|
|
39
|
-
| Deleting a key from template | **Proposed default:** do not delete it from branches; require an explicit delete operation. This remains a decision to confirm. |
|
|
40
|
-
|
|
41
|
-
**Important distinction:** The template is authoritative for **keys it declares**. It is not a whole-file replacement: comments, formatting, ordering, and keys not declared in the template should be preserved by the `.env` transformer. A dynamic placeholder expresses *per-branch ownership of the value*, not a common literal value.
|
|
42
|
-
|
|
43
|
-
## 3. Example semantics
|
|
44
|
-
|
|
45
|
-
Template:
|
|
46
|
-
|
|
47
|
-
```dotenv
|
|
48
|
-
# Uniform values
|
|
49
|
-
DB_NAME=postgres
|
|
50
|
-
DB_PORT=54331
|
|
51
|
-
|
|
52
|
-
# Values sourced from each branch
|
|
53
|
-
SERVICE_NAME={SERVICE_NAME}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
Existing `uat-payments/.env`:
|
|
57
|
-
|
|
58
|
-
```dotenv
|
|
59
|
-
DB_NAME=legacy
|
|
60
|
-
DB_PORT=54330
|
|
61
|
-
SERVICE_NAME=payments
|
|
62
|
-
CUSTOM_FLAG=yes
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
Proposed result:
|
|
66
|
-
|
|
67
|
-
```dotenv
|
|
68
|
-
DB_NAME=postgres
|
|
69
|
-
DB_PORT=54331
|
|
70
|
-
SERVICE_NAME=payments
|
|
71
|
-
CUSTOM_FLAG=yes
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
If `uat-orders` has no `SERVICE_NAME`, the staging/planning interaction asks:
|
|
75
|
-
|
|
76
|
-
```text
|
|
77
|
-
Branch: uat-orders
|
|
78
|
-
Missing SERVICE_NAME
|
|
79
|
-
Enter value for uat-orders > orders
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
It then stages and displays the proposed addition. If the user cancels, that branch is skipped with a recorded reason. Missing values for 50 branches result in 50 individual prompts (not a bulk editor).
|
|
83
|
-
|
|
84
|
-
### `.env` parsing and preservation rules
|
|
85
|
-
|
|
86
|
-
- Recognize blank lines, full-line comments, assignments, `export KEY=...` where supported, and inline comments where syntactically unambiguous.
|
|
87
|
-
- Update the value of a declared existing key **in place**; preserve key ordering, unrelated lines, and comments.
|
|
88
|
-
- Append declared keys that do not exist; preserve the file's existing newline style and final-newline convention where practical.
|
|
89
|
-
- Treat `KEY=` as present with an empty value.
|
|
90
|
-
- Define duplicate-key behavior explicitly: **fail that branch with a diagnostic** in MVP instead of guessing which assignment is authoritative.
|
|
91
|
-
- Fail safely on unsupported or ambiguous syntax instead of rewriting it heuristically.
|
|
92
|
-
- Resolve placeholders from the branch's existing key value first, and prompt only when the key is absent.
|
|
93
|
-
- Use the exact `{NAME}` placeholder syntax from the discussion, with escaping and validation rules documented. Avoid silently mixing it with the earlier `${name}` syntax; support an alias only if intentionally configured.
|
|
94
|
-
- Treat values as opaque text, preserving quoting when possible. Never print secret values in normal logs or persisted reports.
|
|
95
|
-
- The template editor's instruction header is temporary and stripped before parsing/saving; real user comments remain.
|
|
96
|
-
|
|
97
|
-
## 4. CLI/TUI user experience
|
|
98
|
-
|
|
99
|
-
### Interactive default
|
|
100
|
-
|
|
101
|
-
```text
|
|
102
|
-
git-worker [repo]
|
|
103
|
-
1. Resolve/sync project workspace
|
|
104
|
-
2. Select branches (glob/regex, live refilter)
|
|
105
|
-
3. Select target file and operation (edit/add/rename)
|
|
106
|
-
4. Check eligibility per branch
|
|
107
|
-
5. Load saved template or synthesize first-run starter
|
|
108
|
-
6. Open template in VS Code (or Vim)
|
|
109
|
-
7. Validate template and inspect branch files
|
|
110
|
-
8. Prompt individually for missing dynamic values
|
|
111
|
-
9. Build out-of-tree before/after snapshots and diffs
|
|
112
|
-
10. Review each branch; approve/reject/skip, batch actions optional
|
|
113
|
-
11. Revalidate branch tips, apply approved changes, commit
|
|
114
|
-
12. Confirm push policy; push eligible commits
|
|
115
|
-
13. Display report; persist state only according to actual outcomes
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
### Example commands
|
|
119
|
-
|
|
120
|
-
```bash
|
|
121
|
-
git-worker
|
|
122
|
-
git-worker --repo ../my-repo --branch 'uat*' --file .env
|
|
123
|
-
git-worker --repo git@github.com:org/repo.git --branch '/^release\//' --editor code
|
|
124
|
-
git-worker --ci --branch 'uat*' --file .env --push never
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
Keep the original CLI flags from the reference where useful: `--repo/-r`, `--branch/-b`, `--file/-f`, `--op/-o`, `--editor/-e`, `--commit-msg/-m`, `--push/-p`, `--remote`, `--auto-approve`, `--ci`, `--help`, `--version`. Validate incompatible combinations early. In noninteractive mode, unresolved dynamic variables **fail or skip explicitly**; never hang waiting for prompts or silently invent values. Provide a configured values-input mechanism later if CI needs dynamic additions.
|
|
128
|
-
|
|
129
|
-
### Editor adapter
|
|
130
|
-
|
|
131
|
-
- `code --wait <template-file>` for editing; `code --diff <before> <after>` for review. Ensure VS Code is actually installed; show a clear error or configurable fallback.
|
|
132
|
-
- Vim editing through terminal ownership (`vim <template-file>`); diff via `vim -d <before> <after>` (or `vimdiff`).
|
|
133
|
-
- Editor launch, cancellation, file-watch/save behavior, and error re-edit loops are centralized in the editor service.
|
|
134
|
-
- Editor-specific flags are configuration, not hard-coded in the pipeline.
|
|
135
|
-
|
|
136
|
-
## 5. Architecture: services + pipeline
|
|
137
|
-
|
|
138
|
-
### Suggested directory layout
|
|
139
|
-
|
|
140
|
-
```text
|
|
141
|
-
src/
|
|
142
|
-
cli/
|
|
143
|
-
index.ts # parse args and launch
|
|
144
|
-
commands.ts
|
|
145
|
-
config/
|
|
146
|
-
defaults.ts # all default values
|
|
147
|
-
schema.ts # validate merged configuration
|
|
148
|
-
load.ts # defaults -> project config -> CLI
|
|
149
|
-
core/
|
|
150
|
-
types.ts # domain models and Result types
|
|
151
|
-
pipeline.ts # generic stage composer
|
|
152
|
-
errors.ts
|
|
153
|
-
services/
|
|
154
|
-
git/ # Git commands, refs, cleanup, commit, push
|
|
155
|
-
workspace/ # owned project checkout/cache
|
|
156
|
-
selection/ # branch/file selector and eligibility
|
|
157
|
-
editor/ # VS Code/Vim adapter
|
|
158
|
-
template/ # parse, render, transform .env
|
|
159
|
-
state/ # local saved templates
|
|
160
|
-
review/ # snapshots, diffs, approvals
|
|
161
|
-
report/ # terminal and optional JSON/Markdown
|
|
162
|
-
stages/
|
|
163
|
-
resolve-project.ts
|
|
164
|
-
sync.ts
|
|
165
|
-
select.ts
|
|
166
|
-
eligibility.ts
|
|
167
|
-
load-template.ts
|
|
168
|
-
edit-template.ts
|
|
169
|
-
plan.ts
|
|
170
|
-
review.ts
|
|
171
|
-
apply.ts
|
|
172
|
-
push.ts
|
|
173
|
-
report.ts
|
|
174
|
-
app.ts # composition root / dependency wiring
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
These are *logical boundaries*, not a mandate for dozens of classes or barrel files. A service is a small set of related functions behind an injected interface. Keep domain types separate from terminal rendering and Git process execution.
|
|
178
|
-
|
|
179
|
-
### Composition root
|
|
180
|
-
|
|
181
|
-
```ts
|
|
182
|
-
const services = createServices(config);
|
|
183
|
-
const context = createInitialContext(input, config);
|
|
184
|
-
|
|
185
|
-
const run = pipeline(
|
|
186
|
-
resolveProject,
|
|
187
|
-
syncRepository,
|
|
188
|
-
selectTargets,
|
|
189
|
-
checkEligibility,
|
|
190
|
-
loadTemplate,
|
|
191
|
-
editTemplate,
|
|
192
|
-
planChanges,
|
|
193
|
-
reviewChanges,
|
|
194
|
-
applyChanges,
|
|
195
|
-
pushChanges,
|
|
196
|
-
reportResults,
|
|
197
|
-
);
|
|
198
|
-
|
|
199
|
-
const result = await run(context, services);
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
### Simple pipeline API
|
|
203
|
-
|
|
204
|
-
```ts
|
|
205
|
-
type Result<T> =
|
|
206
|
-
| { ok: true; value: T }
|
|
207
|
-
| { ok: false; error: AppError };
|
|
208
|
-
|
|
209
|
-
type Stage<C, D> = (context: C, deps: D) => Promise<Result<C>>;
|
|
210
|
-
|
|
211
|
-
function pipeline<C, D>(...stages: Stage<C, D>[]): Stage<C, D> {
|
|
212
|
-
return async (initial, deps) => {
|
|
213
|
-
let current = initial;
|
|
214
|
-
for (const stage of stages) {
|
|
215
|
-
const result = await stage(current, deps);
|
|
216
|
-
if (!result.ok) return result;
|
|
217
|
-
current = result.value;
|
|
218
|
-
}
|
|
219
|
-
return { ok: true, value: current };
|
|
220
|
-
};
|
|
221
|
-
}
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
This intentionally uses one evolving typed context to minimize generic type complexity. If stage-specific input/output types become important, introduce typed composition overloads later. **Do not let stages mutate the context in place**; return new objects with added fields. For expensive branch data, use maps or immutable records and replace only changed entries.
|
|
225
|
-
|
|
226
|
-
### Core context
|
|
227
|
-
|
|
228
|
-
```ts
|
|
229
|
-
type RunContext = {
|
|
230
|
-
runId: string;
|
|
231
|
-
input: CliInput;
|
|
232
|
-
project?: ManagedProject;
|
|
233
|
-
selectedBranches?: BranchRef[];
|
|
234
|
-
target?: TargetFile;
|
|
235
|
-
eligible?: BranchRef[];
|
|
236
|
-
template?: TemplateDocument;
|
|
237
|
-
plans?: BranchPlan[];
|
|
238
|
-
approvals?: Approval[];
|
|
239
|
-
results?: BranchResult[];
|
|
240
|
-
pushResults?: PushResult[];
|
|
241
|
-
};
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
Stage preconditions are validated explicitly. For example, `applyChanges` refuses to run without plans and approvals. `BranchPlan` should capture `branch`, `baseCommitSha`, `path`, `beforeContentHash`, `afterContent`, `diff`, `status`, and an optional reason. Each stage has one job; the pipeline owns ordering, not business rules.
|
|
245
|
-
|
|
246
|
-
### Pure vs impure responsibilities
|
|
247
|
-
|
|
248
|
-
| Pure functions | Effectful services |
|
|
249
|
-
|---|---|
|
|
250
|
-
| Parse/validate template | Read Git objects |
|
|
251
|
-
| Extract placeholders | Fetch remotes |
|
|
252
|
-
| Compare template assignments | Launch editor |
|
|
253
|
-
| Render branch-specific content | Prompt for missing values |
|
|
254
|
-
| Compute eligibility decisions from supplied facts | Create staging files |
|
|
255
|
-
| Build branch plan from content + answers | Reset/clean/checkout/commit/push |
|
|
256
|
-
| Format report model | Print TUI / write report |
|
|
257
|
-
|
|
258
|
-
Prefer dependency injection by passing service objects, not a service locator or class hierarchy.
|
|
259
|
-
|
|
260
|
-
## 6. Workspace and Git safety
|
|
261
|
-
|
|
262
|
-
### Workspace layout
|
|
263
|
-
|
|
264
|
-
```text
|
|
265
|
-
.git-worker/
|
|
266
|
-
projects/
|
|
267
|
-
<stable-project-id>/
|
|
268
|
-
repo/ # disposable checkout owned by git-worker
|
|
269
|
-
staging/<run-id>/ # outside repo: before/after files
|
|
270
|
-
state/ # local templates
|
|
271
|
-
reports/ # optional run reports
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
- Project ID derived from a canonicalized repository identity; avoid collisions and handle multiple remotes.
|
|
275
|
-
- Never delete or reset the user's supplied local repository. If a local path is supplied, discover its remote and create/use a **separate managed checkout**; define an explicit error when no suitable remote exists rather than silently mutating the original.
|
|
276
|
-
- Verify ownership with a marker file outside the checkout plus canonical real-path checks; reject paths that escape the workspace (including symlinks).
|
|
277
|
-
- Serialize operations per managed checkout (lock file) to prevent concurrent runs corrupting one another.
|
|
278
|
-
- Keep state/staging/reports outside `repo/` so cleanup cannot remove them.
|
|
279
|
-
- `git reset --hard` and `git clean -fd` may run **before and after** branch switches inside the verified managed checkout. Document that ignored files are not removed by `-fd`; if a truly pristine tree is required, make `-fdx` a carefully gated, managed-checkout-only option, not the default.
|
|
280
|
-
- Always stage only the target paths (`git add -- <path>`); check `git diff --cached --name-only` before committing.
|
|
281
|
-
- If an operation fails, clean/reset the disposable checkout and continue to the next branch, recording the failure.
|
|
282
|
-
|
|
283
|
-
### Preventing stale-plan commits
|
|
284
|
-
|
|
285
|
-
Planning reads branch commit `A`. Before applying, fetch and verify the branch still points to `A`. If the tip changed, **skip that branch and require re-planning/re-review**. Do not apply an approved diff against a different version of the file. Use non-force pushes and report non-fast-forward failures.
|
|
286
|
-
|
|
287
|
-
### Per-branch commit behavior
|
|
288
|
-
|
|
289
|
-
1. Verify managed checkout and branch tip matches the reviewed plan.
|
|
290
|
-
2. Clean before checkout, switch to the target branch, clean again.
|
|
291
|
-
3. Verify target file still matches the reviewed before-content hash.
|
|
292
|
-
4. Write only the approved after-content, using a temporary file/atomic replace where practical.
|
|
293
|
-
5. Stage only the approved path(s), inspect staged names and staged diff.
|
|
294
|
-
6. Skip no-op changes (no empty commits).
|
|
295
|
-
7. Commit with configured message and identity; record SHA.
|
|
296
|
-
8. On error, restore disposable checkout, mark branch failed, continue.
|
|
297
|
-
9. Push only after commit phase and explicit push gate; record per-branch push outcome.
|
|
298
|
-
|
|
299
|
-
A Git commit is atomic for its tree, but rollback after a successful commit is not automatic. Do not claim the entire multi-branch run is atomic: commits and pushes across different branches can partially succeed.
|
|
300
|
-
|
|
301
|
-
## 7. Stateful living template, minimal persistence
|
|
302
|
-
|
|
303
|
-
### State location and format
|
|
304
|
-
|
|
305
|
-
One local state file per project + target path, for example:
|
|
306
|
-
|
|
307
|
-
```json
|
|
308
|
-
{
|
|
309
|
-
"schemaVersion": 1,
|
|
310
|
-
"targetPath": ".env",
|
|
311
|
-
"template": "DB_NAME=postgres\nDB_PORT=54331\nSERVICE_NAME={SERVICE_NAME}\n",
|
|
312
|
-
"updatedAt": "2026-10-28T00:00:00Z"
|
|
313
|
-
}
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
**No persistent branch binding map**: branch-specific values are read directly from each branch's `.env` on every run. Avoid storing secrets or sensitive values in state, reports, or terminal logs.
|
|
317
|
-
|
|
318
|
-
### First run
|
|
319
|
-
|
|
320
|
-
- If saved state exists, load it into the editor.
|
|
321
|
-
- Otherwise, synthesize a helpful draft from common keys/values across selected branches. This is a **proposal**, never automatically applied; distinguish uniform values from varying values and suggest placeholders for varying keys.
|
|
322
|
-
- If synthesis is ambiguous, show a minimal valid blank template rather than inventing config values.
|
|
323
|
-
|
|
324
|
-
### Subsequent runs
|
|
325
|
-
|
|
326
|
-
- Load the last saved template; the developer edits it in VS Code/Vim.
|
|
327
|
-
- Re-evaluate the **whole set of declared keys** against every selected branch: static values are enforced and dynamic values are read per branch.
|
|
328
|
-
- Unmanaged keys remain untouched. Removing a key from the template does not implicitly delete it (proposed policy; confirm).
|
|
329
|
-
- If no branches are approved/applied, don't overwrite the saved successful template. If only some branches succeed, retain a clear partial-run status in the report and make it obvious that a subsequent run will re-enforce the template on remaining branches.
|
|
330
|
-
- **State persistence policy needs explicit finalization:** simplest policy is to save the new template after at least one successful local commit, with an accompanying last-run summary; when zero commits occur because everything already matches, allow saving the reviewed template after explicit approval. Never claim a template was applied to all branches when only some succeeded.
|
|
331
|
-
|
|
332
|
-
### Drift and manual edits
|
|
333
|
-
|
|
334
|
-
- No dedicated drift tracking needed in MVP. On each run, the current branch content is the truth for dynamic placeholders, and template literals are authoritative for static keys.
|
|
335
|
-
- A branch that has a manually modified static value will show the proposed correction in its diff.
|
|
336
|
-
- A manually modified dynamic value remains unchanged.
|
|
337
|
-
|
|
338
|
-
## 8. Review UX and diff integrity
|
|
339
|
-
|
|
340
|
-
- Staging stores `before` and `after` snapshots for each eligible branch, outside the checkout.
|
|
341
|
-
- TUI displays statuses: `unchanged`, `changed`, `missing input`, `ineligible`, `approved`, `rejected`, `skipped`, `failed`.
|
|
342
|
-
- Preview changes with VS Code side-by-side (`code --diff before after`); Vim diff is supported.
|
|
343
|
-
- A branch may be approved/rejected independently. Batch approve/reject is a convenience, not a separate execution path.
|
|
344
|
-
- Approval is tied to a **specific immutable plan hash** (branch, base SHA, target path, before/after content hashes). Any change to plan content invalidates approval and requires review again.
|
|
345
|
-
- If the user edits the *after* snapshot during review, revalidate the resulting file and recompute the plan hash/diff before approval. For MVP, a simpler and safer alternative is **read-only diff review** and requiring a template re-edit to change results.
|
|
346
|
-
- Provide an all-branch summary before the first destructive checkout.
|
|
347
|
-
|
|
348
|
-
## 9. Configuration design
|
|
349
|
-
|
|
350
|
-
### Precedence
|
|
351
|
-
|
|
352
|
-
`defaults < project git-worker.config.json < CLI flags` (and environment variables only for explicitly documented options). Validate once at startup and pass a frozen `AppConfig` through dependency injection.
|
|
353
|
-
|
|
354
|
-
Example:
|
|
355
|
-
|
|
356
|
-
```json
|
|
357
|
-
{
|
|
358
|
-
"git": {
|
|
359
|
-
"remote": "origin",
|
|
360
|
-
"fetchPrune": true,
|
|
361
|
-
"cleanMode": "tracked-and-untracked",
|
|
362
|
-
"pushPolicy": "prompt",
|
|
363
|
-
"commitMessage": "chore: sync configuration"
|
|
364
|
-
},
|
|
365
|
-
"workspace": {
|
|
366
|
-
"root": ".git-worker",
|
|
367
|
-
"lockTimeoutMs": 30000
|
|
368
|
-
},
|
|
369
|
-
"editor": {
|
|
370
|
-
"name": "code",
|
|
371
|
-
"editCommand": ["code", "--wait", "{file}"],
|
|
372
|
-
"diffCommand": ["code", "--diff", "{before}", "{after}"]
|
|
373
|
-
},
|
|
374
|
-
"template": {
|
|
375
|
-
"placeholderOpen": "{",
|
|
376
|
-
"placeholderClose": "}",
|
|
377
|
-
"missingValuePolicy": "prompt-each-branch",
|
|
378
|
-
"emptyValueIsPresent": true,
|
|
379
|
-
"unmanagedKeyPolicy": "preserve",
|
|
380
|
-
"removedTemplateKeyPolicy": "preserve"
|
|
381
|
-
},
|
|
382
|
-
"review": {
|
|
383
|
-
"autoApprove": false
|
|
384
|
-
},
|
|
385
|
-
"execution": {
|
|
386
|
-
"concurrency": 1,
|
|
387
|
-
"stopOnBranchError": false
|
|
388
|
-
},
|
|
389
|
-
"report": {
|
|
390
|
-
"writeJson": false,
|
|
391
|
-
"writeMarkdown": false,
|
|
392
|
-
"redactValues": true
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
Keep security invariants **non-configurable**: never clean outside a verified owned workspace, never force-push by default, never stage unspecified paths, never bypass revalidation of a reviewed plan.
|
|
398
|
-
|
|
399
|
-
## 10. Errors, cancellation, and reporting
|
|
400
|
-
|
|
401
|
-
- Use typed error categories: `CONFIG`, `GIT`, `EDITOR`, `TEMPLATE`, `ELIGIBILITY`, `INPUT_CANCELLED`, `STALE_PLAN`, `APPLY`, `PUSH`.
|
|
402
|
-
- Distinguish **run-fatal** errors (invalid config, workspace ownership failure) from **per-branch** errors (missing file, invalid syntax, rejected diff, failed commit).
|
|
403
|
-
- Cancellation before apply must leave target branches unchanged.
|
|
404
|
-
- End with an accurate summary per branch: eligible, skipped, rejected, unchanged, committed, pushed, failed; include commit SHA and reasons where relevant.
|
|
405
|
-
- Reports must avoid leaking `.env` secret values. If a full diff is displayed, warn that it may contain secrets; redact exported reports by default.
|
|
406
|
-
- Persistent Markdown/JSON reports are useful but can follow the terminal summary in implementation priority.
|
|
407
|
-
|
|
408
|
-
## 11. Test strategy
|
|
409
|
-
|
|
410
|
-
### Unit tests (pure logic)
|
|
411
|
-
|
|
412
|
-
- `.env` tokenizer: comments, whitespace, quotes, empty values, CRLF, duplicate keys, `export`, malformed assignments.
|
|
413
|
-
- Static enforcement; dynamic preservation; missing-key prompting request; absent vs empty distinction.
|
|
414
|
-
- Unmanaged-key preservation; append semantics; no-op detection.
|
|
415
|
-
- Template serialization and first-run synthesis.
|
|
416
|
-
- Config precedence and schema validation.
|
|
417
|
-
- Plan hash and stale-plan detection logic.
|
|
418
|
-
- Pipeline short-circuit and context passing.
|
|
419
|
-
|
|
420
|
-
### Integration tests (temporary local Git repositories)
|
|
421
|
-
|
|
422
|
-
- 3–5 branches with different `.env` values; verify exact per-branch results.
|
|
423
|
-
- Managed checkout cleanup never affects the source repository.
|
|
424
|
-
- Dirty/untracked files inside managed checkout cannot enter commits.
|
|
425
|
-
- Stale branch tip causes skip, not accidental commit.
|
|
426
|
-
- One branch fails while later branches continue.
|
|
427
|
-
- Stage only intended paths; no-op branches do not commit.
|
|
428
|
-
- Push confirmation/never/always and non-fast-forward failures.
|
|
429
|
-
- Editor adapter with fake command runner; real VS Code/Vim manual smoke tests.
|
|
430
|
-
- Interrupted run leaves managed workspace recoverable.
|
|
431
|
-
|
|
432
|
-
### Acceptance scenario
|
|
433
|
-
|
|
434
|
-
1. Create three remote branches, each with unique `SERVICE_NAME` and an unmanaged key.
|
|
435
|
-
2. First-run template enforces two static values and preserves `SERVICE_NAME`.
|
|
436
|
-
3. Fourth branch lacks `SERVICE_NAME`; CLI asks once for that branch during staging.
|
|
437
|
-
4. Review shows exact four branch diffs before any commit.
|
|
438
|
-
5. Reject one branch; approve three; only three are committed.
|
|
439
|
-
6. Push prompt defaults to explicit confirmation.
|
|
440
|
-
7. Re-run: saved template opens; add `LOG_LEVEL=debug`; dynamic values are read from Git without re-prompting.
|
|
441
|
-
8. Manually change a static value and a dynamic value on different branches; next run restores static but preserves dynamic.
|
|
442
|
-
9. Force a branch to advance after review; it is skipped as stale.
|
|
443
|
-
10. Source repository remains untouched throughout.
|
|
444
|
-
|
|
445
|
-
## 12. Delivery roadmap
|
|
446
|
-
|
|
447
|
-
### Phase 0 — Lock contracts and test fixtures
|
|
448
|
-
- Confirm placeholder syntax, template-key deletion policy, source-repo handling, state-save semantics, and `.env` grammar.
|
|
449
|
-
- Build fixture repositories and golden before/after files.
|
|
450
|
-
|
|
451
|
-
### Phase 1 — Safe Git foundation
|
|
452
|
-
- Config schema, workspace ownership, project identity, Git command runner, fetch, branch enumeration, clean/checkout/commit/push, lock, path-scoped staging.
|
|
453
|
-
- Tests for isolation, cleanup, and branch-tip revalidation.
|
|
454
|
-
|
|
455
|
-
### Phase 2 — Pure `.env` engine
|
|
456
|
-
- Parser/tokenizer, static/dynamic rules, missing-input request generation, preservation rules, diagnostics, deterministic rendering.
|
|
457
|
-
- Exhaustive unit tests.
|
|
458
|
-
|
|
459
|
-
### Phase 3 — Interactive pipeline and staging
|
|
460
|
-
- Branch/file selection, editor adapter, eligibility, missing-value prompts, out-of-tree snapshots, diff review, approvals.
|
|
461
|
-
- End-to-end dry run that makes no commits.
|
|
462
|
-
|
|
463
|
-
### Phase 4 — Apply and push
|
|
464
|
-
- Revalidate approved plans, clean switch, path-scoped stage, commit, failure isolation, push gate, terminal summary.
|
|
465
|
-
- Full integration tests.
|
|
466
|
-
|
|
467
|
-
### Phase 5 — Living-template persistence
|
|
468
|
-
- Save/load local template; first-run synthesis; accurate partial-success handling; incremental subsequent runs.
|
|
469
|
-
- Tests for repeated execution and manual branch edits.
|
|
470
|
-
|
|
471
|
-
### Phase 6 — Polish and extensions
|
|
472
|
-
- Better TUI filtering, batch actions, exportable reports, CI behavior, additional file-format transformer plugins (Dockerfile/YAML/JSON/Groovy), optional shared state.
|
|
473
|
-
- Add only when real use cases justify them.
|
|
474
|
-
|
|
475
|
-
## 13. Explicit non-goals for first release
|
|
476
|
-
|
|
477
|
-
- No one-worktree-per-branch persistent checkout farm.
|
|
478
|
-
- No remote or team-shared template state.
|
|
479
|
-
- No complex drift database or three-way merge engine.
|
|
480
|
-
- No automatic guessing of missing dynamic values.
|
|
481
|
-
- No implicit deletion of unmanaged keys.
|
|
482
|
-
- No multi-repository distributed transaction or guarantee that all branch pushes succeed atomically.
|
|
483
|
-
- No assumption that arbitrary YAML/JSON/Dockerfile/Groovy can be safely transformed by `.env` rules.
|
|
484
|
-
|
|
485
|
-
## 14. Chosen defaults (open to change)
|
|
486
|
-
|
|
487
|
-
These decisions were made as reasonable defaults; they can be revisited as needs evolve.
|
|
488
|
-
|
|
489
|
-
| Decision | Default | Notes |
|
|
490
|
-
|---|---|---|
|
|
491
|
-
| **Removed template key** | **Preserve** on branches | Never delete keys implicitly. If deletion is needed, add an explicit delete operation later. |
|
|
492
|
-
| **Source repository with no remote** | **Reject with error** | Fail fast rather than guessing. A remote (e.g., `origin`) is required to safely use a separate managed checkout without mutating a local-only repo. |
|
|
493
|
-
| **Saved template on partial success** | **Save after first successful commit** (or after explicit approval if no commits occur because everything already matches) | Preserves progress on partial runs; reports clearly show partial status and remaining branches. |
|
|
494
|
-
| **Editable review snapshots** | **Read-only diff for MVP** | Safer and simpler. To change results, re-edit the template and re-run the plan (with mandatory revalidation). |
|
|
495
|
-
| **Secrets in diffs/reports** | **Show in interactive diff with a warning**; **redact from exported reports by default** | Needed to review `.env` changes, but exports (JSON/Markdown) must redact values by default to prevent accidental leaks. |
|
|
496
|
-
|
|
497
|
-
## 15. Definition of done
|
|
498
|
-
|
|
499
|
-
Git Worker is ready for its first stable release when a developer can run `git-worker` from anywhere, target a repository, select many branches, edit a remembered `.env` template in VS Code or Vim, provide missing per-branch values before review, inspect deterministic diffs, approve a subset, safely commit and optionally push only approved changes, and receive an accurate report—without modifying their original checkout or carrying accidental files into commits.
|
package/demo/README.md
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
# git-worker Demo
|
|
2
|
-
|
|
3
|
-
End-to-end functional verification that exercises every pipeline stage using a **real local Git repository** with 4 branches.
|
|
4
|
-
|
|
5
|
-
## What it does
|
|
6
|
-
|
|
7
|
-
1. **Creates** a local bare Git repo (acts as the "remote") in `/tmp/git-worker-demo/`
|
|
8
|
-
2. **Populates** 4 UAT branches with different `.env` files:
|
|
9
|
-
|
|
10
|
-
| Branch | Contents | Notes |
|
|
11
|
-
|---|---|---|
|
|
12
|
-
| `uat/payments` | All keys present | Baseline |
|
|
13
|
-
| `uat/orders` | `LOG_LEVEL` **missing** | Triggers per-branch prompt |
|
|
14
|
-
| `uat/inventory` | Has `export LEGACY_VAR=…` | Verifies `export` prefix preserved |
|
|
15
|
-
| `uat/notifications` | `DB_NAME=legacy_db` (wrong) | Verifies static enforcement |
|
|
16
|
-
|
|
17
|
-
3. **Pre-loads** this template (skips editor opening):
|
|
18
|
-
```dotenv
|
|
19
|
-
# Static — enforced on all branches
|
|
20
|
-
DB_NAME=uat_db
|
|
21
|
-
|
|
22
|
-
# Dynamic — read from each branch
|
|
23
|
-
DB_PORT={DB_PORT}
|
|
24
|
-
SERVICE_NAME={SERVICE_NAME}
|
|
25
|
-
LOG_LEVEL={LOG_LEVEL}
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
4. **Runs `git-worker`** against the repo matching pattern `/^uat\//`
|
|
29
|
-
5. **Verifies** results: DB_NAME corrected, CUSTOM_FLAG preserved, SERVICE_NAME intact
|
|
30
|
-
|
|
31
|
-
## Run
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
# Interactive — full TUI with prompts and per-branch diff review
|
|
35
|
-
npx tsx demo/index.ts
|
|
36
|
-
|
|
37
|
-
# Non-interactive — CI mode, auto-approve, uat/orders skipped (LOG_LEVEL missing)
|
|
38
|
-
npx tsx demo/index.ts --ci
|
|
39
|
-
|
|
40
|
-
# Clean up demo files
|
|
41
|
-
npx tsx demo/index.ts --clean
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
## Expected outcomes
|
|
45
|
-
|
|
46
|
-
| Branch | Outcome |
|
|
47
|
-
|---|---|
|
|
48
|
-
| `uat/payments` | `DB_NAME` stays `uat_db`, all dynamic values preserved |
|
|
49
|
-
| `uat/orders` | **CI:** skipped (missing `LOG_LEVEL`) — **Interactive:** prompted, then committed |
|
|
50
|
-
| `uat/inventory` | `export LEGACY_VAR` prefix preserved, `DB_NAME` unchanged |
|
|
51
|
-
| `uat/notifications` | `DB_NAME` corrected `legacy_db → uat_db`, `CUSTOM_FLAG` preserved |
|
|
52
|
-
|
|
53
|
-
## What each verification checks
|
|
54
|
-
|
|
55
|
-
After the run, the script reads `.env` from each branch via `git show origin/BRANCH:.env` and asserts:
|
|
56
|
-
- `DB_NAME=uat_db` (static enforcement worked)
|
|
57
|
-
- `CUSTOM_FLAG` still present (unmanaged key preservation)
|
|
58
|
-
- `SERVICE_NAME` still present (dynamic placeholder — value unchanged)
|