@vexdo/cli 0.1.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 +23 -0
- package/.github/workflows/ci.yml +84 -0
- package/.idea/copilot.data.migration.ask2agent.xml +6 -0
- package/.idea/go.imports.xml +11 -0
- package/.idea/misc.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/vcs.xml +7 -0
- package/.idea/vexdo-cli.iml +9 -0
- package/.prettierrc +5 -0
- package/CLAUDE.md +93 -0
- package/CONTRIBUTING.md +62 -0
- package/LICENSE +21 -0
- package/README.md +206 -0
- package/bin/vexdo.js +2 -0
- package/package.json +35 -0
- package/src/commands/abort.ts +66 -0
- package/src/commands/fix.ts +106 -0
- package/src/commands/init.ts +142 -0
- package/src/commands/logs.ts +74 -0
- package/src/commands/review.ts +107 -0
- package/src/commands/start.ts +197 -0
- package/src/commands/status.ts +52 -0
- package/src/commands/submit.ts +38 -0
- package/src/index.ts +42 -0
- package/src/lib/claude.ts +259 -0
- package/src/lib/codex.ts +96 -0
- package/src/lib/config.ts +157 -0
- package/src/lib/gh.ts +78 -0
- package/src/lib/git.ts +119 -0
- package/src/lib/logger.ts +147 -0
- package/src/lib/requirements.ts +18 -0
- package/src/lib/review-loop.ts +154 -0
- package/src/lib/state.ts +121 -0
- package/src/lib/submit-task.ts +43 -0
- package/src/lib/tasks.ts +94 -0
- package/src/prompts/arbiter.ts +21 -0
- package/src/prompts/reviewer.ts +20 -0
- package/src/types/index.ts +96 -0
- package/test/config.test.ts +124 -0
- package/test/state.test.ts +147 -0
- package/test/unit/claude.test.ts +117 -0
- package/test/unit/codex.test.ts +67 -0
- package/test/unit/gh.test.ts +49 -0
- package/test/unit/git.test.ts +120 -0
- package/test/unit/review-loop.test.ts +198 -0
- package/tests/integration/review.test.ts +137 -0
- package/tests/integration/start.test.ts +220 -0
- package/tests/unit/init.test.ts +91 -0
- package/tsconfig.json +15 -0
- package/tsup.config.ts +8 -0
- package/vitest.config.ts +7 -0
package/.eslintrc.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"root": true,
|
|
3
|
+
"env": {
|
|
4
|
+
"node": true,
|
|
5
|
+
"es2022": true
|
|
6
|
+
},
|
|
7
|
+
"parser": "@typescript-eslint/parser",
|
|
8
|
+
"parserOptions": {
|
|
9
|
+
"project": "./tsconfig.json",
|
|
10
|
+
"sourceType": "module"
|
|
11
|
+
},
|
|
12
|
+
"plugins": ["@typescript-eslint"],
|
|
13
|
+
"extends": [
|
|
14
|
+
"eslint:recommended",
|
|
15
|
+
"plugin:@typescript-eslint/strict-type-checked",
|
|
16
|
+
"plugin:@typescript-eslint/stylistic-type-checked",
|
|
17
|
+
"prettier"
|
|
18
|
+
],
|
|
19
|
+
"rules": {
|
|
20
|
+
"@typescript-eslint/consistent-type-imports": "error"
|
|
21
|
+
},
|
|
22
|
+
"ignorePatterns": ["dist", "bin/*.js"]
|
|
23
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- '**'
|
|
7
|
+
tags:
|
|
8
|
+
- 'v*'
|
|
9
|
+
pull_request:
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
lint-typecheck:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
- uses: actions/setup-node@v4
|
|
17
|
+
with:
|
|
18
|
+
node-version: 18
|
|
19
|
+
- uses: actions/cache@v4
|
|
20
|
+
with:
|
|
21
|
+
path: ~/.npm
|
|
22
|
+
key: npm-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
|
|
23
|
+
restore-keys: |
|
|
24
|
+
npm-${{ runner.os }}-
|
|
25
|
+
- run: npm ci
|
|
26
|
+
- run: npm run typecheck
|
|
27
|
+
- run: npm run lint
|
|
28
|
+
|
|
29
|
+
test:
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
needs: lint-typecheck
|
|
32
|
+
steps:
|
|
33
|
+
- uses: actions/checkout@v4
|
|
34
|
+
- uses: actions/setup-node@v4
|
|
35
|
+
with:
|
|
36
|
+
node-version: 18
|
|
37
|
+
- uses: actions/cache@v4
|
|
38
|
+
with:
|
|
39
|
+
path: ~/.npm
|
|
40
|
+
key: npm-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
|
|
41
|
+
restore-keys: |
|
|
42
|
+
npm-${{ runner.os }}-
|
|
43
|
+
- run: npm ci
|
|
44
|
+
- run: npm run test:coverage
|
|
45
|
+
|
|
46
|
+
build:
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
needs: test
|
|
49
|
+
steps:
|
|
50
|
+
- uses: actions/checkout@v4
|
|
51
|
+
- uses: actions/setup-node@v4
|
|
52
|
+
with:
|
|
53
|
+
node-version: 18
|
|
54
|
+
- uses: actions/cache@v4
|
|
55
|
+
with:
|
|
56
|
+
path: ~/.npm
|
|
57
|
+
key: npm-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
|
|
58
|
+
restore-keys: |
|
|
59
|
+
npm-${{ runner.os }}-
|
|
60
|
+
- run: npm ci
|
|
61
|
+
- run: npm run build
|
|
62
|
+
- run: test -n "$(find dist -mindepth 1 -maxdepth 1 -print -quit)"
|
|
63
|
+
|
|
64
|
+
release:
|
|
65
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
66
|
+
runs-on: ubuntu-latest
|
|
67
|
+
needs: [lint-typecheck, test, build]
|
|
68
|
+
steps:
|
|
69
|
+
- uses: actions/checkout@v4
|
|
70
|
+
- uses: actions/setup-node@v4
|
|
71
|
+
with:
|
|
72
|
+
node-version: 18
|
|
73
|
+
registry-url: https://registry.npmjs.org
|
|
74
|
+
- uses: actions/cache@v4
|
|
75
|
+
with:
|
|
76
|
+
path: ~/.npm
|
|
77
|
+
key: npm-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
|
|
78
|
+
restore-keys: |
|
|
79
|
+
npm-${{ runner.os }}-
|
|
80
|
+
- run: npm ci
|
|
81
|
+
- run: npm run build
|
|
82
|
+
- run: npm publish
|
|
83
|
+
env:
|
|
84
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project version="4">
|
|
3
|
+
<component name="GoImports">
|
|
4
|
+
<option name="excludedPackages">
|
|
5
|
+
<array>
|
|
6
|
+
<option value="github.com/pkg/errors" />
|
|
7
|
+
<option value="golang.org/x/net/context" />
|
|
8
|
+
</array>
|
|
9
|
+
</option>
|
|
10
|
+
</component>
|
|
11
|
+
</project>
|
package/.idea/misc.xml
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project version="4">
|
|
3
|
+
<component name="ProjectRootManager" version="2" languageLevel="JDK_24" default="true" project-jdk-name="openjdk-24" project-jdk-type="JavaSDK">
|
|
4
|
+
<output url="file://$PROJECT_DIR$/out" />
|
|
5
|
+
</component>
|
|
6
|
+
</project>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project version="4">
|
|
3
|
+
<component name="ProjectModuleManager">
|
|
4
|
+
<modules>
|
|
5
|
+
<module fileurl="file://$PROJECT_DIR$/.idea/vexdo-cli.iml" filepath="$PROJECT_DIR$/.idea/vexdo-cli.iml" />
|
|
6
|
+
</modules>
|
|
7
|
+
</component>
|
|
8
|
+
</project>
|
package/.idea/vcs.xml
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<module type="JAVA_MODULE" version="4">
|
|
3
|
+
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
|
4
|
+
<exclude-output />
|
|
5
|
+
<content url="file://$MODULE_DIR$" />
|
|
6
|
+
<orderEntry type="inheritedJdk" />
|
|
7
|
+
<orderEntry type="sourceFolder" forTests="false" />
|
|
8
|
+
</component>
|
|
9
|
+
</module>
|
package/.prettierrc
ADDED
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
## 1) Project overview
|
|
4
|
+
|
|
5
|
+
`vexdo` is a task orchestrator CLI for multi-service repositories. The core flow is: load task + config, run Codex for each step, run Claude reviewer + arbiter loop, then submit PRs or escalate.
|
|
6
|
+
|
|
7
|
+
## 2) Architecture
|
|
8
|
+
|
|
9
|
+
Dependency direction should stay:
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
types ← lib ← commands ← index.ts
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Key invariants:
|
|
16
|
+
- `commands/` may exit process; `lib/` should generally return errors.
|
|
17
|
+
- `lib/` is reusable orchestration/integration logic.
|
|
18
|
+
- `types/` stays free of runtime dependencies.
|
|
19
|
+
- Reviewer and arbiter must run with isolated contexts/data.
|
|
20
|
+
|
|
21
|
+
## 3) Key files and roles
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
src/
|
|
25
|
+
index.ts # commander bootstrap, global flags, command wiring
|
|
26
|
+
commands/
|
|
27
|
+
init.ts # interactive bootstrap (`vexdo init`)
|
|
28
|
+
start.ts # primary task execution flow
|
|
29
|
+
review.ts # rerun review loop on active step
|
|
30
|
+
fix.ts # feed corrective prompt to Codex then review
|
|
31
|
+
submit.ts # PR creation and state completion
|
|
32
|
+
abort.ts # cancel task, preserve branches
|
|
33
|
+
status.ts # print active state
|
|
34
|
+
logs.ts # print iteration logs
|
|
35
|
+
lib/
|
|
36
|
+
config.ts # .vexdo.yml discovery + validation
|
|
37
|
+
tasks.ts # task loading/validation and lane moves
|
|
38
|
+
state.ts # active state persistence
|
|
39
|
+
review-loop.ts # reviewer/arbiter loop control
|
|
40
|
+
claude.ts # Anthropic SDK wrapper
|
|
41
|
+
codex.ts # codex CLI wrapper
|
|
42
|
+
gh.ts # gh CLI wrapper for PRs
|
|
43
|
+
git.ts # git operations
|
|
44
|
+
logger.ts # output formatting
|
|
45
|
+
requirements.ts # env/runtime checks
|
|
46
|
+
prompts/
|
|
47
|
+
reviewer.ts # reviewer prompt construction
|
|
48
|
+
arbiter.ts # arbiter prompt construction
|
|
49
|
+
types/index.ts # shared type contracts
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## 4) Common tasks
|
|
53
|
+
|
|
54
|
+
### Add a command
|
|
55
|
+
1. Add `src/commands/<name>.ts` with `register<Name>Command`.
|
|
56
|
+
2. Keep parsing and CLI concerns in command file.
|
|
57
|
+
3. Put reusable logic in `lib/`.
|
|
58
|
+
4. Register in `src/index.ts`.
|
|
59
|
+
5. Add tests and README docs.
|
|
60
|
+
|
|
61
|
+
### Add a lib function
|
|
62
|
+
1. Add function to the nearest `lib/*` module.
|
|
63
|
+
2. Keep signature typed and avoid `any`.
|
|
64
|
+
3. Return errors; avoid process termination.
|
|
65
|
+
4. Add focused unit tests.
|
|
66
|
+
|
|
67
|
+
### Add a test
|
|
68
|
+
1. Unit tests in `test/unit` or `tests/unit` for isolated behavior.
|
|
69
|
+
2. Integration tests in `test/integration` or `tests/integration` for flow.
|
|
70
|
+
3. Use `vi.mock` for `child_process`, SDKs, and external CLIs.
|
|
71
|
+
|
|
72
|
+
## 5) Constraints to always enforce
|
|
73
|
+
|
|
74
|
+
- No `any` in new code.
|
|
75
|
+
- Keep ESM `.js` import specifiers in TS source.
|
|
76
|
+
- No `process.exit` inside `lib/` modules.
|
|
77
|
+
- Do not add `chalk`; use `picocolors` for output styling.
|
|
78
|
+
- Reviewer and arbiter contexts must remain isolated.
|
|
79
|
+
|
|
80
|
+
## 6) Test conventions
|
|
81
|
+
|
|
82
|
+
- Prefer mocking at module boundary.
|
|
83
|
+
- `child_process` calls should be mocked with `vi.mock('node:child_process', ...)`.
|
|
84
|
+
- Anthropic SDK behavior should be mocked through `lib/claude.ts` dependencies.
|
|
85
|
+
- Use temp directories for filesystem side effects.
|
|
86
|
+
|
|
87
|
+
## 7) What not to do
|
|
88
|
+
|
|
89
|
+
- Do not embed orchestration logic directly in `index.ts`.
|
|
90
|
+
- Do not tightly couple command handlers to specific prompt text.
|
|
91
|
+
- Do not bypass task/config validation.
|
|
92
|
+
- Do not mutate state without persisting through `state.ts` helpers.
|
|
93
|
+
- Do not mix reviewer and arbiter outputs in a single decision context.
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Contributing to vexdo
|
|
2
|
+
|
|
3
|
+
## 1) Development setup
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
git clone <repo-url>
|
|
7
|
+
cd vexdo-cli
|
|
8
|
+
npm install
|
|
9
|
+
npm link
|
|
10
|
+
npm test
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Useful checks:
|
|
14
|
+
- `npm run typecheck`
|
|
15
|
+
- `npm run lint`
|
|
16
|
+
- `npm run build`
|
|
17
|
+
|
|
18
|
+
## 2) Project structure
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
src/
|
|
22
|
+
index.ts # CLI entrypoint and command registration
|
|
23
|
+
commands/ # User-facing command handlers
|
|
24
|
+
lib/ # Core orchestration, integrations, and helpers
|
|
25
|
+
prompts/ # Claude reviewer/arbiter prompt templates
|
|
26
|
+
types/ # Shared TypeScript types
|
|
27
|
+
test/ + tests/ # Unit and integration tests
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 3) Adding a new command
|
|
31
|
+
|
|
32
|
+
1. Create `src/commands/<name>.ts`.
|
|
33
|
+
2. Export `register<Name>Command(program: Command)`.
|
|
34
|
+
3. Implement `run<Name>` function and keep side effects inside command layer.
|
|
35
|
+
4. Add registration in `src/index.ts`.
|
|
36
|
+
5. Add unit tests for parsing/behavior and integration tests if command touches git/fs/process.
|
|
37
|
+
6. Update README command docs.
|
|
38
|
+
|
|
39
|
+
## 4) Testing conventions
|
|
40
|
+
|
|
41
|
+
- **Unit tests**: isolated logic, heavy mocking (`child_process`, SDK clients, filesystem helpers).
|
|
42
|
+
- **Integration tests**: flow-level behavior and state transitions.
|
|
43
|
+
- Prefer deterministic fixtures and temporary directories.
|
|
44
|
+
- External dependencies (Anthropic, gh, codex) must be mocked in unit tests.
|
|
45
|
+
|
|
46
|
+
## 5) Commit conventions
|
|
47
|
+
|
|
48
|
+
- Follow Conventional Commits, e.g.:
|
|
49
|
+
- `feat: add init command`
|
|
50
|
+
- `fix: prevent duplicate gitignore entry`
|
|
51
|
+
- `docs: expand README`
|
|
52
|
+
- PRs should include:
|
|
53
|
+
- clear summary
|
|
54
|
+
- tests run
|
|
55
|
+
- any breaking changes
|
|
56
|
+
|
|
57
|
+
## 6) Release process
|
|
58
|
+
|
|
59
|
+
1. Bump version and update changelog/release notes.
|
|
60
|
+
2. Push tag `vX.Y.Z`.
|
|
61
|
+
3. GitHub Actions CI runs lint/typecheck/test/build.
|
|
62
|
+
4. Release job publishes to npm using `NPM_TOKEN`.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 vexdo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# vexdo
|
|
2
|
+
|
|
3
|
+
Automated implementation + review loop for multi-service tasks, powered by Codex and Claude.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+

