@pixel613/spec 1.0.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/LICENSE +21 -0
- package/README.md +174 -0
- package/dist/bin/pxs.d.ts +2 -0
- package/dist/bin/pxs.js +5 -0
- package/dist/bin/pxs.js.map +1 -0
- package/dist/src/backends/claude.d.ts +9 -0
- package/dist/src/backends/claude.js +80 -0
- package/dist/src/backends/claude.js.map +1 -0
- package/dist/src/backends/codex.d.ts +9 -0
- package/dist/src/backends/codex.js +72 -0
- package/dist/src/backends/codex.js.map +1 -0
- package/dist/src/backends/factory.d.ts +2 -0
- package/dist/src/backends/factory.js +14 -0
- package/dist/src/backends/factory.js.map +1 -0
- package/dist/src/backends/interface.d.ts +15 -0
- package/dist/src/backends/interface.js +2 -0
- package/dist/src/backends/interface.js.map +1 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +79 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/commands/clarify.d.ts +5 -0
- package/dist/src/commands/clarify.js +46 -0
- package/dist/src/commands/clarify.js.map +1 -0
- package/dist/src/commands/implement.d.ts +9 -0
- package/dist/src/commands/implement.js +244 -0
- package/dist/src/commands/implement.js.map +1 -0
- package/dist/src/commands/init.d.ts +6 -0
- package/dist/src/commands/init.js +177 -0
- package/dist/src/commands/init.js.map +1 -0
- package/dist/src/commands/new.d.ts +5 -0
- package/dist/src/commands/new.js +143 -0
- package/dist/src/commands/new.js.map +1 -0
- package/dist/src/commands/refine.d.ts +8 -0
- package/dist/src/commands/refine.js +158 -0
- package/dist/src/commands/refine.js.map +1 -0
- package/dist/src/commands/review.d.ts +4 -0
- package/dist/src/commands/review.js +70 -0
- package/dist/src/commands/review.js.map +1 -0
- package/dist/src/commands/status.d.ts +1 -0
- package/dist/src/commands/status.js +53 -0
- package/dist/src/commands/status.js.map +1 -0
- package/dist/src/discovery/project.d.ts +7 -0
- package/dist/src/discovery/project.js +90 -0
- package/dist/src/discovery/project.js.map +1 -0
- package/dist/src/git/operations.d.ts +10 -0
- package/dist/src/git/operations.js +56 -0
- package/dist/src/git/operations.js.map +1 -0
- package/dist/src/parsers/arguments.d.ts +18 -0
- package/dist/src/parsers/arguments.js +43 -0
- package/dist/src/parsers/arguments.js.map +1 -0
- package/dist/src/parsers/plan.d.ts +23 -0
- package/dist/src/parsers/plan.js +117 -0
- package/dist/src/parsers/plan.js.map +1 -0
- package/dist/src/parsers/spec.d.ts +10 -0
- package/dist/src/parsers/spec.js +46 -0
- package/dist/src/parsers/spec.js.map +1 -0
- package/dist/src/state/manager.d.ts +24 -0
- package/dist/src/state/manager.js +103 -0
- package/dist/src/state/manager.js.map +1 -0
- package/dist/src/state/types.d.ts +47 -0
- package/dist/src/state/types.js +21 -0
- package/dist/src/state/types.js.map +1 -0
- package/dist/src/utils/display.d.ts +7 -0
- package/dist/src/utils/display.js +42 -0
- package/dist/src/utils/display.js.map +1 -0
- package/dist/src/utils/prompt.d.ts +31 -0
- package/dist/src/utils/prompt.js +81 -0
- package/dist/src/utils/prompt.js.map +1 -0
- package/package.json +52 -0
- package/templates/agents-md-snippet.md +20 -0
- package/templates/architectures/clean/csharp-aspnet.md +56 -0
- package/templates/architectures/clean/go-gin.md +50 -0
- package/templates/architectures/clean/go-std.md +49 -0
- package/templates/architectures/clean/python-fastapi.md +49 -0
- package/templates/architectures/clean/typescript-express.md +60 -0
- package/templates/architectures/clean/typescript-nestjs.md +61 -0
- package/templates/architectures/ddd/csharp-aspnet.md +55 -0
- package/templates/architectures/ddd/go-gin.md +53 -0
- package/templates/architectures/ddd/python-fastapi.md +52 -0
- package/templates/architectures/ddd/typescript-nestjs.md +62 -0
- package/templates/architectures/hexagonal/csharp-aspnet.md +45 -0
- package/templates/architectures/hexagonal/go-gin.md +47 -0
- package/templates/architectures/hexagonal/python-fastapi.md +43 -0
- package/templates/architectures/hexagonal/typescript-nestjs.md +44 -0
- package/templates/architectures/layered/csharp-aspnet.md +45 -0
- package/templates/architectures/layered/go-gin.md +41 -0
- package/templates/architectures/layered/python-fastapi.md +42 -0
- package/templates/architectures/layered/typescript-nestjs.md +48 -0
- package/templates/architectures/modular/csharp-aspnet.md +45 -0
- package/templates/architectures/modular/go-gin.md +47 -0
- package/templates/architectures/modular/python-fastapi.md +45 -0
- package/templates/architectures/modular/typescript-nestjs.md +48 -0
- package/templates/claude-commands/sf.clarify.md +18 -0
- package/templates/claude-commands/sf.implement.md +79 -0
- package/templates/claude-commands/sf.new.md +22 -0
- package/templates/claude-commands/sf.refine.md +47 -0
- package/templates/claude-commands/sf.review.md +17 -0
- package/templates/claude-commands/sf.status.md +12 -0
- package/templates/workflow/config.yaml +17 -0
- package/templates/workflow/prompts/clarify.md +39 -0
- package/templates/workflow/prompts/final-review.md +30 -0
- package/templates/workflow/prompts/implement-tdd.md +35 -0
- package/templates/workflow/prompts/implement.md +43 -0
- package/templates/workflow/prompts/refine.md +52 -0
- package/templates/workflow/prompts/review.md +34 -0
- package/templates/workflow/prompts/test.md +14 -0
- package/templates/workflow/templates/spec-template.md +13 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pixel
|
|
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,174 @@
|
|
|
1
|
+
# @pixel613/spec (pxs)
|
|
2
|
+
|
|
3
|
+
Spec-driven development CLI for Claude Code. Write a spec, refine a plan, implement task by task — all powered by AI.
|
|
4
|
+
|
|
5
|
+
`@pixel613/spec` 是一套為 Claude Code 設計的規格驅動開發 CLI。撰寫規格、拆解計畫、逐步實作,全程 AI 驅動。
|
|
6
|
+
|
|
7
|
+
> **Supported backend: Claude Code only**
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Installation / 安裝
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g @pixel613/spec
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Start / 快速開始
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# 1. Initialize workflow in your project / 初始化工作流
|
|
21
|
+
pxs init
|
|
22
|
+
|
|
23
|
+
# 2. Create a spec / 建立規格
|
|
24
|
+
pxs new login-feature --desc "Add JWT login endpoint"
|
|
25
|
+
|
|
26
|
+
# 3. Refine spec into implementation plan / 拆解為實作計畫
|
|
27
|
+
pxs refine login-feature
|
|
28
|
+
|
|
29
|
+
# 4. Implement task by task / 逐步實作
|
|
30
|
+
pxs implement login-feature
|
|
31
|
+
|
|
32
|
+
# 5. Check status / 查看狀態
|
|
33
|
+
pxs status login-feature
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Commands / 指令
|
|
37
|
+
|
|
38
|
+
### `pxs init`
|
|
39
|
+
|
|
40
|
+
Initialize `.workflow/` directory and Claude Code slash commands for your project.
|
|
41
|
+
|
|
42
|
+
在專案中初始化 `.workflow/` 目錄與 Claude Code slash commands。
|
|
43
|
+
|
|
44
|
+
| Option | Description |
|
|
45
|
+
|--------|-------------|
|
|
46
|
+
| `--force` | Overwrite existing `.workflow/` / 覆蓋現有目錄 |
|
|
47
|
+
| `--arch <pattern>` | Architecture pattern: `clean` \| `hexagonal` \| `ddd` \| `layered` \| `modular` \| `custom` |
|
|
48
|
+
| `--lang <lang>` | Language-framework override (e.g. `go`, `typescript`, `go-gin`) |
|
|
49
|
+
|
|
50
|
+
### `pxs new <name>`
|
|
51
|
+
|
|
52
|
+
Create a new spec file under `.workflow/specs/`.
|
|
53
|
+
|
|
54
|
+
建立新的規格檔案。
|
|
55
|
+
|
|
56
|
+
| Option | Description |
|
|
57
|
+
|--------|-------------|
|
|
58
|
+
| `--desc <text>` | Generate spec from text description / 從文字描述產生規格 |
|
|
59
|
+
| `--jira <tickets...>` | Import from Jira tickets / 從 Jira ticket 匯入 |
|
|
60
|
+
| `-i, --interactive` | Interactive Q&A mode / 互動問答模式 |
|
|
61
|
+
|
|
62
|
+
### `pxs refine <name>`
|
|
63
|
+
|
|
64
|
+
Refine spec and decompose into a step-by-step implementation plan.
|
|
65
|
+
|
|
66
|
+
精煉規格並拆解為逐步實作計畫。
|
|
67
|
+
|
|
68
|
+
| Option | Description |
|
|
69
|
+
|--------|-------------|
|
|
70
|
+
| `--skip-clarify` | Skip requirement clarification / 跳過需求釐清 |
|
|
71
|
+
| `--clarify <n>` | Max clarification rounds / 最大釐清輪數 |
|
|
72
|
+
| `@agent /skill` | Pass agents or skills to assist / 指定 agent 或 skill 協助 |
|
|
73
|
+
|
|
74
|
+
### `pxs clarify <name>`
|
|
75
|
+
|
|
76
|
+
Run requirement clarification on a spec independently.
|
|
77
|
+
|
|
78
|
+
獨立執行需求釐清。
|
|
79
|
+
|
|
80
|
+
### `pxs implement <name>`
|
|
81
|
+
|
|
82
|
+
Implement code task by task with AI. Each task goes through: implement → commit → test (optional) → AI review → user approval.
|
|
83
|
+
|
|
84
|
+
AI 逐步實作。每個 task 流程:實作 → commit → 測試(可選)→ AI review → 使用者審核。
|
|
85
|
+
|
|
86
|
+
After all tasks complete, a **final branch code review** runs automatically against the full diff, spec, and plan.
|
|
87
|
+
|
|
88
|
+
所有 task 完成後,自動執行**整個 branch 的完整 code review**。
|
|
89
|
+
|
|
90
|
+
| Option | Description |
|
|
91
|
+
|--------|-------------|
|
|
92
|
+
| `--skip-review` | Skip final branch code review / 跳過最終 code review |
|
|
93
|
+
| `@agent /skill` | Pass agents or skills to assist review / 指定 agent 或 skill 協助 review |
|
|
94
|
+
|
|
95
|
+
**Test strategies / 測試策略:**
|
|
96
|
+
|
|
97
|
+
| Flag | Behavior |
|
|
98
|
+
|------|----------|
|
|
99
|
+
| `--test tdd` | TDD: write failing tests → implement → pass → refactor |
|
|
100
|
+
| `--test intg` | Post-hoc integration tests / 整合測試 |
|
|
101
|
+
| `--test tdd intg` | TDD + integration tests |
|
|
102
|
+
| `--test` | Post-hoc unit tests / 單元測試 |
|
|
103
|
+
| *(none)* | No tests / 不產生測試 |
|
|
104
|
+
|
|
105
|
+
### `pxs review <name>`
|
|
106
|
+
|
|
107
|
+
View review records.
|
|
108
|
+
|
|
109
|
+
查看 review 紀錄。
|
|
110
|
+
|
|
111
|
+
| Option | Description |
|
|
112
|
+
|--------|-------------|
|
|
113
|
+
| `--step <n>` | View specific task review / 查看特定 task 的 review |
|
|
114
|
+
| `--summary` | Summary overview of all tasks / 所有 task 的摘要 |
|
|
115
|
+
| *(default)* | Shows final branch review if completed, otherwise latest task review / 預設顯示 final review 或最新的 task review |
|
|
116
|
+
|
|
117
|
+
### `pxs status [name]`
|
|
118
|
+
|
|
119
|
+
View workflow status. Without `<name>`, lists all features.
|
|
120
|
+
|
|
121
|
+
查看工作流狀態。不帶 `<name>` 則列出所有 feature。
|
|
122
|
+
|
|
123
|
+
## Workflow / 工作流程
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
pxs init → pxs new → pxs refine → pxs implement → merge
|
|
127
|
+
│
|
|
128
|
+
pxs clarify (optional)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
implement 流程:
|
|
133
|
+
|
|
134
|
+
Task 1 → commit → [test] → AI review → approve/skip
|
|
135
|
+
Task 2 → commit → [test] → AI review → approve/skip
|
|
136
|
+
...
|
|
137
|
+
All tasks complete
|
|
138
|
+
↓
|
|
139
|
+
Final Code Review (full branch diff vs spec + plan)
|
|
140
|
+
↓
|
|
141
|
+
merge / squash-merge / keep-branch
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Claude Code Integration
|
|
145
|
+
|
|
146
|
+
After `pxs init`, the following slash commands are available in Claude Code:
|
|
147
|
+
|
|
148
|
+
執行 `pxs init` 後,可在 Claude Code 中使用以下 slash commands:
|
|
149
|
+
|
|
150
|
+
| Slash Command | Description |
|
|
151
|
+
|---------------|-------------|
|
|
152
|
+
| `/pxs:new` | Create a new spec / 建立規格 |
|
|
153
|
+
| `/pxs:refine` | Refine spec into plan / 拆解計畫 |
|
|
154
|
+
| `/pxs:clarify` | Clarify requirements / 釐清需求 |
|
|
155
|
+
| `/pxs:implement` | Implement task by task / 逐步實作 |
|
|
156
|
+
| `/pxs:review` | View reviews / 查看 review |
|
|
157
|
+
| `/pxs:status` | Check status / 查看狀態 |
|
|
158
|
+
|
|
159
|
+
## Project Structure / 專案結構
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
.workflow/
|
|
163
|
+
├── state.yaml # Workflow state / 工作流狀態
|
|
164
|
+
├── config.yaml # Project config / 專案設定
|
|
165
|
+
├── architecture.md # Architecture constraints (if --arch) / 架構約束
|
|
166
|
+
├── specs/ # Feature specs / 功能規格
|
|
167
|
+
├── plans/ # Implementation plans / 實作計畫
|
|
168
|
+
├── reviews/ # AI review records / AI review 紀錄
|
|
169
|
+
└── prompts/ # Prompt templates / Prompt 模板
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## License
|
|
173
|
+
|
|
174
|
+
MIT
|
package/dist/bin/pxs.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pxs.js","sourceRoot":"","sources":["../../bin/pxs.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;AAChC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AIBackend, ExecuteOptions, ExecuteResult } from './interface.js';
|
|
2
|
+
export declare class ClaudeBackend implements AIBackend {
|
|
3
|
+
name: string;
|
|
4
|
+
isAvailable(): Promise<boolean>;
|
|
5
|
+
execute(prompt: string, opts?: ExecuteOptions): Promise<ExecuteResult>;
|
|
6
|
+
resume(sessionId: string, prompt: string, opts?: ExecuteOptions): Promise<ExecuteResult>;
|
|
7
|
+
private _run;
|
|
8
|
+
private _parseStreamJson;
|
|
9
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { spawn, execFileSync } from 'node:child_process';
|
|
2
|
+
export class ClaudeBackend {
|
|
3
|
+
name = 'claude';
|
|
4
|
+
async isAvailable() {
|
|
5
|
+
try {
|
|
6
|
+
execFileSync('which', ['claude'], { encoding: 'utf-8' });
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
async execute(prompt, opts) {
|
|
14
|
+
return this._run(['claude', '-p', prompt, '--output-format', 'stream-json'], opts);
|
|
15
|
+
}
|
|
16
|
+
async resume(sessionId, prompt, opts) {
|
|
17
|
+
return this._run(['claude', '-p', prompt, '--resume', sessionId, '--output-format', 'stream-json'], opts);
|
|
18
|
+
}
|
|
19
|
+
_run(args, opts) {
|
|
20
|
+
const [cmd, ...cmdArgs] = args;
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
const child = spawn(cmd, cmdArgs, {
|
|
23
|
+
cwd: opts?.cwd ?? process.cwd(),
|
|
24
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
25
|
+
timeout: opts?.timeout,
|
|
26
|
+
});
|
|
27
|
+
let stdout = '';
|
|
28
|
+
let stderr = '';
|
|
29
|
+
child.stdout.on('data', (data) => {
|
|
30
|
+
stdout += data.toString();
|
|
31
|
+
});
|
|
32
|
+
child.stderr.on('data', (data) => {
|
|
33
|
+
stderr += data.toString();
|
|
34
|
+
});
|
|
35
|
+
child.on('close', (code) => {
|
|
36
|
+
const result = this._parseStreamJson(stdout);
|
|
37
|
+
resolve({
|
|
38
|
+
output: result.output,
|
|
39
|
+
sessionId: result.sessionId,
|
|
40
|
+
exitCode: code ?? 1,
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
child.on('error', (err) => {
|
|
44
|
+
reject(new Error(`Claude CLI error: ${err.message}`));
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
_parseStreamJson(raw) {
|
|
49
|
+
let output = '';
|
|
50
|
+
let sessionId = '';
|
|
51
|
+
const lines = raw.split('\n').filter((l) => l.trim());
|
|
52
|
+
for (const line of lines) {
|
|
53
|
+
try {
|
|
54
|
+
const json = JSON.parse(line);
|
|
55
|
+
if (json.type === 'assistant' && json.message?.content) {
|
|
56
|
+
for (const block of json.message.content) {
|
|
57
|
+
if (block.type === 'text') {
|
|
58
|
+
output += block.text;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (json.session_id) {
|
|
63
|
+
sessionId = json.session_id;
|
|
64
|
+
}
|
|
65
|
+
// Also check result message
|
|
66
|
+
if (json.type === 'result' && json.result) {
|
|
67
|
+
output = json.result;
|
|
68
|
+
}
|
|
69
|
+
if (json.type === 'result' && json.session_id) {
|
|
70
|
+
sessionId = json.session_id;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
// Not JSON, skip
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return { output, sessionId };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=claude.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../../../src/backends/claude.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGzD,MAAM,OAAO,aAAa;IACxB,IAAI,GAAG,QAAQ,CAAC;IAEhB,KAAK,CAAC,WAAW;QACf,IAAI,CAAC;YACH,YAAY,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;YACzD,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAc,EAAE,IAAqB;QACjD,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,EAAE,aAAa,CAAC,EAAE,IAAI,CAAC,CAAC;IACrF,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,SAAiB,EAAE,MAAc,EAAE,IAAqB;QACnE,OAAO,IAAI,CAAC,IAAI,CACd,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,iBAAiB,EAAE,aAAa,CAAC,EACjF,IAAI,CACL,CAAC;IACJ,CAAC;IAEO,IAAI,CAAC,IAAc,EAAE,IAAqB;QAChD,MAAM,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC;QAC/B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE;gBAChC,GAAG,EAAE,IAAI,EAAE,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE;gBAC/B,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;gBACjC,OAAO,EAAE,IAAI,EAAE,OAAO;aACvB,CAAC,CAAC;YAEH,IAAI,MAAM,GAAG,EAAE,CAAC;YAChB,IAAI,MAAM,GAAG,EAAE,CAAC;YAEhB,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;gBACvC,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC5B,CAAC,CAAC,CAAC;YAEH,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;gBACvC,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC5B,CAAC,CAAC,CAAC;YAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;gBACzB,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;gBAC7C,OAAO,CAAC;oBACN,MAAM,EAAE,MAAM,CAAC,MAAM;oBACrB,SAAS,EAAE,MAAM,CAAC,SAAS;oBAC3B,QAAQ,EAAE,IAAI,IAAI,CAAC;iBACpB,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBACxB,MAAM,CAAC,IAAI,KAAK,CAAC,qBAAqB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YACxD,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,gBAAgB,CAAC,GAAW;QAClC,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,SAAS,GAAG,EAAE,CAAC;QAEnB,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QACtD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC9B,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,IAAI,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC;oBACvD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;wBACzC,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;4BAC1B,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC;wBACvB,CAAC;oBACH,CAAC;gBACH,CAAC;gBACD,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;oBACpB,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC;gBAC9B,CAAC;gBACD,4BAA4B;gBAC5B,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;oBAC1C,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;gBACvB,CAAC;gBACD,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;oBAC9C,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC;gBAC9B,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,iBAAiB;YACnB,CAAC;QACH,CAAC;QAED,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAC/B,CAAC;CACF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AIBackend, ExecuteOptions, ExecuteResult } from './interface.js';
|
|
2
|
+
export declare class CodexBackend implements AIBackend {
|
|
3
|
+
name: string;
|
|
4
|
+
isAvailable(): Promise<boolean>;
|
|
5
|
+
execute(prompt: string, opts?: ExecuteOptions): Promise<ExecuteResult>;
|
|
6
|
+
resume(sessionId: string, prompt: string, opts?: ExecuteOptions): Promise<ExecuteResult>;
|
|
7
|
+
private _run;
|
|
8
|
+
private _parseJsonl;
|
|
9
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { spawn, execFileSync } from 'node:child_process';
|
|
2
|
+
export class CodexBackend {
|
|
3
|
+
name = 'codex';
|
|
4
|
+
async isAvailable() {
|
|
5
|
+
try {
|
|
6
|
+
execFileSync('which', ['codex'], { encoding: 'utf-8' });
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
async execute(prompt, opts) {
|
|
14
|
+
return this._run(['codex', 'exec', prompt, '--json'], opts);
|
|
15
|
+
}
|
|
16
|
+
async resume(sessionId, prompt, opts) {
|
|
17
|
+
return this._run(['codex', 'exec', 'resume', sessionId, prompt], opts);
|
|
18
|
+
}
|
|
19
|
+
_run(args, opts) {
|
|
20
|
+
const [cmd, ...cmdArgs] = args;
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
const child = spawn(cmd, cmdArgs, {
|
|
23
|
+
cwd: opts?.cwd ?? process.cwd(),
|
|
24
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
25
|
+
timeout: opts?.timeout,
|
|
26
|
+
});
|
|
27
|
+
let stdout = '';
|
|
28
|
+
let stderr = '';
|
|
29
|
+
child.stdout.on('data', (data) => {
|
|
30
|
+
stdout += data.toString();
|
|
31
|
+
});
|
|
32
|
+
child.stderr.on('data', (data) => {
|
|
33
|
+
stderr += data.toString();
|
|
34
|
+
});
|
|
35
|
+
child.on('close', (code) => {
|
|
36
|
+
const result = this._parseJsonl(stdout);
|
|
37
|
+
resolve({
|
|
38
|
+
output: result.output,
|
|
39
|
+
sessionId: result.sessionId,
|
|
40
|
+
exitCode: code ?? 1,
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
child.on('error', (err) => {
|
|
44
|
+
reject(new Error(`Codex CLI error: ${err.message}`));
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
_parseJsonl(raw) {
|
|
49
|
+
let output = '';
|
|
50
|
+
let sessionId = '';
|
|
51
|
+
const lines = raw.split('\n').filter((l) => l.trim());
|
|
52
|
+
for (const line of lines) {
|
|
53
|
+
try {
|
|
54
|
+
const json = JSON.parse(line);
|
|
55
|
+
if (json.output)
|
|
56
|
+
output += json.output;
|
|
57
|
+
if (json.text)
|
|
58
|
+
output += json.text;
|
|
59
|
+
if (json.session_id)
|
|
60
|
+
sessionId = json.session_id;
|
|
61
|
+
if (json.id)
|
|
62
|
+
sessionId = json.id;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
// Plain text fallback
|
|
66
|
+
output += line + '\n';
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return { output: output.trim(), sessionId };
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=codex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../../src/backends/codex.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ClaudeBackend } from './claude.js';
|
|
2
|
+
import { CodexBackend } from './codex.js';
|
|
3
|
+
const backends = {
|
|
4
|
+
claude: () => new ClaudeBackend(),
|
|
5
|
+
codex: () => new CodexBackend(),
|
|
6
|
+
};
|
|
7
|
+
export function createBackend(name) {
|
|
8
|
+
const factory = backends[name];
|
|
9
|
+
if (!factory) {
|
|
10
|
+
throw new Error(`Unknown backend: "${name}". Available: ${Object.keys(backends).join(', ')}`);
|
|
11
|
+
}
|
|
12
|
+
return factory();
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../../src/backends/factory.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,QAAQ,GAAoC;IAChD,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,aAAa,EAAE;IACjC,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,YAAY,EAAE;CAChC,CAAC;AAEF,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,iBAAiB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAChG,CAAC;IACD,OAAO,OAAO,EAAE,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface ExecuteOptions {
|
|
2
|
+
cwd?: string;
|
|
3
|
+
timeout?: number;
|
|
4
|
+
}
|
|
5
|
+
export interface ExecuteResult {
|
|
6
|
+
output: string;
|
|
7
|
+
sessionId: string;
|
|
8
|
+
exitCode: number;
|
|
9
|
+
}
|
|
10
|
+
export interface AIBackend {
|
|
11
|
+
name: string;
|
|
12
|
+
isAvailable(): Promise<boolean>;
|
|
13
|
+
execute(prompt: string, opts?: ExecuteOptions): Promise<ExecuteResult>;
|
|
14
|
+
resume(sessionId: string, prompt: string, opts?: ExecuteOptions): Promise<ExecuteResult>;
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interface.js","sourceRoot":"","sources":["../../../src/backends/interface.ts"],"names":[],"mappings":""}
|
package/dist/src/cli.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { initCommand } from './commands/init.js';
|
|
3
|
+
import { newCommand } from './commands/new.js';
|
|
4
|
+
import { refineCommand } from './commands/refine.js';
|
|
5
|
+
import { clarifyCommand } from './commands/clarify.js';
|
|
6
|
+
import { implementCommand } from './commands/implement.js';
|
|
7
|
+
import { reviewCommand } from './commands/review.js';
|
|
8
|
+
import { statusCommand } from './commands/status.js';
|
|
9
|
+
import { parseArgs } from './parsers/arguments.js';
|
|
10
|
+
export function createProgram() {
|
|
11
|
+
const program = new Command();
|
|
12
|
+
program
|
|
13
|
+
.name('pxs')
|
|
14
|
+
.description('Spec-driven development CLI')
|
|
15
|
+
.version('1.0.0');
|
|
16
|
+
program
|
|
17
|
+
.command('init')
|
|
18
|
+
.description('Initialize pxs workflow for this project')
|
|
19
|
+
.option('--force', 'Overwrite existing .workflow/')
|
|
20
|
+
.option('--arch <architecture>', 'Architecture pattern (clean|hexagonal|ddd|layered|modular|custom)')
|
|
21
|
+
.option('--lang <lang-framework>', 'Language-framework (overrides auto-detect)')
|
|
22
|
+
.action(initCommand);
|
|
23
|
+
program
|
|
24
|
+
.command('new <name>')
|
|
25
|
+
.description('Create a new spec file')
|
|
26
|
+
.option('--desc <text>', 'Generate spec from text description')
|
|
27
|
+
.option('--jira <tickets...>', 'Import from Jira tickets')
|
|
28
|
+
.option('-i, --interactive', 'Interactive Q&A mode')
|
|
29
|
+
.action(newCommand);
|
|
30
|
+
program
|
|
31
|
+
.command('refine <name>')
|
|
32
|
+
.description('Refine spec and decompose implementation plan')
|
|
33
|
+
.option('--skip-clarify', 'Skip requirement clarification')
|
|
34
|
+
.option('--clarify <n>', 'Max clarification rounds', parseInt)
|
|
35
|
+
.allowUnknownOption()
|
|
36
|
+
.action((name, options, cmd) => {
|
|
37
|
+
const rawArgs = cmd.args ?? [];
|
|
38
|
+
const parsed = parseArgs(rawArgs);
|
|
39
|
+
return refineCommand(name, parsed, options);
|
|
40
|
+
});
|
|
41
|
+
program
|
|
42
|
+
.command('clarify <name>')
|
|
43
|
+
.description('Run requirement clarification on a spec')
|
|
44
|
+
.allowUnknownOption()
|
|
45
|
+
.action((name, _options, cmd) => {
|
|
46
|
+
const rawArgs = cmd.args ?? [];
|
|
47
|
+
const parsed = parseArgs(rawArgs);
|
|
48
|
+
return clarifyCommand(name, parsed);
|
|
49
|
+
});
|
|
50
|
+
program
|
|
51
|
+
.command('implement <name>')
|
|
52
|
+
.description('Implement code task by task')
|
|
53
|
+
.option('--backend <name>', 'AI backend (claude | codex)')
|
|
54
|
+
.option('--test [types...]', 'Test strategy')
|
|
55
|
+
.option('--skip-review', 'Skip final branch code review')
|
|
56
|
+
.allowUnknownOption()
|
|
57
|
+
.action((name, options, cmd) => {
|
|
58
|
+
const rawArgs = cmd.args ?? [];
|
|
59
|
+
const parsed = parseArgs(rawArgs);
|
|
60
|
+
return implementCommand(name, parsed, options);
|
|
61
|
+
});
|
|
62
|
+
program
|
|
63
|
+
.command('review <name>')
|
|
64
|
+
.description('View review records')
|
|
65
|
+
.option('--step <n>', 'View specific task review', parseInt)
|
|
66
|
+
.option('--summary', 'Summary overview of all tasks')
|
|
67
|
+
.allowUnknownOption()
|
|
68
|
+
.action((name, options) => {
|
|
69
|
+
return reviewCommand(name, options);
|
|
70
|
+
});
|
|
71
|
+
program
|
|
72
|
+
.command('status [name]')
|
|
73
|
+
.description('View workflow status')
|
|
74
|
+
.action((name) => {
|
|
75
|
+
return statusCommand(name);
|
|
76
|
+
});
|
|
77
|
+
return program;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { StateManager } from '../state/manager.js';
|
|
3
|
+
import { createBackend } from '../backends/factory.js';
|
|
4
|
+
import { assemblePrompt } from '../utils/prompt.js';
|
|
5
|
+
import * as display from '../utils/display.js';
|
|
6
|
+
export async function clarifyCommand(name, args) {
|
|
7
|
+
const state = new StateManager();
|
|
8
|
+
state.ensureWorkflow();
|
|
9
|
+
state.checkPhaseGuard('clarify', name);
|
|
10
|
+
const specPath = state.specPath(name);
|
|
11
|
+
if (!fs.existsSync(specPath)) {
|
|
12
|
+
display.error(`Spec "${name}" not found. Run \`pxs new ${name}\` first.`);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const specContent = fs.readFileSync(specPath, 'utf-8');
|
|
16
|
+
const config = state.readConfig();
|
|
17
|
+
const backend = createBackend(config.backend.default);
|
|
18
|
+
if (!(await backend.isAvailable())) {
|
|
19
|
+
display.error(`Backend "${config.backend.default}" not available.`);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
display.heading(`Clarifying: ${name}`);
|
|
23
|
+
const prompt = assemblePrompt({
|
|
24
|
+
templateName: 'clarify',
|
|
25
|
+
vars: { spec_content: specContent },
|
|
26
|
+
agents: args.agents,
|
|
27
|
+
skills: args.skills,
|
|
28
|
+
extraText: args.text,
|
|
29
|
+
});
|
|
30
|
+
const feature = state.getFeature(name);
|
|
31
|
+
let result;
|
|
32
|
+
if (feature?.session?.id) {
|
|
33
|
+
result = await backend.resume(feature.session.id, prompt);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
result = await backend.execute(prompt);
|
|
37
|
+
}
|
|
38
|
+
console.log('\n' + result.output);
|
|
39
|
+
// Update state
|
|
40
|
+
if (feature) {
|
|
41
|
+
feature.phase = 'clarifying';
|
|
42
|
+
feature.session = { backend: config.backend.default, id: result.sessionId };
|
|
43
|
+
state.upsertFeature(feature);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=clarify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clarify.js","sourceRoot":"","sources":["../../../src/commands/clarify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAC;AAE/C,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,IAAY,EACZ,IAA0D;IAE1D,MAAM,KAAK,GAAG,IAAI,YAAY,EAAE,CAAC;IACjC,KAAK,CAAC,cAAc,EAAE,CAAC;IACvB,KAAK,CAAC,eAAe,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAEvC,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,KAAK,CAAC,SAAS,IAAI,8BAA8B,IAAI,WAAW,CAAC,CAAC;QAC1E,OAAO;IACT,CAAC;IAED,MAAM,WAAW,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACvD,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,EAAE,CAAC;IAClC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAEtD,IAAI,CAAC,CAAC,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;QACnC,OAAO,CAAC,KAAK,CAAC,YAAY,MAAM,CAAC,OAAO,CAAC,OAAO,kBAAkB,CAAC,CAAC;QACpE,OAAO;IACT,CAAC;IAED,OAAO,CAAC,OAAO,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC;IAEvC,MAAM,MAAM,GAAG,cAAc,CAAC;QAC5B,YAAY,EAAE,SAAS;QACvB,IAAI,EAAE,EAAE,YAAY,EAAE,WAAW,EAAE;QACnC,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,SAAS,EAAE,IAAI,CAAC,IAAI;KACrB,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,MAAM,CAAC;IACX,IAAI,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QACzB,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAC5D,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IAElC,eAAe;IACf,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,GAAG,YAAY,CAAC;QAC7B,OAAO,CAAC,OAAO,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC;QAC5E,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;AACH,CAAC"}
|