@orderful/droid 0.24.0 → 0.25.0
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/.eslintrc.json +6 -4
- package/AGENTS.md +58 -0
- package/CHANGELOG.md +25 -0
- package/README.md +11 -6
- package/dist/bin/droid.js +384 -170
- package/dist/commands/config.d.ts +15 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/exec.d.ts +10 -0
- package/dist/commands/exec.d.ts.map +1 -0
- package/dist/commands/tui.d.ts.map +1 -1
- package/dist/index.js +171 -33
- package/dist/lib/migrations.d.ts.map +1 -1
- package/dist/lib/skills.d.ts.map +1 -1
- package/dist/tools/codex/TOOL.yaml +1 -1
- package/dist/tools/codex/skills/droid-codex/SKILL.md +81 -65
- package/dist/tools/codex/skills/droid-codex/references/creating.md +13 -51
- package/dist/tools/codex/skills/droid-codex/references/decisions.md +15 -19
- package/dist/tools/codex/skills/droid-codex/references/topics.md +14 -12
- package/dist/tools/codex/skills/droid-codex/scripts/git-finish-write.d.ts +31 -0
- package/dist/tools/codex/skills/droid-codex/scripts/git-finish-write.d.ts.map +1 -0
- package/dist/tools/codex/skills/droid-codex/scripts/git-finish-write.ts +236 -0
- package/dist/tools/codex/skills/droid-codex/scripts/git-preamble.d.ts +20 -0
- package/dist/tools/codex/skills/droid-codex/scripts/git-preamble.d.ts.map +1 -0
- package/dist/tools/codex/skills/droid-codex/scripts/git-preamble.ts +156 -0
- package/dist/tools/codex/skills/droid-codex/scripts/git-scripts.test.ts +364 -0
- package/dist/tools/codex/skills/droid-codex/scripts/git-start-write.d.ts +23 -0
- package/dist/tools/codex/skills/droid-codex/scripts/git-start-write.d.ts.map +1 -0
- package/dist/tools/codex/skills/droid-codex/scripts/git-start-write.ts +172 -0
- package/package.json +1 -1
- package/src/bin/droid.ts +9 -0
- package/src/commands/config.ts +38 -4
- package/src/commands/exec.ts +96 -0
- package/src/commands/install.ts +1 -1
- package/src/commands/setup.ts +6 -6
- package/src/commands/tui.tsx +254 -175
- package/src/lib/migrations.ts +103 -10
- package/src/lib/quotes.ts +6 -6
- package/src/lib/skills.ts +168 -45
- package/src/tools/codex/TOOL.yaml +1 -1
- package/src/tools/codex/skills/droid-codex/SKILL.md +81 -65
- package/src/tools/codex/skills/droid-codex/references/creating.md +13 -51
- package/src/tools/codex/skills/droid-codex/references/decisions.md +15 -19
- package/src/tools/codex/skills/droid-codex/references/topics.md +14 -12
- package/src/tools/codex/skills/droid-codex/scripts/git-finish-write.ts +236 -0
- package/src/tools/codex/skills/droid-codex/scripts/git-preamble.ts +156 -0
- package/src/tools/codex/skills/droid-codex/scripts/git-scripts.test.ts +364 -0
- package/src/tools/codex/skills/droid-codex/scripts/git-start-write.ts +172 -0
|
@@ -35,15 +35,54 @@ If prerequisites fail, guide user to fix:
|
|
|
35
35
|
- Repo missing: `git clone git@github.com:orderful/orderful-codex.git {path}`
|
|
36
36
|
- gh missing: `brew install gh && gh auth login`
|
|
37
37
|
|
|
38
|
-
##
|
|
38
|
+
## Git Hygiene (CRITICAL)
|
|
39
39
|
|
|
40
|
-
**
|
|
40
|
+
**Users should never see git complexity.** Use the deterministic scripts below - they handle all git operations silently and recover gracefully. Non-engineers use this tool - if they hit a git error, they're stuck.
|
|
41
|
+
|
|
42
|
+
### Scripts
|
|
43
|
+
|
|
44
|
+
The codex skill includes three git scripts. **Always use these instead of raw git commands.**
|
|
45
|
+
|
|
46
|
+
| Script | Purpose | When to use |
|
|
47
|
+
|--------|---------|-------------|
|
|
48
|
+
| `git-preamble` | Ensure clean main + pull latest | Before ANY operation |
|
|
49
|
+
| `git-start-write` | Preamble + create branch | Before write operations |
|
|
50
|
+
| `git-finish-write` | Commit + PR + return to main | After write operations |
|
|
51
|
+
|
|
52
|
+
### Read Operations (search, load, list)
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
droid config codex | droid exec droid-codex git-preamble --config -
|
|
56
|
+
# Then proceed with the read
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Write Operations (new, decision, snapshot, artifact)
|
|
41
60
|
|
|
42
61
|
```bash
|
|
43
|
-
|
|
62
|
+
# 1. Start write (runs preamble + creates branch)
|
|
63
|
+
droid config codex | droid exec droid-codex git-start-write --config - --branch codex/{action}-{name}
|
|
64
|
+
|
|
65
|
+
# 2. Make your changes (write files)
|
|
66
|
+
|
|
67
|
+
# 3. Finish write (commit + PR + return to main)
|
|
68
|
+
droid config codex | droid exec droid-codex git-finish-write --config - \
|
|
69
|
+
--message "{commit message}" \
|
|
70
|
+
--pr-title "{PR title}" \
|
|
71
|
+
--pr-body "{PR description}"
|
|
44
72
|
```
|
|
45
73
|
|
|
46
|
-
|
|
74
|
+
The scripts return JSON with success/failure status. Check the result before proceeding.
|
|
75
|
+
|
|
76
|
+
### Error Handling
|
|
77
|
+
|
|
78
|
+
The scripts handle errors internally:
|
|
79
|
+
- Silent recovery for transient issues
|
|
80
|
+
- Clear error messages in JSON output
|
|
81
|
+
- Automatic return to main even on partial failure
|
|
82
|
+
|
|
83
|
+
If a script fails, check the JSON `error` field and report a user-friendly message:
|
|
84
|
+
- "I hit a sync issue with the codex. Let me try again..."
|
|
85
|
+
- Only escalate as last resort: "The codex repo needs manual attention."
|
|
47
86
|
|
|
48
87
|
## Security
|
|
49
88
|
|
|
@@ -208,19 +247,10 @@ Scoped operations (`decision`, `snapshot`) require an active project:
|
|
|
208
247
|
**Procedure:**
|
|
209
248
|
|
|
210
249
|
1. Verify active project exists (if not, prompt to select)
|
|
211
|
-
2.
|
|
212
|
-
3.
|
|
213
|
-
```markdown
|
|
214
|
-
## {YYYY-MM-DD}: {Decision summary from text}
|
|
215
|
-
|
|
216
|
-
**Context:** {Extract from conversation}
|
|
217
|
-
|
|
218
|
-
**Decision:** {The decision}
|
|
219
|
-
|
|
220
|
-
**Rationale:** {Why this choice}
|
|
221
|
-
```
|
|
250
|
+
2. **Run `git-start-write`** with branch `codex/decision-{short-summary}`
|
|
251
|
+
3. Read and append to `{codex_repo}/projects/{active}/DECISIONS.md`
|
|
222
252
|
4. Update `updated` date in frontmatter
|
|
223
|
-
5.
|
|
253
|
+
5. **Run `git-finish-write`** with appropriate commit message and PR title
|
|
224
254
|
|
|
225
255
|
Full procedure: `references/decisions.md`
|
|
226
256
|
|
|
@@ -230,14 +260,11 @@ Full procedure: `references/decisions.md`
|
|
|
230
260
|
|
|
231
261
|
**Procedure:**
|
|
232
262
|
|
|
233
|
-
1.
|
|
234
|
-
2.
|
|
235
|
-
3. Fill in frontmatter
|
|
236
|
-
- `explored`: today's date
|
|
237
|
-
- `confidence`: ask user or infer from exploration depth
|
|
238
|
-
- `codebase_paths`: paths that were explored
|
|
263
|
+
1. **Run `git-start-write`** with branch `codex/topic-{name}`
|
|
264
|
+
2. Create `{codex_repo}/topics/{name}.md` from template
|
|
265
|
+
3. Fill in frontmatter (explored, confidence, codebase_paths)
|
|
239
266
|
4. Fill in content from current exploration/conversation
|
|
240
|
-
5.
|
|
267
|
+
5. **Run `git-finish-write`** with appropriate commit message and PR title
|
|
241
268
|
|
|
242
269
|
Full procedure: `references/topics.md`
|
|
243
270
|
|
|
@@ -250,21 +277,15 @@ Full procedure: `references/topics.md`
|
|
|
250
277
|
**Procedure:**
|
|
251
278
|
|
|
252
279
|
1. Determine the document type (required): `prd`, `tech-design`, `topic`, or `pattern`
|
|
253
|
-
2.
|
|
280
|
+
2. **Run `git-start-write`** with branch `codex/snapshot-{name}`
|
|
281
|
+
3. Spawn the `codex-document-processor` agent with:
|
|
254
282
|
- File path to the source document
|
|
255
283
|
- Document type
|
|
256
284
|
- Project/entry name
|
|
257
285
|
- Codex repo path from config
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
- Writes to correct location in codex repo
|
|
262
|
-
- Returns file path and summary
|
|
263
|
-
4. **Back in main conversation:** Handle git workflow
|
|
264
|
-
- Create branch: `codex/snapshot-{name}`
|
|
265
|
-
- Commit the new file
|
|
266
|
-
- Push and create PR via `gh pr create`
|
|
267
|
-
5. Share PR link with user
|
|
286
|
+
4. Agent writes the processed document to codex repo
|
|
287
|
+
5. **Run `git-finish-write`** with appropriate commit message and PR title
|
|
288
|
+
6. Share PR link with user
|
|
268
289
|
|
|
269
290
|
**Example invocations:**
|
|
270
291
|
|
|
@@ -293,9 +314,10 @@ Artifacts are supplementary documents that support a project but aren't core doc
|
|
|
293
314
|
|
|
294
315
|
**Procedure:**
|
|
295
316
|
|
|
296
|
-
1.
|
|
297
|
-
2.
|
|
298
|
-
3.
|
|
317
|
+
1. **Run `git-start-write`** with branch `codex/artifact-{project}-{filename}`
|
|
318
|
+
2. Use the `codex-document-processor` agent with type `artifact`
|
|
319
|
+
3. Agent writes to `{codex_repo}/projects/{project}/artifacts/{filename}.md`
|
|
320
|
+
4. **Run `git-finish-write`** with appropriate commit message and PR title
|
|
299
321
|
|
|
300
322
|
**Example invocations:**
|
|
301
323
|
|
|
@@ -325,13 +347,11 @@ The `/codex new` command scaffolds new entries from templates:
|
|
|
325
347
|
|
|
326
348
|
**Procedure:**
|
|
327
349
|
|
|
328
|
-
1.
|
|
329
|
-
2.
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
3. Fill in frontmatter with today's date
|
|
334
|
-
4. Create branch, commit, and open PR via `gh pr create`
|
|
350
|
+
1. **Run `git-start-write`** with branch `codex/new-{name}`
|
|
351
|
+
2. Create `{codex_repo}/projects/{name}/`
|
|
352
|
+
3. Copy templates: PRD.md, TECH-DESIGN.md, DECISIONS.md
|
|
353
|
+
4. Fill in frontmatter with today's date
|
|
354
|
+
5. **Run `git-finish-write`** with appropriate commit message and PR title
|
|
335
355
|
|
|
336
356
|
### Domains
|
|
337
357
|
|
|
@@ -339,11 +359,10 @@ The `/codex new` command scaffolds new entries from templates:
|
|
|
339
359
|
|
|
340
360
|
**Procedure:**
|
|
341
361
|
|
|
342
|
-
1.
|
|
343
|
-
2.
|
|
344
|
-
3. Fill in frontmatter
|
|
345
|
-
4.
|
|
346
|
-
5. Create branch, commit, and open PR via `gh pr create`
|
|
362
|
+
1. **Run `git-start-write`** with branch `codex/domain-{name}`
|
|
363
|
+
2. Create `{codex_repo}/domains/{name}.md` from template
|
|
364
|
+
3. Fill in frontmatter, guide user through sections
|
|
365
|
+
4. **Run `git-finish-write`** with appropriate commit message and PR title
|
|
347
366
|
|
|
348
367
|
### Proposals
|
|
349
368
|
|
|
@@ -351,11 +370,10 @@ The `/codex new` command scaffolds new entries from templates:
|
|
|
351
370
|
|
|
352
371
|
**Procedure:**
|
|
353
372
|
|
|
354
|
-
1.
|
|
355
|
-
2.
|
|
356
|
-
3. Fill in frontmatter
|
|
357
|
-
4.
|
|
358
|
-
5. Create branch, commit, and open PR via `gh pr create`
|
|
373
|
+
1. **Run `git-start-write`** with branch `codex/proposal-{name}`
|
|
374
|
+
2. Create `{codex_repo}/proposals/{name}.md` from template
|
|
375
|
+
3. Fill in frontmatter, guide user through sections
|
|
376
|
+
4. **Run `git-finish-write`** with appropriate commit message and PR title
|
|
359
377
|
|
|
360
378
|
### Patterns and Topics
|
|
361
379
|
|
|
@@ -363,10 +381,10 @@ The `/codex new` command scaffolds new entries from templates:
|
|
|
363
381
|
|
|
364
382
|
**Procedure:**
|
|
365
383
|
|
|
366
|
-
1.
|
|
367
|
-
2.
|
|
384
|
+
1. **Run `git-start-write`** with branch `codex/{pattern|topic}-{name}`
|
|
385
|
+
2. Create file from template
|
|
368
386
|
3. Fill in frontmatter with today's date
|
|
369
|
-
4.
|
|
387
|
+
4. **Run `git-finish-write`** with appropriate commit message and PR title
|
|
370
388
|
|
|
371
389
|
Full procedure: `references/creating.md`
|
|
372
390
|
|
|
@@ -387,12 +405,10 @@ When user runs `/project create --from codex:{name}`:
|
|
|
387
405
|
|
|
388
406
|
## Git Workflow
|
|
389
407
|
|
|
390
|
-
**All codex changes
|
|
391
|
-
|
|
392
|
-
1. Create branch: `codex/{action}-{name}` (e.g., `codex/decision-uuid-format`)
|
|
393
|
-
2. Make changes
|
|
394
|
-
3. Commit with descriptive message
|
|
395
|
-
4. Push and create PR via `gh pr create`
|
|
396
|
-
5. Share PR link with user
|
|
408
|
+
**See "Git Hygiene (CRITICAL)" section above.** All codex changes go through PRs (main branch is protected).
|
|
397
409
|
|
|
398
|
-
|
|
410
|
+
**Key points:**
|
|
411
|
+
- Always run the preamble before any operation (ensures clean main + latest)
|
|
412
|
+
- Write operations: branch → commit → PR → **return to main**
|
|
413
|
+
- Safe changes (new files, decision appends) auto-merge via GitHub Action
|
|
414
|
+
- Never leave the repo on a feature branch
|
|
@@ -28,15 +28,18 @@ A project named '{name}' already exists. Did you mean to load it?
|
|
|
28
28
|
→ /codex {name}
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
### 3.
|
|
31
|
+
### 3. Start Write Operation
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
|
-
|
|
34
|
+
droid config codex | droid exec droid-codex git-start-write --config - --branch codex/new-{name}
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
This runs the git preamble (ensures clean main + pulls latest) and creates the branch.
|
|
38
|
+
|
|
39
|
+
### 4. Create Project Directory and Copy Templates
|
|
38
40
|
|
|
39
41
|
```bash
|
|
42
|
+
mkdir -p {codex_repo}/projects/{name}
|
|
40
43
|
cp {codex_repo}/templates/PRD.md {codex_repo}/projects/{name}/
|
|
41
44
|
cp {codex_repo}/templates/TECH-DESIGN.md {codex_repo}/projects/{name}/
|
|
42
45
|
cp {codex_repo}/templates/DECISIONS.md {codex_repo}/projects/{name}/
|
|
@@ -56,19 +59,17 @@ If user provides context, fill in what we know:
|
|
|
56
59
|
- TECH-DESIGN.md: Any architectural decisions mentioned
|
|
57
60
|
- DECISIONS.md: Leave as template (decisions come during impl)
|
|
58
61
|
|
|
59
|
-
### 7.
|
|
62
|
+
### 7. Finish Write Operation
|
|
60
63
|
|
|
61
64
|
```bash
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
feat(codex): scaffold {name} project
|
|
67
|
-
EOF
|
|
68
|
-
git push -u origin codex/new-{name}
|
|
69
|
-
gh pr create --title "New project: {name}" --body "Scaffold for {name} project"
|
|
65
|
+
droid config codex | droid exec droid-codex git-finish-write --config - \
|
|
66
|
+
--message "feat(codex): scaffold {name} project" \
|
|
67
|
+
--pr-title "New project: {name}" \
|
|
68
|
+
--pr-body "Scaffold for {name} project"
|
|
70
69
|
```
|
|
71
70
|
|
|
71
|
+
This commits, pushes, creates PR, and returns to main.
|
|
72
|
+
|
|
72
73
|
### 8. Confirm to User
|
|
73
74
|
|
|
74
75
|
```
|
|
@@ -109,42 +110,3 @@ Next steps:
|
|
|
109
110
|
|
|
110
111
|
Want me to help fill in any of these based on what we've discussed?
|
|
111
112
|
```
|
|
112
|
-
|
|
113
|
-
## With Pre-Existing Context
|
|
114
|
-
|
|
115
|
-
If the user has already discussed the feature:
|
|
116
|
-
|
|
117
|
-
**User:** "We're building audit logging to track all API changes for compliance. It'll use an event sourcing pattern."
|
|
118
|
-
|
|
119
|
-
**User:** `/codex new audit-logging`
|
|
120
|
-
|
|
121
|
-
**Result:** (PRD.md pre-filled with discussed context)
|
|
122
|
-
|
|
123
|
-
```markdown
|
|
124
|
-
---
|
|
125
|
-
title: Audit Logging
|
|
126
|
-
type: prd
|
|
127
|
-
created: 2026-01-07
|
|
128
|
-
updated: 2026-01-07
|
|
129
|
-
confidence: medium
|
|
130
|
-
source: implementation
|
|
131
|
-
---
|
|
132
|
-
|
|
133
|
-
# Audit Logging - PRD
|
|
134
|
-
|
|
135
|
-
## Problem Statement
|
|
136
|
-
|
|
137
|
-
Need to track all API changes for compliance requirements.
|
|
138
|
-
|
|
139
|
-
## Goals
|
|
140
|
-
|
|
141
|
-
- Track all API changes
|
|
142
|
-
- Support compliance auditing
|
|
143
|
-
- {More goals to be defined}
|
|
144
|
-
|
|
145
|
-
## Non-Goals
|
|
146
|
-
|
|
147
|
-
- {To be defined}
|
|
148
|
-
|
|
149
|
-
...
|
|
150
|
-
```
|
|
@@ -39,15 +39,19 @@ I'll add this decision. Can you clarify:
|
|
|
39
39
|
- Were there alternatives you considered?
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
### 3.
|
|
42
|
+
### 3. Start Write Operation
|
|
43
43
|
|
|
44
44
|
```bash
|
|
45
|
-
|
|
45
|
+
droid config codex | droid exec droid-codex git-start-write --config - --branch codex/decision-{short-summary}
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
### 4.
|
|
48
|
+
### 4. Read and Update DECISIONS.md
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
cat {codex_repo}/projects/{active}/DECISIONS.md
|
|
52
|
+
```
|
|
49
53
|
|
|
50
|
-
|
|
54
|
+
Append new decision at the end:
|
|
51
55
|
|
|
52
56
|
```markdown
|
|
53
57
|
---
|
|
@@ -68,26 +72,18 @@ Add at the end, before the template marker:
|
|
|
68
72
|
- {Expected outcomes, trade-offs}
|
|
69
73
|
```
|
|
70
74
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
Update the `updated` field to today's date.
|
|
75
|
+
Update the `updated` field in frontmatter to today's date.
|
|
74
76
|
|
|
75
|
-
###
|
|
77
|
+
### 5. Finish Write Operation
|
|
76
78
|
|
|
77
79
|
```bash
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
decision({active}): {summary}
|
|
83
|
-
EOF
|
|
84
|
-
git push -u origin codex/decision-{short-summary}
|
|
85
|
-
gh pr create --title "Decision: {summary}" --body-file - <<EOF
|
|
86
|
-
{full decision text}
|
|
87
|
-
EOF
|
|
80
|
+
droid config codex | droid exec droid-codex git-finish-write --config - \
|
|
81
|
+
--message "decision({active}): {summary}" \
|
|
82
|
+
--pr-title "Decision: {summary}" \
|
|
83
|
+
--pr-body "{full decision text}"
|
|
88
84
|
```
|
|
89
85
|
|
|
90
|
-
###
|
|
86
|
+
### 6. Confirm to User
|
|
91
87
|
|
|
92
88
|
```
|
|
93
89
|
✅ Added decision to {active}/DECISIONS.md:
|
|
@@ -43,13 +43,19 @@ Ask user or infer:
|
|
|
43
43
|
- `low` - Quick exploration, definitely incomplete
|
|
44
44
|
- **Codebase paths:** Which directories/files were explored?
|
|
45
45
|
|
|
46
|
-
### 4.
|
|
46
|
+
### 4. Start Write Operation
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
droid config codex | droid exec droid-codex git-start-write --config - --branch codex/topic-{name}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 5. Read Template
|
|
47
53
|
|
|
48
54
|
```bash
|
|
49
55
|
cat {codex_repo}/templates/TOPIC.md
|
|
50
56
|
```
|
|
51
57
|
|
|
52
|
-
###
|
|
58
|
+
### 6. Create Topic File
|
|
53
59
|
|
|
54
60
|
```bash
|
|
55
61
|
# Create the file
|
|
@@ -115,20 +121,16 @@ codebase_paths:
|
|
|
115
121
|
- {Links to related topics, PRDs, or external docs}
|
|
116
122
|
```
|
|
117
123
|
|
|
118
|
-
###
|
|
124
|
+
### 7. Finish Write Operation
|
|
119
125
|
|
|
120
126
|
```bash
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
topic: add {name}
|
|
126
|
-
EOF
|
|
127
|
-
git push -u origin codex/topic-{name}
|
|
128
|
-
gh pr create --title "Topic: {name}" --body "New topic from codebase exploration"
|
|
127
|
+
droid config codex | droid exec droid-codex git-finish-write --config - \
|
|
128
|
+
--message "topic: add {name}" \
|
|
129
|
+
--pr-title "Topic: {name}" \
|
|
130
|
+
--pr-body "New topic from codebase exploration"
|
|
129
131
|
```
|
|
130
132
|
|
|
131
|
-
###
|
|
133
|
+
### 8. Confirm to User
|
|
132
134
|
|
|
133
135
|
```
|
|
134
136
|
✅ Added topic: {name}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* codex git-finish-write
|
|
4
|
+
*
|
|
5
|
+
* Completes a write operation by committing, pushing, creating a PR,
|
|
6
|
+
* and returning to main.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* droid config codex | droid exec droid-codex git-finish-write --config - \
|
|
10
|
+
* --message "feat: add new topic" \
|
|
11
|
+
* --pr-title "New topic: caching" \
|
|
12
|
+
* --pr-body "Added exploration of caching patterns"
|
|
13
|
+
*
|
|
14
|
+
* Options:
|
|
15
|
+
* --config <json> Config with codex_repo path (required)
|
|
16
|
+
* --message <text> Commit message (required)
|
|
17
|
+
* --pr-title <text> PR title (required)
|
|
18
|
+
* --pr-body <text> PR body (optional, defaults to commit message)
|
|
19
|
+
*
|
|
20
|
+
* What it does:
|
|
21
|
+
* 1. Stage all changes
|
|
22
|
+
* 2. Commit with message
|
|
23
|
+
* 3. Push branch to origin
|
|
24
|
+
* 4. Create PR via gh CLI
|
|
25
|
+
* 5. Return to main branch
|
|
26
|
+
*
|
|
27
|
+
* Output (JSON):
|
|
28
|
+
* { "success": true, "pr_url": "https://github.com/...", "branch": "codex/topic-caching" }
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import { execSync } from 'child_process';
|
|
32
|
+
import { readFileSync, existsSync } from 'fs';
|
|
33
|
+
|
|
34
|
+
interface Config {
|
|
35
|
+
codex_repo: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface Result {
|
|
39
|
+
success: boolean;
|
|
40
|
+
pr_url?: string;
|
|
41
|
+
branch?: string;
|
|
42
|
+
error?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function parseArgs(args: string[]): {
|
|
46
|
+
config: Config | null;
|
|
47
|
+
message: string | null;
|
|
48
|
+
prTitle: string | null;
|
|
49
|
+
prBody: string | null;
|
|
50
|
+
} {
|
|
51
|
+
let config: Config | null = null;
|
|
52
|
+
let message: string | null = null;
|
|
53
|
+
let prTitle: string | null = null;
|
|
54
|
+
let prBody: string | null = null;
|
|
55
|
+
|
|
56
|
+
for (let i = 0; i < args.length; i++) {
|
|
57
|
+
const arg = args[i];
|
|
58
|
+
if (arg === '--config' && args[i + 1]) {
|
|
59
|
+
const configArg = args[++i];
|
|
60
|
+
if (configArg === '-') {
|
|
61
|
+
const stdin = readFileSync(0, 'utf-8').trim();
|
|
62
|
+
config = JSON.parse(stdin) as Config;
|
|
63
|
+
} else {
|
|
64
|
+
config = JSON.parse(configArg) as Config;
|
|
65
|
+
}
|
|
66
|
+
} else if (arg === '--message' && args[i + 1]) {
|
|
67
|
+
message = args[++i];
|
|
68
|
+
} else if (arg === '--pr-title' && args[i + 1]) {
|
|
69
|
+
prTitle = args[++i];
|
|
70
|
+
} else if (arg === '--pr-body' && args[i + 1]) {
|
|
71
|
+
prBody = args[++i];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return { config, message, prTitle, prBody };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function expandPath(p: string): string {
|
|
79
|
+
if (p.startsWith('~/')) {
|
|
80
|
+
return p.replace('~', process.env.HOME || '');
|
|
81
|
+
}
|
|
82
|
+
return p;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function run(cmd: string, cwd: string): { ok: boolean; output: string } {
|
|
86
|
+
try {
|
|
87
|
+
const output = execSync(cmd, {
|
|
88
|
+
cwd,
|
|
89
|
+
encoding: 'utf-8',
|
|
90
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
91
|
+
});
|
|
92
|
+
return { ok: true, output: output.trim() };
|
|
93
|
+
} catch (err: unknown) {
|
|
94
|
+
const error = err as { stderr?: string; stdout?: string; message?: string };
|
|
95
|
+
return { ok: false, output: error.stderr || error.stdout || error.message || 'Unknown error' };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function gitFinishWrite(
|
|
100
|
+
repoPath: string,
|
|
101
|
+
commitMessage: string,
|
|
102
|
+
prTitle: string,
|
|
103
|
+
prBody: string
|
|
104
|
+
): Result {
|
|
105
|
+
const cwd = expandPath(repoPath);
|
|
106
|
+
|
|
107
|
+
// Verify repo exists
|
|
108
|
+
if (!existsSync(cwd)) {
|
|
109
|
+
return { success: false, error: `Codex repo not found at ${cwd}` };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Get current branch
|
|
113
|
+
const branchResult = run('git branch --show-current', cwd);
|
|
114
|
+
if (!branchResult.ok) {
|
|
115
|
+
return { success: false, error: `Failed to get current branch: ${branchResult.output}` };
|
|
116
|
+
}
|
|
117
|
+
const branch = branchResult.output;
|
|
118
|
+
|
|
119
|
+
// Don't allow commits directly to main
|
|
120
|
+
if (branch === 'main') {
|
|
121
|
+
return { success: false, error: 'Cannot commit directly to main. Use git-start-write first to create a branch.' };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// 1. Stage all changes
|
|
125
|
+
const add = run('git add -A', cwd);
|
|
126
|
+
if (!add.ok) {
|
|
127
|
+
return { success: false, error: `Failed to stage changes: ${add.output}` };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Check if there are changes to commit
|
|
131
|
+
const status = run('git status --porcelain', cwd);
|
|
132
|
+
if (status.ok && status.output.length === 0) {
|
|
133
|
+
return { success: false, error: 'No changes to commit' };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// 2. Commit (use heredoc-style to avoid injection)
|
|
137
|
+
// Write commit message to a temp approach using -F -
|
|
138
|
+
const commit = run(`git commit -m "${commitMessage.replace(/"/g, '\\"')}"`, cwd);
|
|
139
|
+
if (!commit.ok) {
|
|
140
|
+
return { success: false, error: `Failed to commit: ${commit.output}` };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// 3. Push to origin
|
|
144
|
+
const push = run(`git push -u origin ${branch}`, cwd);
|
|
145
|
+
if (!push.ok) {
|
|
146
|
+
// Try force push if branch exists with different history
|
|
147
|
+
const forcePush = run(`git push -u origin ${branch} --force-with-lease`, cwd);
|
|
148
|
+
if (!forcePush.ok) {
|
|
149
|
+
return { success: false, error: `Failed to push: ${forcePush.output}` };
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// 4. Create PR via gh CLI
|
|
154
|
+
const escapedTitle = prTitle.replace(/"/g, '\\"');
|
|
155
|
+
const escapedBody = prBody.replace(/"/g, '\\"');
|
|
156
|
+
const prCreate = run(
|
|
157
|
+
`gh pr create --title "${escapedTitle}" --body "${escapedBody}" 2>&1 || gh pr view --json url -q .url`,
|
|
158
|
+
cwd
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
let prUrl = '';
|
|
162
|
+
if (prCreate.ok) {
|
|
163
|
+
// Output might be the PR URL directly or JSON
|
|
164
|
+
const output = prCreate.output;
|
|
165
|
+
if (output.startsWith('https://')) {
|
|
166
|
+
prUrl = output.split('\n')[0]; // First line is the URL
|
|
167
|
+
} else {
|
|
168
|
+
// Try to extract URL from output
|
|
169
|
+
const urlMatch = output.match(/https:\/\/github\.com\/[^\s]+/);
|
|
170
|
+
if (urlMatch) {
|
|
171
|
+
prUrl = urlMatch[0];
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// 5. Return to main
|
|
177
|
+
const checkoutMain = run('git checkout main', cwd);
|
|
178
|
+
if (!checkoutMain.ok) {
|
|
179
|
+
// Non-fatal - PR was created, just warn
|
|
180
|
+
console.error(`Warning: Failed to return to main: ${checkoutMain.output}`);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
success: true,
|
|
185
|
+
pr_url: prUrl || 'PR created (check GitHub)',
|
|
186
|
+
branch,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Main
|
|
191
|
+
const args = process.argv.slice(2);
|
|
192
|
+
const { config, message, prTitle, prBody } = parseArgs(args);
|
|
193
|
+
|
|
194
|
+
if (!config) {
|
|
195
|
+
console.log(JSON.stringify({
|
|
196
|
+
success: false,
|
|
197
|
+
error: 'Missing --config. Usage: droid config codex | droid exec droid-codex git-finish-write --config - --message "..." --pr-title "..."',
|
|
198
|
+
}));
|
|
199
|
+
process.exit(1);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (!config.codex_repo) {
|
|
203
|
+
console.log(JSON.stringify({
|
|
204
|
+
success: false,
|
|
205
|
+
error: 'Missing codex_repo in config',
|
|
206
|
+
}));
|
|
207
|
+
process.exit(1);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (!message) {
|
|
211
|
+
console.log(JSON.stringify({
|
|
212
|
+
success: false,
|
|
213
|
+
error: 'Missing --message argument',
|
|
214
|
+
}));
|
|
215
|
+
process.exit(1);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (!prTitle) {
|
|
219
|
+
console.log(JSON.stringify({
|
|
220
|
+
success: false,
|
|
221
|
+
error: 'Missing --pr-title argument',
|
|
222
|
+
}));
|
|
223
|
+
process.exit(1);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const result = gitFinishWrite(
|
|
227
|
+
config.codex_repo,
|
|
228
|
+
message,
|
|
229
|
+
prTitle,
|
|
230
|
+
prBody || message
|
|
231
|
+
);
|
|
232
|
+
console.log(JSON.stringify(result, null, 2));
|
|
233
|
+
|
|
234
|
+
if (!result.success) {
|
|
235
|
+
process.exit(1);
|
|
236
|
+
}
|