|
|
9
|
+
|
|
10
|
+
## 1) What is vexdo
|
|
11
|
+
|
|
12
|
+
`vexdo` is a CLI that turns a task spec into a controlled execution pipeline across one or more services. It applies changes with Codex, reviews with Claude, loops until quality gates are met, and then opens PRs (or escalates when needed).
|
|
13
|
+
|
|
14
|
+
Real-world example: you need to add a new billing field in API, web, and worker repos. Instead of running separate ad-hoc sessions, you define one `task.yml` with ordered steps and let `vexdo` orchestrate execution + review with traceable state.
|
|
15
|
+
|
|
16
|
+
## 2) How it works
|
|
17
|
+
|
|
18
|
+
```text
|
|
19
|
+
task.yml
|
|
20
|
+
↓
|
|
21
|
+
vexdo start
|
|
22
|
+
↓
|
|
23
|
+
codex exec
|
|
24
|
+
↓
|
|
25
|
+
git diff
|
|
26
|
+
↓
|
|
27
|
+
claude reviewer
|
|
28
|
+
↓
|
|
29
|
+
claude arbiter
|
|
30
|
+
↓
|
|
31
|
+
fix loop (max N)
|
|
32
|
+
↓
|
|
33
|
+
PR or escalate
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## 3) Requirements
|
|
37
|
+
|
|
38
|
+
- Node.js >= 18
|
|
39
|
+
- `ANTHROPIC_API_KEY` environment variable
|
|
40
|
+
- Codex CLI installed globally:
|
|
41
|
+
- `npm install -g @openai/codex`
|
|
42
|
+
- GitHub CLI installed:
|
|
43
|
+
- https://cli.github.com
|
|
44
|
+
|
|
45
|
+
## 4) Quick start (5 minutes)
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm install -g vexdo
|
|
49
|
+
cd my-project
|
|
50
|
+
vexdo init
|
|
51
|
+
# create tasks/backlog/my-task.yml
|
|
52
|
+
vexdo start tasks/backlog/my-task.yml
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 5) Commands
|
|
56
|
+
|
|
57
|
+
| Command | Description |
|
|
58
|
+
|---|---|
|
|
59
|
+
| `vexdo init` | Initialize `.vexdo.yml`, folders, and `.gitignore` entry. |
|
|
60
|
+
| `vexdo start <task-file> [--resume]` | Start a task and run implementation/review orchestration. |
|
|
61
|
+
| `vexdo review` | Re-run review loop for the current step. |
|
|
62
|
+
| `vexdo fix <feedback>` | Send targeted feedback to Codex, then review again. |
|
|
63
|
+
| `vexdo submit` | Create PRs for active task branches. |
|
|
64
|
+
| `vexdo status` | Show current task state. |
|
|
65
|
+
| `vexdo logs [task-id] [--full]` | Inspect iteration logs. |
|
|
66
|
+
| `vexdo abort [--force]` | Abort active task and move task file back to backlog. |
|
|
67
|
+
|
|
68
|
+
### Global flags
|
|
69
|
+
|
|
70
|
+
- `--verbose`: Print debug logs.
|
|
71
|
+
- `--dry-run`: Show actions without making changes.
|
|
72
|
+
|
|
73
|
+
### Command details
|
|
74
|
+
|
|
75
|
+
#### `vexdo init`
|
|
76
|
+
Interactive bootstrap wizard:
|
|
77
|
+
- asks service names/paths
|
|
78
|
+
- asks review and model defaults
|
|
79
|
+
- writes `.vexdo.yml`
|
|
80
|
+
- creates `tasks/*` lanes and `.vexdo/logs/`
|
|
81
|
+
- adds `.vexdo/` to `.gitignore` once
|
|
82
|
+
|
|
83
|
+
#### `vexdo start <task-file>`
|
|
84
|
+
Flags:
|
|
85
|
+
- `--resume`: resume from existing state if present
|
|
86
|
+
|
|
87
|
+
Behavior:
|
|
88
|
+
- validates config and task
|
|
89
|
+
- creates/checks service branches
|
|
90
|
+
- runs Codex then review loop per step
|
|
91
|
+
- moves task files across lanes (`backlog → in_progress → review/done/blocked`)
|
|
92
|
+
|
|
93
|
+
#### `vexdo review`
|
|
94
|
+
Runs review + arbiter flow against current step without restarting full task.
|
|
95
|
+
|
|
96
|
+
#### `vexdo fix <feedback>`
|
|
97
|
+
Runs Codex with your corrective feedback, then re-enters review loop.
|
|
98
|
+
|
|
99
|
+
#### `vexdo submit`
|
|
100
|
+
Creates PRs for each service branch in the active task and marks task as done.
|
|
101
|
+
|
|
102
|
+
#### `vexdo status`
|
|
103
|
+
Prints a concise summary of active task id/title/step statuses.
|
|
104
|
+
|
|
105
|
+
#### `vexdo logs [task-id]`
|
|
106
|
+
Flags:
|
|
107
|
+
- `--full`: include full diffs and complete comment payloads
|
|
108
|
+
|
|
109
|
+
#### `vexdo abort`
|
|
110
|
+
Flags:
|
|
111
|
+
- `--force`: skip confirmation prompt
|
|
112
|
+
|
|
113
|
+
## 6) Task YAML format
|
|
114
|
+
|
|
115
|
+
```yaml
|
|
116
|
+
id: billing-vat-001
|
|
117
|
+
title: "Add VAT ID support"
|
|
118
|
+
depends_on: [] # optional task-level dependencies
|
|
119
|
+
|
|
120
|
+
steps:
|
|
121
|
+
- service: api
|
|
122
|
+
spec: |
|
|
123
|
+
Add vat_id to organization model, migration, and create/update APIs.
|
|
124
|
+
Ensure validation rules and API docs are updated.
|
|
125
|
+
|
|
126
|
+
- service: web
|
|
127
|
+
depends_on: [api] # optional per-step ordering dependency
|
|
128
|
+
spec: |
|
|
129
|
+
Add VAT ID input to organization settings screen.
|
|
130
|
+
Integrate with updated API and show validation errors.
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Field reference:
|
|
134
|
+
- `id` *(string, required)*: stable slug used for branches and state.
|
|
135
|
+
- `title` *(string, required)*: human-readable name.
|
|
136
|
+
- `depends_on` *(string[], optional)*: coarse dependency marker at task level.
|
|
137
|
+
- `steps` *(array, required)*: ordered units of work.
|
|
138
|
+
- `service` *(string, required)*: must match `.vexdo.yml` service name.
|
|
139
|
+
- `spec` *(string, required)*: concrete implementation request for Codex.
|
|
140
|
+
- `depends_on` *(string[], optional)*: service dependencies before this step starts.
|
|
141
|
+
|
|
142
|
+
## 7) `.vexdo.yml` format
|
|
143
|
+
|
|
144
|
+
```yaml
|
|
145
|
+
version: 1
|
|
146
|
+
services:
|
|
147
|
+
- name: api
|
|
148
|
+
path: ./api
|
|
149
|
+
- name: web
|
|
150
|
+
path: ./web
|
|
151
|
+
|
|
152
|
+
review:
|
|
153
|
+
model: claude-haiku-4-5-20251001
|
|
154
|
+
max_iterations: 3
|
|
155
|
+
auto_submit: false
|
|
156
|
+
|
|
157
|
+
codex:
|
|
158
|
+
model: gpt-4o
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Field reference:
|
|
162
|
+
- `version`: config schema version (currently `1`).
|
|
163
|
+
- `services`: list of service roots used by task steps.
|
|
164
|
+
- `review.model`: Claude model for reviewer + arbiter.
|
|
165
|
+
- `review.max_iterations`: hard cap for fix/review loop.
|
|
166
|
+
- `review.auto_submit`: auto-run `submit` after successful review.
|
|
167
|
+
- `codex.model`: model passed to Codex execution.
|
|
168
|
+
|
|
169
|
+
## 8) Spec format guide
|
|
170
|
+
|
|
171
|
+
Good specs are:
|
|
172
|
+
- **specific**: list exact files, behaviors, and edge cases.
|
|
173
|
+
- **testable**: include acceptance checks.
|
|
174
|
+
- **constrained**: mention prohibited changes and compatibility limits.
|
|
175
|
+
|
|
176
|
+
Recommended template:
|
|
177
|
+
|
|
178
|
+
```text
|
|
179
|
+
Goal:
|
|
180
|
+
Constraints:
|
|
181
|
+
Acceptance criteria:
|
|
182
|
+
- ...
|
|
183
|
+
- ...
|
|
184
|
+
Non-goals:
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## 9) Troubleshooting
|
|
188
|
+
|
|
189
|
+
- **"Not inside a vexdo project"**
|
|
190
|
+
- Run from a directory containing `.vexdo.yml` (or use `vexdo init`).
|
|
191
|
+
- **Anthropic key errors**
|
|
192
|
+
- Ensure `ANTHROPIC_API_KEY` is exported in shell/CI.
|
|
193
|
+
- **Codex not found**
|
|
194
|
+
- Install with `npm install -g @openai/codex` and verify PATH.
|
|
195
|
+
- **`vexdo submit` fails with GitHub auth issues**
|
|
196
|
+
- Run `gh auth login` and confirm repo access.
|
|
197
|
+
- **Task escalated**
|
|
198
|
+
- Review `.vexdo/logs/*` and rerun with `vexdo fix "..."`.
|
|
199
|
+
|
|
200
|
+
## 10) Contributing
|
|
201
|
+
|
|
202
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md).
|
|
203
|
+
|
|
204
|
+
## 11) License
|
|
205
|
+
|
|
206
|
+
MIT.
|
package/bin/vexdo.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vexdo/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"vexdo": "./bin/vexdo.js"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsup",
|
|
10
|
+
"typecheck": "tsc --noEmit",
|
|
11
|
+
"lint": "eslint .",
|
|
12
|
+
"test": "vitest run",
|
|
13
|
+
"test:coverage": "vitest run"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@anthropic-ai/sdk": "^0.39.0",
|
|
17
|
+
"@types/js-yaml": "^4.0.9",
|
|
18
|
+
"commander": "^12.1.0",
|
|
19
|
+
"js-yaml": "^4.1.1",
|
|
20
|
+
"ora": "^8.1.1",
|
|
21
|
+
"picocolors": "^1.1.1",
|
|
22
|
+
"yaml": "^2.6.1"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/node": "^22.13.10",
|
|
26
|
+
"@typescript-eslint/eslint-plugin": "^8.25.0",
|
|
27
|
+
"@typescript-eslint/parser": "^8.25.0",
|
|
28
|
+
"eslint": "^8.57.1",
|
|
29
|
+
"eslint-config-prettier": "^10.1.1",
|
|
30
|
+
"prettier": "^3.5.2",
|
|
31
|
+
"tsup": "^8.4.0",
|
|
32
|
+
"typescript": "^5.8.2",
|
|
33
|
+
"vitest": "^3.0.8"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import readline from 'node:readline/promises';
|
|
4
|
+
|
|
5
|
+
import type { Command } from 'commander';
|
|
6
|
+
|
|
7
|
+
import { findProjectRoot } from '../lib/config.js';
|
|
8
|
+
import * as logger from '../lib/logger.js';
|
|
9
|
+
import { clearState, loadState } from '../lib/state.js';
|
|
10
|
+
import { ensureTaskDirectory, moveTaskFileAtomically } from '../lib/tasks.js';
|
|
11
|
+
|
|
12
|
+
export interface AbortOptions { force?: boolean }
|
|
13
|
+
|
|
14
|
+
function fatalAndExit(message: string): never {
|
|
15
|
+
logger.fatal(message);
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async function promptConfirmation(taskId: string): Promise<boolean> {
|
|
20
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
21
|
+
try {
|
|
22
|
+
const answer = await rl.question(`Abort task ${taskId}? Branches will be kept. [y/N] `);
|
|
23
|
+
return answer.trim().toLowerCase() === 'y';
|
|
24
|
+
} finally {
|
|
25
|
+
rl.close();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function runAbort(options: AbortOptions): Promise<void> {
|
|
30
|
+
const projectRoot = findProjectRoot();
|
|
31
|
+
if (!projectRoot) {
|
|
32
|
+
fatalAndExit('Not inside a vexdo project.');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const state = loadState(projectRoot);
|
|
36
|
+
if (!state) {
|
|
37
|
+
fatalAndExit('No active task.');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!options.force) {
|
|
41
|
+
const confirmed = await promptConfirmation(state.taskId);
|
|
42
|
+
if (!confirmed) {
|
|
43
|
+
logger.info('Abort cancelled.');
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const inProgressDir = path.join(projectRoot, 'tasks', 'in_progress');
|
|
49
|
+
if (state.taskPath.startsWith(inProgressDir) && fs.existsSync(state.taskPath)) {
|
|
50
|
+
const backlogDir = ensureTaskDirectory(projectRoot, 'backlog');
|
|
51
|
+
moveTaskFileAtomically(state.taskPath, backlogDir);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
clearState(projectRoot);
|
|
55
|
+
logger.info('Task aborted. Branches preserved for manual review.');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function registerAbortCommand(program: Command): void {
|
|
59
|
+
program
|
|
60
|
+
.command('abort')
|
|
61
|
+
.description('Abort active task')
|
|
62
|
+
.option('--force', 'Skip confirmation prompt')
|
|
63
|
+
.action(async (options: AbortOptions) => {
|
|
64
|
+
await runAbort(options);
|
|
65
|
+
});
|
|
66
|
+
}
|