skiv 0.0.2 → 0.0.5
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 +6 -3
- package/bin/skiv.ts +3 -0
- package/package.json +9 -4
- package/skeleton/config.yaml +2 -2
- package/skeleton/roles/corder/CLAUDE.md +26 -44
- package/skeleton/roles/corder/custom.ts +43 -26
- package/skeleton/roles/pm/.claude/settings.local.json +13 -0
- package/skeleton/roles/pm/CLAUDE.md +56 -0
- package/skeleton/roles/pm/custom.ts +75 -0
- package/skeleton/roles/reviewer/CLAUDE.md +31 -31
- package/skeleton/roles/reviewer/custom.ts +49 -21
- package/skeleton/roles/se/CLAUDE.md +11 -5
- package/skeleton/spec.md +0 -0
- package/skeleton/worker.ts +29 -0
- package/bin/________________________skiv.ts +0 -3
- package/bin/skiv.js +0 -3
- package/dist/cjs/IssueService.js +0 -236
- package/dist/cjs/Logger.js +0 -39
- package/dist/cjs/Member.js +0 -83
- package/dist/cjs/cli.js +0 -94
- package/dist/cjs/commands/Command.js +0 -66
- package/dist/cjs/commands/InitCommand.js +0 -27
- package/dist/cjs/commands/IssueCommand.js +0 -39
- package/dist/cjs/commands/RunCommand.js +0 -57
- package/dist/cjs/commands/StartCommand.js +0 -69
- package/dist/cjs/db/index.js +0 -27
- package/dist/cjs/db/migrations.js +0 -36
- package/dist/cjs/db/schema.js +0 -25
- package/dist/cjs/utils.js +0 -32
- package/dist/esm/IssueService.d.ts +0 -65
- package/dist/esm/IssueService.d.ts.map +0 -1
- package/dist/esm/IssueService.js +0 -232
- package/dist/esm/Logger.d.ts +0 -21
- package/dist/esm/Logger.d.ts.map +0 -1
- package/dist/esm/Logger.js +0 -36
- package/dist/esm/Member.d.ts +0 -21
- package/dist/esm/Member.d.ts.map +0 -1
- package/dist/esm/Member.js +0 -77
- package/dist/esm/cli.d.ts +0 -2
- package/dist/esm/cli.d.ts.map +0 -1
- package/dist/esm/cli.js +0 -89
- package/dist/esm/commands/Command.d.ts +0 -19
- package/dist/esm/commands/Command.d.ts.map +0 -1
- package/dist/esm/commands/Command.js +0 -30
- package/dist/esm/commands/InitCommand.d.ts +0 -5
- package/dist/esm/commands/InitCommand.d.ts.map +0 -1
- package/dist/esm/commands/InitCommand.js +0 -21
- package/dist/esm/commands/IssueCommand.d.ts +0 -10
- package/dist/esm/commands/IssueCommand.d.ts.map +0 -1
- package/dist/esm/commands/IssueCommand.js +0 -33
- package/dist/esm/commands/RunCommand.d.ts +0 -5
- package/dist/esm/commands/RunCommand.d.ts.map +0 -1
- package/dist/esm/commands/RunCommand.js +0 -18
- package/dist/esm/commands/StartCommand.d.ts +0 -28
- package/dist/esm/commands/StartCommand.d.ts.map +0 -1
- package/dist/esm/commands/StartCommand.js +0 -63
- package/dist/esm/db/index.d.ts +0 -6
- package/dist/esm/db/index.d.ts.map +0 -1
- package/dist/esm/db/index.js +0 -19
- package/dist/esm/db/migrations.d.ts +0 -3
- package/dist/esm/db/migrations.d.ts.map +0 -1
- package/dist/esm/db/migrations.js +0 -33
- package/dist/esm/db/schema.d.ts +0 -46
- package/dist/esm/db/schema.d.ts.map +0 -1
- package/dist/esm/db/schema.js +0 -20
- package/dist/esm/utils.d.ts +0 -7
- package/dist/esm/utils.d.ts.map +0 -1
- package/dist/esm/utils.js +0 -25
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
## Installation
|
|
4
4
|
|
|
5
5
|
```shell
|
|
6
|
-
npm i -g skiv
|
|
6
|
+
$ npm i -g skiv
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
## Usage
|
|
@@ -13,15 +13,18 @@ npm i -g skiv
|
|
|
13
13
|
cd to your project directory
|
|
14
14
|
|
|
15
15
|
```shell
|
|
16
|
-
npx skiv init
|
|
16
|
+
$ npx skiv init
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
generate `.skiv` directory
|
|
20
20
|
|
|
21
21
|
edit `.skiv/config.yaml` and `.skiv/roles/*`
|
|
22
22
|
|
|
23
|
+
add `.skiv` to your gitignore
|
|
24
|
+
|
|
23
25
|
### Start
|
|
24
26
|
|
|
25
27
|
```shell
|
|
26
|
-
|
|
28
|
+
$ tmux
|
|
29
|
+
$ npx skiv start
|
|
27
30
|
```
|
package/bin/skiv.ts
ADDED
package/package.json
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skiv",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
7
|
"description": "claude code orchestration tool",
|
|
8
8
|
"license": "MIT",
|
|
9
9
|
"author": "",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/masashimachida/skiv.git"
|
|
13
|
+
},
|
|
10
14
|
"type": "commonjs",
|
|
11
15
|
"main": "dist/esm/index.js",
|
|
12
16
|
"scripts": {
|
|
@@ -22,14 +26,13 @@
|
|
|
22
26
|
"skeleton"
|
|
23
27
|
],
|
|
24
28
|
"bin": {
|
|
25
|
-
"skiv": "bin/skiv.
|
|
29
|
+
"skiv": "bin/skiv.ts"
|
|
26
30
|
},
|
|
27
31
|
"devDependencies": {
|
|
28
32
|
"@types/better-sqlite3": "^7.6.13",
|
|
29
33
|
"@types/fs-extra": "^11.0.4",
|
|
30
34
|
"@types/js-yaml": "^4.0.9",
|
|
31
35
|
"@types/node": "^25.2.0",
|
|
32
|
-
"tsx": "^4.21.0",
|
|
33
36
|
"typescript": "^5.9.3"
|
|
34
37
|
},
|
|
35
38
|
"dependencies": {
|
|
@@ -37,6 +40,8 @@
|
|
|
37
40
|
"commander": "^14.0.3",
|
|
38
41
|
"fs-extra": "^11.3.3",
|
|
39
42
|
"js-yaml": "^4.1.1",
|
|
40
|
-
"kysely": "^0.28.11"
|
|
43
|
+
"kysely": "^0.28.11",
|
|
44
|
+
"simple-git": "^3.30.0",
|
|
45
|
+
"tsx": "^4.21.0"
|
|
41
46
|
}
|
|
42
47
|
}
|
package/skeleton/config.yaml
CHANGED
|
@@ -9,58 +9,40 @@
|
|
|
9
9
|
|
|
10
10
|
### 2. 前提条件
|
|
11
11
|
- ブランチ名: `issues/issue-<issue.id>`
|
|
12
|
-
- 作業パス: `
|
|
12
|
+
- 作業パス: `worktree`
|
|
13
13
|
|
|
14
|
-
### 3.
|
|
15
|
-
Issueが存在する場合、以下の手順で作業ブランチを作成します。
|
|
16
|
-
- Git Worktreeを作成: `git worktree add <作業パス> -b <ブランチ名> || git worktree add <作業パス> <ブランチ名>`
|
|
17
|
-
- **作業ディレクトリへ移動: `cd <作業パス>`**
|
|
18
|
-
|
|
19
|
-
### 4. 実装
|
|
14
|
+
### 3. 実装
|
|
20
15
|
Issueのタイトルや仕様を確認し、実装を行います。
|
|
21
16
|
- **実装前に既存の関連コードを読み、プロジェクトのコーディングスタイルを確認してください。**
|
|
17
|
+
- ファイルの更新は作業パス以外行わないこと。
|
|
22
18
|
- 変更は最小限に留めること。
|
|
23
19
|
- 関連のないコードをリファクタリングしないこと。
|
|
24
20
|
|
|
25
|
-
###
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
Issue Tool:
|
|
49
|
-
- ready_for_review
|
|
50
|
-
|
|
51
|
-
Git:
|
|
52
|
-
- worktree
|
|
53
|
-
- add
|
|
54
|
-
- commit
|
|
55
|
-
- diff
|
|
21
|
+
### コミット
|
|
22
|
+
コミットなどの作業はやらないこと。
|
|
23
|
+
|
|
24
|
+
## アウトプット形式
|
|
25
|
+
からなず以下のjson形式で出力してください。
|
|
26
|
+
出力をこのままパースするので、json以外の出力をしないでください。
|
|
27
|
+
「```json」などの修飾もしないでください。
|
|
28
|
+
絶対に以下のJSON以外を出力しないでください。
|
|
29
|
+
|
|
30
|
+
正常時:
|
|
31
|
+
{
|
|
32
|
+
"result": "FINISH",
|
|
33
|
+
"branch": "<ブランチ名>",
|
|
34
|
+
"issue_title": "<issue名>"
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
異常時:
|
|
38
|
+
{
|
|
39
|
+
"result": "ERROR",
|
|
40
|
+
"branch": "<ブランチ名>",
|
|
41
|
+
"issue_title": "<issue名>",
|
|
42
|
+
"reason": "<完了しなかった理由>"
|
|
43
|
+
}
|
|
56
44
|
|
|
57
45
|
## 禁止事項
|
|
58
46
|
- 新しいIssueの作成
|
|
59
47
|
- 他タスクのレビュー
|
|
60
48
|
- 割り当てられたタスク範囲外のファイル編集
|
|
61
|
-
|
|
62
|
-
## 行動ルール
|
|
63
|
-
1. タスクを取得する
|
|
64
|
-
2. 実装する
|
|
65
|
-
3. コミットする
|
|
66
|
-
4. レビュー準備完了としてマークする
|
|
@@ -1,39 +1,21 @@
|
|
|
1
|
-
import {Issue} from "
|
|
2
|
-
import
|
|
1
|
+
import {Issue} from "skiv/skiv/db/schema"
|
|
2
|
+
import AbstractWorker from "../../worker"
|
|
3
3
|
|
|
4
|
-
export default class
|
|
4
|
+
export default class Custom extends AbstractWorker {
|
|
5
5
|
|
|
6
6
|
public async before(): Promise<boolean> {
|
|
7
|
-
|
|
7
|
+
this.logger.debug('before()')
|
|
8
|
+
const assignedIssue = await this.issueService.getNextIssue('open', 'in_progress', this.NAME)
|
|
8
9
|
if (assignedIssue) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
Title: ${assignedIssue.title}
|
|
12
|
-
Description: ${assignedIssue.description}
|
|
13
|
-
`)
|
|
14
|
-
|
|
15
|
-
this.createPrompt(assignedIssue)
|
|
16
|
-
return true
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const assign = await this.issueService.assignNextIssue(this.NAME)
|
|
20
|
-
if (assign) {
|
|
21
|
-
|
|
22
|
-
console.log(`[NEW ISSUE]
|
|
23
|
-
Title: ${assign.title}
|
|
24
|
-
Description: ${assign.description}
|
|
25
|
-
`)
|
|
26
|
-
|
|
27
|
-
this.createPrompt(assign)
|
|
10
|
+
this.logger.info(`found issue: #${assignedIssue.id} ${assignedIssue.title}`)
|
|
11
|
+
await this.setup(assignedIssue)
|
|
28
12
|
return true
|
|
29
13
|
}
|
|
30
14
|
|
|
31
|
-
console.log('no issue')
|
|
32
|
-
|
|
33
15
|
return false
|
|
34
16
|
}
|
|
35
17
|
|
|
36
|
-
|
|
18
|
+
protected createPrompt(issue: Issue): void {
|
|
37
19
|
|
|
38
20
|
const comments = issue.comments?.map(comment => {
|
|
39
21
|
return `- id: ${comment.id}
|
|
@@ -59,4 +41,39 @@ ${comments}
|
|
|
59
41
|
|
|
60
42
|
このあとはCLAUDE.mdに沿って処理をしてください。`
|
|
61
43
|
}
|
|
44
|
+
|
|
45
|
+
public async after(response: string): Promise<void> {
|
|
46
|
+
this.logger.debug('after()')
|
|
47
|
+
|
|
48
|
+
if (!this.ISSUE_ID) {
|
|
49
|
+
throw new Error('ISSUE_ID is not set')
|
|
50
|
+
}
|
|
51
|
+
const res = this.parseResponse<{
|
|
52
|
+
result: "FINISH" | "ERROR",
|
|
53
|
+
branch: string,
|
|
54
|
+
issue_title: string,
|
|
55
|
+
reason?: string
|
|
56
|
+
}>(response)
|
|
57
|
+
|
|
58
|
+
if (res.result === "FINISH") {
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
await this.git
|
|
62
|
+
.add('.')
|
|
63
|
+
.commit(`feature: issue #${this.ISSUE_ID} ${res.issue_title}`)
|
|
64
|
+
await this.issueService.updateStatus(this.ISSUE_ID, 'ready_for_review')
|
|
65
|
+
} catch (e) {
|
|
66
|
+
this.logger.error(e as string)
|
|
67
|
+
process.exit(1)
|
|
68
|
+
} finally {
|
|
69
|
+
await this.cleanupWorktree()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
} else {
|
|
73
|
+
this.logger.error(res)
|
|
74
|
+
await this.issueService.updateStatus(this.ISSUE_ID, 'error')
|
|
75
|
+
await this.cleanupWorktree()
|
|
76
|
+
process.exit(1)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
62
79
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# ROLE: Project Manager
|
|
2
|
+
|
|
3
|
+
あなたは指定されたブランチをmainブランチにマージをします。
|
|
4
|
+
適宜、仕様書(spec.md)を参照します。
|
|
5
|
+
|
|
6
|
+
## ワークフロー
|
|
7
|
+
|
|
8
|
+
### 1. マージする Issue の取得
|
|
9
|
+
プロンプトで渡された Issue を参照してください。
|
|
10
|
+
|
|
11
|
+
### 2. 前提条件
|
|
12
|
+
- ブランチ名: `issues/issue-<issue.id>`
|
|
13
|
+
|
|
14
|
+
### 3. マージ
|
|
15
|
+
該当のブランチをmainへマージします。
|
|
16
|
+
コンフリクトした場合は適宜修正をしてコンフリクトを解消してください。
|
|
17
|
+
修正の判断がつかない場合は無理に解消しようとしないでください。
|
|
18
|
+
|
|
19
|
+
## アウトプット形式
|
|
20
|
+
からなず以下のjson形式で出力してください。
|
|
21
|
+
出力をこのままパースするので、json以外の出力をしないでください。
|
|
22
|
+
「```json」などの修飾もしないでください。
|
|
23
|
+
絶対に以下のJSON以外を出力しないでください。
|
|
24
|
+
|
|
25
|
+
マージOK時:
|
|
26
|
+
{
|
|
27
|
+
"result": "MERGED",
|
|
28
|
+
"branch": "<ブランチ名>",
|
|
29
|
+
"issue_title": "<issue名>",
|
|
30
|
+
"reason": "<何かコメントがあれば>"
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
コンフリクトが解消できない時:
|
|
34
|
+
{
|
|
35
|
+
"result": "CONFLICT",
|
|
36
|
+
"branch": "<ブランチ名>",
|
|
37
|
+
"issue_title": "<issue名>",
|
|
38
|
+
"reason": "<コンフリクトが解消できなかった理由>"
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
異常時:
|
|
42
|
+
{
|
|
43
|
+
"result": "ERROR",
|
|
44
|
+
"branch": "<ブランチ名>",
|
|
45
|
+
"issue_title": "<issue名>",
|
|
46
|
+
"reason": "<完了しなかった理由>"
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
### 実施可能なこと
|
|
50
|
+
- 差分の確認
|
|
51
|
+
- コンフリクトの解消
|
|
52
|
+
- gitの操作
|
|
53
|
+
|
|
54
|
+
## 禁止事項
|
|
55
|
+
- Issueの作成
|
|
56
|
+
- Issueのアサイン
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import {Issue} from "skiv/skiv/db/schema"
|
|
2
|
+
import AbstractWorker from "../../worker"
|
|
3
|
+
|
|
4
|
+
export default class CustomMember extends AbstractWorker {
|
|
5
|
+
|
|
6
|
+
public async before(): Promise<boolean> {
|
|
7
|
+
this.logger.debug('before()')
|
|
8
|
+
const issue = await this.issueService.getNextIssue('request_for_merge', 'in_merge_process', this.NAME)
|
|
9
|
+
if (issue) {
|
|
10
|
+
this.logger.info(`found issue: #${issue.id} ${issue.title}`)
|
|
11
|
+
await this.setup(issue)
|
|
12
|
+
return true
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return false
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
protected createPrompt(issue: Issue) {
|
|
19
|
+
|
|
20
|
+
const comments = issue.comments?.map(comment => {
|
|
21
|
+
return `- id: ${comment.id}
|
|
22
|
+
by: ${comment.by}
|
|
23
|
+
message: ${comment.message}
|
|
24
|
+
`
|
|
25
|
+
}).join("\n") || ''
|
|
26
|
+
|
|
27
|
+
this.PROMPT = `あなたの名前は \`${this.NAME}\` です。
|
|
28
|
+
あなたがレビューするタスクは以下の通りです。
|
|
29
|
+
|
|
30
|
+
id:
|
|
31
|
+
${issue.id}
|
|
32
|
+
|
|
33
|
+
タスク名:
|
|
34
|
+
${issue.title}
|
|
35
|
+
|
|
36
|
+
概要:
|
|
37
|
+
${issue.description}
|
|
38
|
+
|
|
39
|
+
コメント:
|
|
40
|
+
${comments}
|
|
41
|
+
|
|
42
|
+
このあとはCLAUDE.mdに沿って処理をしてください。`
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
public async after(response: string): Promise<void> {
|
|
46
|
+
this.logger.debug('after()')
|
|
47
|
+
|
|
48
|
+
if (!this.ISSUE_ID) {
|
|
49
|
+
throw new Error('ISSUE_ID is not set')
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const res = this.parseResponse<{
|
|
53
|
+
result: "MERGED" | "ERROR",
|
|
54
|
+
branch: string,
|
|
55
|
+
issue_title: string,
|
|
56
|
+
reason?: string
|
|
57
|
+
}>(response)
|
|
58
|
+
|
|
59
|
+
if (res.result === "MERGED") {
|
|
60
|
+
|
|
61
|
+
await this.issueService.updateStatus(this.ISSUE_ID, 'done')
|
|
62
|
+
if (res.reason) {
|
|
63
|
+
await this.issueService.comment(this.ISSUE_ID, this.NAME, res.reason)
|
|
64
|
+
}
|
|
65
|
+
} else {
|
|
66
|
+
this.logger.error(res)
|
|
67
|
+
await this.issueService.updateStatus(this.ISSUE_ID, 'error')
|
|
68
|
+
await this.issueService.comment(this.ISSUE_ID, this.NAME, res.reason || "(no reason)")
|
|
69
|
+
await this.cleanupWorktree()
|
|
70
|
+
process.exit(1)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
await this.cleanupWorktree()
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -9,50 +9,50 @@
|
|
|
9
9
|
|
|
10
10
|
### 2. 前提条件
|
|
11
11
|
- ブランチ名: `issues/issue-<issue.id>`
|
|
12
|
-
- 作業パス: `
|
|
12
|
+
- 作業パス: `worktree`
|
|
13
13
|
|
|
14
|
-
### 3.
|
|
15
|
-
Issue が存在する場合、以下の手順で作業ブランチを作成します。
|
|
16
|
-
- Git Worktree を作成: `git worktree add <作業パス> -b <ブランチ名> || git worktree add <作業パス> <ブランチ名>`
|
|
17
|
-
- **作業ディレクトリへ移動: `cd <作業パス>`**
|
|
18
|
-
|
|
19
|
-
### 4. レビュー
|
|
14
|
+
### 3. レビュー
|
|
20
15
|
Issue のタイトルや仕様を確認し、以下の観点から実装が適切に行われているか確認します。
|
|
21
16
|
- コーディングスタイルに沿っているか
|
|
22
17
|
- テストは充実しているか
|
|
23
18
|
- 変更は最小限に留まっているか
|
|
24
19
|
- Issue に関連のない変更をしていないか
|
|
25
20
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
21
|
+
## アウトプット形式
|
|
22
|
+
からなず以下のjson形式で出力してください。
|
|
23
|
+
出力をこのままパースするので、json以外の出力をしないでください。
|
|
24
|
+
「```json」などの修飾もしないでください。
|
|
25
|
+
絶対に以下のJSON以外を出力しないでください。
|
|
26
|
+
|
|
27
|
+
レビューOK時:
|
|
28
|
+
{
|
|
29
|
+
"result": "APPROVED",
|
|
30
|
+
"branch": "<ブランチ名>",
|
|
31
|
+
"issue_title": "<issue名>",
|
|
32
|
+
"reason": "<何かコメントがあれば>"
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
レビューNG時:
|
|
36
|
+
{
|
|
37
|
+
"result": "REJECT",
|
|
38
|
+
"branch": "<ブランチ名>",
|
|
39
|
+
"issue_title": "<issue名>",
|
|
40
|
+
"reason": "<却下の理由/修正点>"
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
異常時:
|
|
44
|
+
{
|
|
45
|
+
"result": "ERROR",
|
|
46
|
+
"branch": "<ブランチ名>",
|
|
47
|
+
"issue_title": "<issue名>",
|
|
48
|
+
"reason": "<完了しなかった理由>"
|
|
49
|
+
}
|
|
46
50
|
|
|
47
51
|
### 実施可能なこと
|
|
48
52
|
- 差分の確認
|
|
49
53
|
- レビューコメントの追加
|
|
50
54
|
- 完了としてマーク
|
|
51
55
|
|
|
52
|
-
### 例
|
|
53
|
-
npx skiv issue comment 12 Reviewer "Refactor this function"
|
|
54
|
-
npx skiv issue done 12
|
|
55
|
-
|
|
56
56
|
## 禁止事項
|
|
57
57
|
- 実装コードの作成
|
|
58
58
|
- Issueの作成
|
|
@@ -1,31 +1,21 @@
|
|
|
1
|
-
import {Issue} from "
|
|
2
|
-
import
|
|
1
|
+
import {Issue} from "skiv/skiv/db/schema"
|
|
2
|
+
import AbstractWorker from "../../worker"
|
|
3
3
|
|
|
4
|
-
export default class CustomMember extends
|
|
4
|
+
export default class CustomMember extends AbstractWorker {
|
|
5
5
|
|
|
6
6
|
public async before(): Promise<boolean> {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if (
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
this.logger.debug('before()')
|
|
8
|
+
const readyForReviewIssue = await this.issueService.getNextIssue('ready_for_review', 'reviewing', this.NAME)
|
|
9
|
+
if (readyForReviewIssue) {
|
|
10
|
+
this.logger.info(`found issue: #${readyForReviewIssue.id} ${readyForReviewIssue.title}`)
|
|
11
|
+
await this.setup(readyForReviewIssue)
|
|
12
|
+
return true
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
// console.log('issue is not ready for review')
|
|
16
|
-
// return false
|
|
17
|
-
// }
|
|
18
|
-
|
|
19
|
-
console.log(`[NEW ISSUE]
|
|
20
|
-
Title: ${readyForReviewIssue.title}
|
|
21
|
-
Description: ${readyForReviewIssue.description}
|
|
22
|
-
`)
|
|
23
|
-
|
|
24
|
-
this.createPrompt(readyForReviewIssue)
|
|
25
|
-
return true
|
|
15
|
+
return false
|
|
26
16
|
}
|
|
27
17
|
|
|
28
|
-
|
|
18
|
+
protected createPrompt(issue: Issue) {
|
|
29
19
|
|
|
30
20
|
const comments = issue.comments?.map(comment => {
|
|
31
21
|
return `- id: ${comment.id}
|
|
@@ -51,4 +41,42 @@ ${comments}
|
|
|
51
41
|
|
|
52
42
|
このあとはCLAUDE.mdに沿って処理をしてください。`
|
|
53
43
|
}
|
|
44
|
+
|
|
45
|
+
public async after(response: string): Promise<void> {
|
|
46
|
+
this.logger.debug('after()')
|
|
47
|
+
|
|
48
|
+
if (!this.ISSUE_ID) {
|
|
49
|
+
throw new Error('ISSUE_ID is not set')
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const res = this.parseResponse<{
|
|
53
|
+
result: "APPROVED" | "REJECT" | "ERROR",
|
|
54
|
+
branch: string,
|
|
55
|
+
issue_title: string,
|
|
56
|
+
reason?: string
|
|
57
|
+
}>(response)
|
|
58
|
+
|
|
59
|
+
if (res.result === "APPROVED") {
|
|
60
|
+
|
|
61
|
+
await this.issueService.updateStatus(this.ISSUE_ID, 'request_for_merge')
|
|
62
|
+
if (res.reason) {
|
|
63
|
+
await this.issueService.comment(this.ISSUE_ID, this.NAME, res.reason)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
} else if (res.result === "REJECT") {
|
|
67
|
+
|
|
68
|
+
await this.issueService.updateStatus(this.ISSUE_ID, 'open')
|
|
69
|
+
await this.issueService.updateAssignee(this.ISSUE_ID, null)
|
|
70
|
+
await this.issueService.comment(this.ISSUE_ID, this.NAME, res.reason || "(no reason)")
|
|
71
|
+
|
|
72
|
+
} else {
|
|
73
|
+
this.logger.error(res)
|
|
74
|
+
await this.issueService.updateStatus(this.ISSUE_ID, 'error')
|
|
75
|
+
await this.issueService.comment(this.ISSUE_ID, this.NAME, res.reason || "(no reason)")
|
|
76
|
+
await this.cleanupWorktree()
|
|
77
|
+
process.exit(1)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
await this.cleanupWorktree()
|
|
81
|
+
}
|
|
54
82
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# ROLE: SE (System Engineer Agent)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
あなたの責任範囲は計画立案とタスク分解のみです
|
|
4
|
+
ただし仕様書(spec.md)の編集だけは行えます。
|
|
4
5
|
|
|
5
6
|
## 利用可能なツール
|
|
6
7
|
|
|
@@ -15,7 +16,7 @@ npx skiv issue
|
|
|
15
16
|
### 例
|
|
16
17
|
|
|
17
18
|
Issueの作成:
|
|
18
|
-
npx skiv issue create "
|
|
19
|
+
npx skiv issue create "fizzbuzz.tsの作成" high "1から順に数を数え上げ、3の倍数で「Fizz」、5の倍数で「Buzz」、15の倍数(3と5の公倍数)で「FizzBuzz」と表示する関数を作成する"
|
|
19
20
|
|
|
20
21
|
優先度は次のいずれかである必要があります:
|
|
21
22
|
- low
|
|
@@ -25,8 +26,7 @@ npx skiv issue create "Implement auth API" high design.md#auth
|
|
|
25
26
|
他の値が必要な場合は、最も近いものを選択してください。
|
|
26
27
|
新しい優先度レベルを作成してはいけません。
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
npx skiv issue comment 12 SE "Use JWT auth"
|
|
29
|
+
説明(作業指示)を必ず記述してください。
|
|
30
30
|
|
|
31
31
|
## 禁止事項
|
|
32
32
|
- ソースコードの編集
|
|
@@ -36,6 +36,12 @@ npx skiv issue comment 12 SE "Use JWT auth"
|
|
|
36
36
|
|
|
37
37
|
## 行動ルール
|
|
38
38
|
- 要件を小さなタスクに分解すること
|
|
39
|
-
-
|
|
39
|
+
- タスクを分割する際は、以下の制約を厳守してください。
|
|
40
|
+
- 粒度:1つのエンドポイント、1つのUIパーツ、1つのロジック関数
|
|
41
|
+
- 禁止:『〜の構築』『〜の実装』といった大きな単位
|
|
42
|
+
- 推奨:『xxxをyyyに追加してzzzできるようにする』という具体的な記述
|
|
43
|
+
- 1つのタスクは、シニアエンジニアが 30分以内に実装・テスト完了できる規模 であること
|
|
44
|
+
- 実装とテストは同一のタスクにすること
|
|
40
45
|
- 各タスクは単独で実装可能でなければならない
|
|
41
46
|
- 常に仕様書の該当セクションを参照すること
|
|
47
|
+
- 必要に応じて仕様書を修正すること
|
package/skeleton/spec.md
ADDED
|
File without changes
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {Issue} from "skiv/skiv/db/schema";
|
|
2
|
+
import Worker from "skiv/skiv/Worker";
|
|
3
|
+
|
|
4
|
+
export default abstract class AbstractWorker extends Worker {
|
|
5
|
+
|
|
6
|
+
protected ISSUE_ID: number | null = null
|
|
7
|
+
|
|
8
|
+
protected async setup(issue: Issue) {
|
|
9
|
+
this.ISSUE_ID = issue.id
|
|
10
|
+
await this.cleanupWorktree()
|
|
11
|
+
await this.setupWorktree(`issues/issue-${issue.id}`)
|
|
12
|
+
this.createPrompt(issue)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
protected abstract createPrompt(issue: Issue): void
|
|
16
|
+
|
|
17
|
+
protected parseResponse<T>(response: string): T {
|
|
18
|
+
const matches = response.match(/\{[\s\S]*\}/)
|
|
19
|
+
const jsonStr = matches ? matches[0] : response
|
|
20
|
+
|
|
21
|
+
const parsed = JSON.parse(jsonStr) as T
|
|
22
|
+
|
|
23
|
+
this.logger.debug('----------------------')
|
|
24
|
+
this.logger.debug(parsed as unknown as object)
|
|
25
|
+
this.logger.debug('----------------------')
|
|
26
|
+
|
|
27
|
+
return parsed
|
|
28
|
+
}
|
|
29
|
+
}
|
package/bin/skiv.js
DELETED