spets 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -5,23 +5,27 @@ Spec Driven Development Execution Framework - 유저가 정의한 스텝대로 S
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
+
# 글로벌 설치 (선택)
|
|
8
9
|
npm install -g spets
|
|
10
|
+
|
|
11
|
+
# 또는 npx로 바로 사용 (설치 불필요)
|
|
12
|
+
npx spets init
|
|
9
13
|
```
|
|
10
14
|
|
|
11
15
|
## Quick Start
|
|
12
16
|
|
|
13
17
|
```bash
|
|
14
18
|
# 프로젝트에서 초기화
|
|
15
|
-
spets init
|
|
19
|
+
npx spets init
|
|
16
20
|
|
|
17
21
|
# 워크플로우 시작
|
|
18
|
-
spets start "TODO 앱 만들어줘"
|
|
22
|
+
npx spets start "TODO 앱 만들어줘"
|
|
19
23
|
|
|
20
24
|
# 상태 확인
|
|
21
|
-
spets status
|
|
25
|
+
npx spets status
|
|
22
26
|
|
|
23
27
|
# 중단된 워크플로우 재개
|
|
24
|
-
spets resume
|
|
28
|
+
npx spets resume
|
|
25
29
|
```
|
|
26
30
|
|
|
27
31
|
## How it Works
|
|
@@ -56,10 +60,10 @@ PR/Issue 코멘트로 워크플로우 제어:
|
|
|
56
60
|
|
|
57
61
|
```bash
|
|
58
62
|
# GitHub Actions 워크플로우 포함해서 초기화
|
|
59
|
-
spets init --github
|
|
63
|
+
npx spets init --github
|
|
60
64
|
|
|
61
65
|
# GitHub 플랫폼으로 시작
|
|
62
|
-
spets start "task" --platform github --owner myorg --repo myrepo --issue 42
|
|
66
|
+
npx spets start "task" --platform github --owner myorg --repo myrepo --issue 42
|
|
63
67
|
```
|
|
64
68
|
|
|
65
69
|
코멘트 명령어:
|
|
@@ -71,12 +75,14 @@ spets start "task" --platform github --owner myorg --repo myrepo --issue 42
|
|
|
71
75
|
|
|
72
76
|
```bash
|
|
73
77
|
# Claude Code 스킬 설치
|
|
74
|
-
spets plugin install claude
|
|
78
|
+
npx spets plugin install claude
|
|
75
79
|
|
|
76
80
|
# Claude Code에서 사용
|
|
77
81
|
/spets start "task description"
|
|
78
82
|
```
|
|
79
83
|
|
|
84
|
+
스킬이 설치되면 Claude Code 내에서 `npx spets` 명령어를 자동으로 실행합니다. 글로벌 설치 없이도 동작합니다.
|
|
85
|
+
|
|
80
86
|
## Configuration
|
|
81
87
|
|
|
82
88
|
`.sept/config.yml`:
|
|
@@ -52,6 +52,10 @@ function loadStepDefinition(stepName, cwd = process.cwd()) {
|
|
|
52
52
|
template
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
|
+
function getGitHubConfig(cwd = process.cwd()) {
|
|
56
|
+
const config = loadConfig(cwd);
|
|
57
|
+
return config.github;
|
|
58
|
+
}
|
|
55
59
|
|
|
56
60
|
// src/core/state.ts
|
|
57
61
|
function generateTaskId() {
|
|
@@ -194,6 +198,7 @@ export {
|
|
|
194
198
|
spetsExists,
|
|
195
199
|
loadConfig,
|
|
196
200
|
loadStepDefinition,
|
|
201
|
+
getGitHubConfig,
|
|
197
202
|
generateTaskId,
|
|
198
203
|
getTaskDir,
|
|
199
204
|
getOutputPath,
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
generateTaskId,
|
|
4
|
+
getGitHubConfig,
|
|
4
5
|
getOutputPath,
|
|
5
6
|
getSpetsDir,
|
|
6
7
|
getWorkflowState,
|
|
@@ -13,7 +14,7 @@ import {
|
|
|
13
14
|
saveTaskMetadata,
|
|
14
15
|
spetsExists,
|
|
15
16
|
updateDocumentStatus
|
|
16
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-XYU22TND.js";
|
|
17
18
|
|
|
18
19
|
// src/index.ts
|
|
19
20
|
import { Command } from "commander";
|
|
@@ -37,12 +38,14 @@ async function initCommand(options) {
|
|
|
37
38
|
const templatesDir = join(__dirname, "..", "templates");
|
|
38
39
|
writeFileSync(join(spetsDir, "config.yml"), getDefaultConfig());
|
|
39
40
|
createDefaultSteps(spetsDir);
|
|
41
|
+
createClaudeCommand(cwd);
|
|
40
42
|
console.log("Initialized spets in .spets/");
|
|
41
43
|
console.log("");
|
|
42
44
|
console.log("Created:");
|
|
43
|
-
console.log(" .spets/config.yml
|
|
44
|
-
console.log(" .spets/steps/01-plan/
|
|
45
|
-
console.log(" .spets/steps/02-implement/
|
|
45
|
+
console.log(" .spets/config.yml - Workflow configuration");
|
|
46
|
+
console.log(" .spets/steps/01-plan/ - Planning step");
|
|
47
|
+
console.log(" .spets/steps/02-implement/ - Implementation step");
|
|
48
|
+
console.log(" .claude/commands/spets.md - Claude Code command");
|
|
46
49
|
if (options.github) {
|
|
47
50
|
createGitHubWorkflow(cwd);
|
|
48
51
|
console.log(" .github/workflows/spets.yml - GitHub Actions workflow");
|
|
@@ -236,6 +239,65 @@ None / List any deviations with justification.
|
|
|
236
239
|
- Follow-up task 2
|
|
237
240
|
`;
|
|
238
241
|
}
|
|
242
|
+
function createClaudeCommand(cwd) {
|
|
243
|
+
const commandDir = join(cwd, ".claude", "commands");
|
|
244
|
+
mkdirSync(commandDir, { recursive: true });
|
|
245
|
+
writeFileSync(join(commandDir, "spets.md"), getClaudeCommand());
|
|
246
|
+
}
|
|
247
|
+
function getClaudeCommand() {
|
|
248
|
+
return `# Spets - Spec Driven Development
|
|
249
|
+
|
|
250
|
+
Run spets workflows from Claude Code.
|
|
251
|
+
|
|
252
|
+
## Usage
|
|
253
|
+
|
|
254
|
+
\`\`\`
|
|
255
|
+
/spets start "task description" - Start a new workflow
|
|
256
|
+
/spets status - Show workflow status
|
|
257
|
+
/spets resume - Resume paused workflow
|
|
258
|
+
\`\`\`
|
|
259
|
+
|
|
260
|
+
## Instructions
|
|
261
|
+
|
|
262
|
+
When the user invokes this command:
|
|
263
|
+
|
|
264
|
+
1. Parse the subcommand (start, status, resume)
|
|
265
|
+
2. Execute the appropriate spets CLI command using Bash
|
|
266
|
+
3. For 'start', read the generated documents and help iterate
|
|
267
|
+
|
|
268
|
+
### Start Flow
|
|
269
|
+
|
|
270
|
+
1. Run: \`npx spets start "<query>"\`
|
|
271
|
+
2. Read the generated plan document from .spets/outputs/<taskId>/
|
|
272
|
+
3. Present the plan to the user
|
|
273
|
+
4. If user approves, continue. If they want changes, provide feedback.
|
|
274
|
+
|
|
275
|
+
### Status Flow
|
|
276
|
+
|
|
277
|
+
1. Run: \`npx spets status\`
|
|
278
|
+
2. Present the current workflow state
|
|
279
|
+
|
|
280
|
+
### Resume Flow
|
|
281
|
+
|
|
282
|
+
1. Run: \`npx spets resume\`
|
|
283
|
+
2. Continue the workflow from where it paused
|
|
284
|
+
|
|
285
|
+
## Example Session
|
|
286
|
+
|
|
287
|
+
User: /spets start "Create a REST API for user management"
|
|
288
|
+
|
|
289
|
+
Claude:
|
|
290
|
+
1. Runs \`npx spets start "Create a REST API for user management"\`
|
|
291
|
+
2. Reads the generated plan
|
|
292
|
+
3. Asks user: "Here's the plan. [shows plan] Would you like to approve or revise?"
|
|
293
|
+
4. On approve: \`npx spets resume --approve\`
|
|
294
|
+
5. On revise: \`npx spets resume --revise "user feedback"\`
|
|
295
|
+
|
|
296
|
+
$ARGUMENTS
|
|
297
|
+
command: The spets command to run (start, status, resume)
|
|
298
|
+
args: Additional arguments for the command
|
|
299
|
+
`;
|
|
300
|
+
}
|
|
239
301
|
function createGitHubWorkflow(cwd) {
|
|
240
302
|
const workflowDir = join(cwd, ".github", "workflows");
|
|
241
303
|
mkdirSync(workflowDir, { recursive: true });
|
|
@@ -591,7 +653,7 @@ var Executor = class {
|
|
|
591
653
|
};
|
|
592
654
|
|
|
593
655
|
// src/platform/cli.ts
|
|
594
|
-
import { spawn as spawn2 } from "child_process";
|
|
656
|
+
import { spawn as spawn2, execSync } from "child_process";
|
|
595
657
|
import { input, select, confirm } from "@inquirer/prompts";
|
|
596
658
|
|
|
597
659
|
// src/platform/interface.ts
|
|
@@ -740,6 +802,24 @@ var CliPlatform = class extends BasePlatform {
|
|
|
740
802
|
});
|
|
741
803
|
});
|
|
742
804
|
}
|
|
805
|
+
isClaudeInstalled() {
|
|
806
|
+
try {
|
|
807
|
+
const command = process.platform === "win32" ? "where" : "which";
|
|
808
|
+
execSync(`${command} claude`, { stdio: "ignore" });
|
|
809
|
+
return true;
|
|
810
|
+
} catch {
|
|
811
|
+
return false;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
getClaudeExecutable() {
|
|
815
|
+
if (this.claudeCommand !== "claude") {
|
|
816
|
+
return { command: this.claudeCommand, args: [] };
|
|
817
|
+
}
|
|
818
|
+
if (this.isClaudeInstalled()) {
|
|
819
|
+
return { command: "claude", args: [] };
|
|
820
|
+
}
|
|
821
|
+
return { command: "npx", args: ["--yes", "@anthropic-ai/claude-code"] };
|
|
822
|
+
}
|
|
743
823
|
parseResponse(response) {
|
|
744
824
|
const questions = [];
|
|
745
825
|
const questionMatch = response.match(/```questions\n([\s\S]*?)```/);
|
|
@@ -1015,19 +1095,24 @@ async function startCommand(query, options) {
|
|
|
1015
1095
|
saveTaskMetadata(taskId, query, cwd);
|
|
1016
1096
|
let platform;
|
|
1017
1097
|
if (options.platform === "github") {
|
|
1018
|
-
|
|
1019
|
-
|
|
1098
|
+
const githubConfig = getGitHubConfig(cwd);
|
|
1099
|
+
const owner = options.owner || githubConfig?.owner;
|
|
1100
|
+
const repo = options.repo || githubConfig?.repo;
|
|
1101
|
+
const pr = options.pr || (githubConfig?.defaultPr ? String(githubConfig.defaultPr) : void 0);
|
|
1102
|
+
const issue = options.issue || (githubConfig?.defaultIssue ? String(githubConfig.defaultIssue) : void 0);
|
|
1103
|
+
if (!owner || !repo) {
|
|
1104
|
+
console.error("GitHub platform requires --owner and --repo (or set in .spets/config.yml)");
|
|
1020
1105
|
process.exit(1);
|
|
1021
1106
|
}
|
|
1022
|
-
if (!
|
|
1023
|
-
console.error("GitHub platform requires --pr or --issue");
|
|
1107
|
+
if (!pr && !issue) {
|
|
1108
|
+
console.error("GitHub platform requires --pr or --issue (or set defaultPr/defaultIssue in .spets/config.yml)");
|
|
1024
1109
|
process.exit(1);
|
|
1025
1110
|
}
|
|
1026
1111
|
platform = new GitHubPlatform({
|
|
1027
|
-
owner
|
|
1028
|
-
repo
|
|
1029
|
-
prNumber:
|
|
1030
|
-
issueNumber:
|
|
1112
|
+
owner,
|
|
1113
|
+
repo,
|
|
1114
|
+
prNumber: pr ? parseInt(pr, 10) : void 0,
|
|
1115
|
+
issueNumber: issue ? parseInt(issue, 10) : void 0
|
|
1031
1116
|
});
|
|
1032
1117
|
} else {
|
|
1033
1118
|
platform = new CliPlatform();
|
|
@@ -1188,6 +1273,8 @@ function installClaudePlugin() {
|
|
|
1188
1273
|
console.log(' /spets start "your task description"');
|
|
1189
1274
|
console.log(" /spets status");
|
|
1190
1275
|
console.log(" /spets resume");
|
|
1276
|
+
console.log("");
|
|
1277
|
+
console.log("Note: The plugin uses npx to run spets, so global installation is not required.");
|
|
1191
1278
|
}
|
|
1192
1279
|
async function uninstallPlugin(name) {
|
|
1193
1280
|
if (name === "claude") {
|
|
@@ -1238,21 +1325,23 @@ When the user invokes this command:
|
|
|
1238
1325
|
2. Execute the appropriate spets CLI command using Bash
|
|
1239
1326
|
3. For 'start', read the generated documents and help iterate
|
|
1240
1327
|
|
|
1328
|
+
**Important**: Use \`npx spets\` to run commands. This ensures the command works even if spets is not globally installed.
|
|
1329
|
+
|
|
1241
1330
|
### Start Flow
|
|
1242
1331
|
|
|
1243
|
-
1. Run: \`spets start "<query>"\`
|
|
1332
|
+
1. Run: \`npx spets start "<query>"\`
|
|
1244
1333
|
2. Read the generated plan document from .spets/outputs/<taskId>/
|
|
1245
1334
|
3. Present the plan to the user
|
|
1246
1335
|
4. If user approves, continue. If they want changes, provide feedback.
|
|
1247
1336
|
|
|
1248
1337
|
### Status Flow
|
|
1249
1338
|
|
|
1250
|
-
1. Run: \`spets status\`
|
|
1339
|
+
1. Run: \`npx spets status\`
|
|
1251
1340
|
2. Present the current workflow state
|
|
1252
1341
|
|
|
1253
1342
|
### Resume Flow
|
|
1254
1343
|
|
|
1255
|
-
1. Run: \`spets resume\`
|
|
1344
|
+
1. Run: \`npx spets resume\`
|
|
1256
1345
|
2. Continue the workflow from where it paused
|
|
1257
1346
|
|
|
1258
1347
|
## Example Session
|
|
@@ -1260,11 +1349,11 @@ When the user invokes this command:
|
|
|
1260
1349
|
User: /spets start "Create a REST API for user management"
|
|
1261
1350
|
|
|
1262
1351
|
Claude:
|
|
1263
|
-
1. Runs \`spets start "Create a REST API for user management"\`
|
|
1352
|
+
1. Runs \`npx spets start "Create a REST API for user management"\`
|
|
1264
1353
|
2. Reads the generated plan
|
|
1265
1354
|
3. Asks user: "Here's the plan. [shows plan] Would you like to approve or revise?"
|
|
1266
|
-
4. On approve: \`spets resume --approve\`
|
|
1267
|
-
5. On revise: \`spets resume --revise "user feedback"\`
|
|
1355
|
+
4. On approve: \`npx spets resume --approve\`
|
|
1356
|
+
5. On revise: \`npx spets resume --revise "user feedback"\`
|
|
1268
1357
|
|
|
1269
1358
|
$ARGUMENTS
|
|
1270
1359
|
command: The spets command to run (start, status, resume)
|
|
@@ -1279,9 +1368,18 @@ async function githubCommand(options) {
|
|
|
1279
1368
|
console.error("Spets not initialized.");
|
|
1280
1369
|
process.exit(1);
|
|
1281
1370
|
}
|
|
1282
|
-
const
|
|
1371
|
+
const configGitHub = getGitHubConfig(cwd);
|
|
1372
|
+
const owner = options.owner || configGitHub?.owner;
|
|
1373
|
+
const repo = options.repo || configGitHub?.repo;
|
|
1374
|
+
const pr = options.pr || (configGitHub?.defaultPr ? String(configGitHub.defaultPr) : void 0);
|
|
1375
|
+
const issue = options.issue || (configGitHub?.defaultIssue ? String(configGitHub.defaultIssue) : void 0);
|
|
1376
|
+
const { comment, task } = options;
|
|
1377
|
+
if (!owner || !repo) {
|
|
1378
|
+
console.error("GitHub requires --owner and --repo (or set in .spets/config.yml)");
|
|
1379
|
+
process.exit(1);
|
|
1380
|
+
}
|
|
1283
1381
|
if (!pr && !issue) {
|
|
1284
|
-
console.error("Either --pr or --issue is required");
|
|
1382
|
+
console.error("Either --pr or --issue is required (or set defaultPr/defaultIssue in .spets/config.yml)");
|
|
1285
1383
|
process.exit(1);
|
|
1286
1384
|
}
|
|
1287
1385
|
const parsed = parseGitHubCommand(comment);
|
|
@@ -1299,7 +1397,7 @@ async function githubCommand(options) {
|
|
|
1299
1397
|
}
|
|
1300
1398
|
if (!taskId) {
|
|
1301
1399
|
const config2 = loadConfig(cwd);
|
|
1302
|
-
const { listTasks: listTasks2 } = await import("./state-
|
|
1400
|
+
const { listTasks: listTasks2 } = await import("./state-H2GQS43T.js");
|
|
1303
1401
|
const tasks = listTasks2(cwd);
|
|
1304
1402
|
for (const tid of tasks) {
|
|
1305
1403
|
const state2 = getWorkflowState(tid, config2, cwd);
|
|
@@ -1431,6 +1529,6 @@ program.command("init").description("Initialize spets in current directory").opt
|
|
|
1431
1529
|
program.command("status").description("Show current workflow status").option("-t, --task <taskId>", "Show status for specific task").action(statusCommand);
|
|
1432
1530
|
program.command("start").description("Start a new workflow").argument("<query>", "User query describing the task").option("-p, --platform <platform>", "Platform to use (cli, github)", "cli").option("--owner <owner>", "GitHub owner (for github platform)").option("--repo <repo>", "GitHub repo (for github platform)").option("--pr <number>", "GitHub PR number (for github platform)").option("--issue <number>", "GitHub issue number (for github platform)").action(startCommand);
|
|
1433
1531
|
program.command("resume").description("Resume paused workflow").option("-t, --task <taskId>", "Resume specific task").option("--approve", "Approve current document and proceed").option("--revise <feedback>", "Request revision with feedback").action(resumeCommand);
|
|
1434
|
-
program.command("github").description("Handle GitHub Action callback (internal)").
|
|
1532
|
+
program.command("github").description("Handle GitHub Action callback (internal)").option("--owner <owner>", "GitHub owner (or set in .spets/config.yml)").option("--repo <repo>", "GitHub repo (or set in .spets/config.yml)").option("--pr <number>", "PR number (or set defaultPr in .spets/config.yml)").option("--issue <number>", "Issue number (or set defaultIssue in .spets/config.yml)").option("-t, --task <taskId>", "Task ID").requiredOption("--comment <comment>", "Comment body").action(githubCommand);
|
|
1435
1533
|
program.command("plugin").description("Manage plugins").argument("<action>", "Action: install, uninstall, list").argument("[name]", "Plugin name").action(pluginCommand);
|
|
1436
1534
|
program.parse();
|