hamster-wheel-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/.github/ISSUE_TEMPLATE/bug_report.yml +107 -0
- package/.github/ISSUE_TEMPLATE/config.yml +15 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +56 -0
- package/.github/workflows/ci-pr.yml +50 -0
- package/.github/workflows/publish.yml +121 -0
- package/.github/workflows/sync-master-to-dev.yml +100 -0
- package/AGENTS.md +20 -0
- package/CHANGELOG.md +12 -0
- package/LICENSE +21 -0
- package/README.md +90 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.js +2678 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +80 -0
- package/dist/index.js +2682 -0
- package/dist/index.js.map +1 -0
- package/docs/ai-workflow.md +58 -0
- package/package.json +44 -0
- package/src/ai.ts +173 -0
- package/src/cli.ts +189 -0
- package/src/config.ts +134 -0
- package/src/deps.ts +210 -0
- package/src/gh.ts +228 -0
- package/src/git.ts +285 -0
- package/src/global-config.ts +296 -0
- package/src/index.ts +3 -0
- package/src/logger.ts +122 -0
- package/src/logs-viewer.ts +420 -0
- package/src/logs.ts +132 -0
- package/src/loop.ts +422 -0
- package/src/monitor.ts +291 -0
- package/src/runtime-tracker.ts +65 -0
- package/src/summary.ts +255 -0
- package/src/types.ts +176 -0
- package/src/utils.ts +179 -0
- package/src/webhook.ts +107 -0
- package/tests/deps.test.ts +72 -0
- package/tests/e2e/cli.e2e.test.ts +77 -0
- package/tests/e2e/gh-pr-create.e2e.test.ts +55 -0
- package/tests/e2e/gh-run-list.e2e.test.ts +47 -0
- package/tests/gh-pr-create.test.ts +55 -0
- package/tests/gh-run-list.test.ts +35 -0
- package/tests/global-config.test.ts +52 -0
- package/tests/logger-file.test.ts +56 -0
- package/tests/logger.test.ts +72 -0
- package/tests/logs-viewer.test.ts +57 -0
- package/tests/logs.test.ts +33 -0
- package/tests/prompt.test.ts +20 -0
- package/tests/run-command-stream.test.ts +60 -0
- package/tests/summary.test.ts +58 -0
- package/tests/token-usage.test.ts +33 -0
- package/tests/utils.test.ts +8 -0
- package/tests/webhook.test.ts +89 -0
- package/tsconfig.json +18 -0
- package/tsup.config.ts +18 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
name: "🐞 Bug 报告 (Bug Report)"
|
|
2
|
+
description: 提交一个 Bug 报告来帮助我们改进(Commit a bug report to help us improve)
|
|
3
|
+
title: "[Bug]: "
|
|
4
|
+
labels: ["bug"]
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: |
|
|
9
|
+
感谢你花时间填写这份报告!请尽可能详细地描述问题。
|
|
10
|
+
(Thanks for taking the time to fill out this report! Please describe the issue in as much detail as possible.)
|
|
11
|
+
- type: textarea
|
|
12
|
+
id: description
|
|
13
|
+
attributes:
|
|
14
|
+
label: 描述一下 (Describe the bug)
|
|
15
|
+
description: 请清晰简洁地描述这个Bug。 (A clear and concise description of what the bug is.)
|
|
16
|
+
placeholder: "我尝试做... 结果... 发生了...(I tried to do... and the result... something went wrong.)"
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
- type: textarea
|
|
20
|
+
id: reproduction
|
|
21
|
+
attributes:
|
|
22
|
+
label: 如何复现 (To Reproduce)
|
|
23
|
+
description: 请提供详细的复现步骤。 (Steps to reproduce the behavior.)
|
|
24
|
+
placeholder: |
|
|
25
|
+
1. 访问页面 '...'(Go to '...')
|
|
26
|
+
2. 点击按钮 '....'(Click on '....')
|
|
27
|
+
3. 滚动到 '....'(Scroll down to '....')
|
|
28
|
+
4. 看到错误 '...'(Error appears '...')
|
|
29
|
+
validations:
|
|
30
|
+
required: true
|
|
31
|
+
- type: textarea
|
|
32
|
+
id: expected-behavior
|
|
33
|
+
attributes:
|
|
34
|
+
label: 预期表现 (Expected behavior)
|
|
35
|
+
description: 请清晰简洁地描述你实际预期中的表现。 (A clear and concise description of what you expected to happen.)
|
|
36
|
+
placeholder: "我预期... 应该发生。(I expected... to happen.)"
|
|
37
|
+
validations:
|
|
38
|
+
required: true
|
|
39
|
+
- type: textarea
|
|
40
|
+
id: screenshots
|
|
41
|
+
attributes:
|
|
42
|
+
label: 截图 (Screenshots)
|
|
43
|
+
description: 如果可以的话,贴几张截图最好啦。你可以直接拖拽或粘贴图片到这里。(If applicable, add screenshots. You can drag & drop or paste images here.)
|
|
44
|
+
validations:
|
|
45
|
+
required: false
|
|
46
|
+
- type: markdown
|
|
47
|
+
attributes:
|
|
48
|
+
value: "### 💻 电脑环境 (Desktop Environment)"
|
|
49
|
+
- type: input
|
|
50
|
+
id: os-desktop
|
|
51
|
+
attributes:
|
|
52
|
+
label: 操作系统 (OS)
|
|
53
|
+
placeholder: "e.g. Windows 11 / macOS 13.0"
|
|
54
|
+
validations:
|
|
55
|
+
required: false
|
|
56
|
+
- type: input
|
|
57
|
+
id: browser-desktop
|
|
58
|
+
attributes:
|
|
59
|
+
label: 浏览器名称 (Browser)
|
|
60
|
+
placeholder: "e.g. Chrome, Safari, Edge"
|
|
61
|
+
validations:
|
|
62
|
+
required: false
|
|
63
|
+
- type: input
|
|
64
|
+
id: browser-version-desktop
|
|
65
|
+
attributes:
|
|
66
|
+
label: 浏览器版本 (Version)
|
|
67
|
+
placeholder: "e.g. 108.0.5359.125"
|
|
68
|
+
validations:
|
|
69
|
+
required: false
|
|
70
|
+
- type: markdown
|
|
71
|
+
attributes:
|
|
72
|
+
value: "### 📱 手机环境 (Smartphone Environment)"
|
|
73
|
+
- type: input
|
|
74
|
+
id: device-mobile
|
|
75
|
+
attributes:
|
|
76
|
+
label: 设备名称 (Device)
|
|
77
|
+
placeholder: "e.g. iPhone 14 Pro / Google Pixel 7"
|
|
78
|
+
validations:
|
|
79
|
+
required: false
|
|
80
|
+
- type: input
|
|
81
|
+
id: os-mobile
|
|
82
|
+
attributes:
|
|
83
|
+
label: 系统名称以及系统版本 (OS)
|
|
84
|
+
placeholder: "e.g. iOS 16.2 / Android 13"
|
|
85
|
+
validations:
|
|
86
|
+
required: false
|
|
87
|
+
- type: input
|
|
88
|
+
id: browser-mobile
|
|
89
|
+
attributes:
|
|
90
|
+
label: 浏览器名称 (Browser)
|
|
91
|
+
placeholder: "e.g. Safari, Chrome, Stock Browser"
|
|
92
|
+
validations:
|
|
93
|
+
required: false
|
|
94
|
+
- type: input
|
|
95
|
+
id: browser-version-mobile
|
|
96
|
+
attributes:
|
|
97
|
+
label: 浏览器版本 (Version)
|
|
98
|
+
placeholder: "e.g. 22"
|
|
99
|
+
validations:
|
|
100
|
+
required: false
|
|
101
|
+
- type: textarea
|
|
102
|
+
id: additional-context
|
|
103
|
+
attributes:
|
|
104
|
+
label: 其他附加内容 (Additional context)
|
|
105
|
+
description: 如果有其他附加信息,请在这里描述。(Add any other context about the problem here.)
|
|
106
|
+
validations:
|
|
107
|
+
required: false
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# 默认设置为 false,强制用户从模板中选择,而不是创建空白 issue
|
|
2
|
+
# Set to false to force users to select from templates, rather than creating blank issues
|
|
3
|
+
blank_issues_enabled: false
|
|
4
|
+
|
|
5
|
+
# (可选)添加外部链接,比如文档或讨论区
|
|
6
|
+
# (Optional) Add external links, e.g., to documentation or discussion forums
|
|
7
|
+
contact_links:
|
|
8
|
+
- name: ❓ 提问或讨论 (Question or Discussion)
|
|
9
|
+
# 替换成你的仓库讨论区链接 (Replace with your repo's discussions link)
|
|
10
|
+
url: https://github.com/orgs/SystemUI-js/discussions
|
|
11
|
+
about: "提问或发起讨论,请使用 GitHub Discussions (Please use GitHub Discussions for questions or discussions.)"
|
|
12
|
+
- name: 📚 查看文档 (Read the Documentation)
|
|
13
|
+
# 替换成你的文档链接 (Replace with your documentation link)
|
|
14
|
+
url: https://github.com/SystemUI-js/multi-drag
|
|
15
|
+
about: "在提 Bug 之前,请先查阅我们的文档 (Please check our documentation before submitting a bug.)"
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: "🌟 新功能请求 (Feature Request)"
|
|
2
|
+
description: 为这个项目提出一个新功能的建议(Commit a feature request to help us improve)
|
|
3
|
+
title: "[Feature]: "
|
|
4
|
+
labels: ["enhancement"]
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: |
|
|
9
|
+
感谢你花时间提出建议来帮助我们改进!
|
|
10
|
+
(Thanks for taking the time to suggest an enhancement!)
|
|
11
|
+
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: problem
|
|
14
|
+
attributes:
|
|
15
|
+
label: 你的功能请求是否与某个问题有关? (Is your feature request related to a problem?)
|
|
16
|
+
description: 请描述一下你遇到的问题或痛点。 (Please describe the problem or pain point.)
|
|
17
|
+
placeholder: "我总是...的时候感到很沮丧,因为..."
|
|
18
|
+
validations:
|
|
19
|
+
required: true
|
|
20
|
+
|
|
21
|
+
- type: textarea
|
|
22
|
+
id: solution
|
|
23
|
+
attributes:
|
|
24
|
+
label: 你期望的解决方案是什么? (Describe the solution you'd like)
|
|
25
|
+
description: 请清晰简洁地描述你希望实现的功能。 (A clear and concise description of what you want to happen.)
|
|
26
|
+
placeholder: "我希望...可以... 这样我就能...(I hope... can... so that I can...)"
|
|
27
|
+
validations:
|
|
28
|
+
required: true
|
|
29
|
+
|
|
30
|
+
- type: textarea
|
|
31
|
+
id: alternatives
|
|
32
|
+
attributes:
|
|
33
|
+
label: 你是否考虑过其他方案? (Describe alternatives you've considered)
|
|
34
|
+
description: 描述一下你考虑过的任何替代方案或功能。 (A clear and concise description of any alternative solutions or features you've considered.)
|
|
35
|
+
validations:
|
|
36
|
+
required: false
|
|
37
|
+
|
|
38
|
+
- type: textarea
|
|
39
|
+
id: screenshots
|
|
40
|
+
attributes:
|
|
41
|
+
label: 截图或模型图 (Screenshots or Mockups)
|
|
42
|
+
description: |
|
|
43
|
+
如果可以的话,添加截图、流程图或简单的模型图来帮助解释你的想法。
|
|
44
|
+
(If applicable, add screenshots, flowcharts, or mockups to help explain your idea.)
|
|
45
|
+
validations:
|
|
46
|
+
required: false
|
|
47
|
+
|
|
48
|
+
- type: textarea
|
|
49
|
+
id: additional-context
|
|
50
|
+
attributes:
|
|
51
|
+
label: 其他附加内容 (Additional context)
|
|
52
|
+
description: |
|
|
53
|
+
关于这个功能请求,还有其他要补充的吗?
|
|
54
|
+
(Add any other context about the feature request here. e.g. Why is this important? Who would benefit?)
|
|
55
|
+
validations:
|
|
56
|
+
required: false
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
name: PR CI (tests & build)
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
- dev
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: pr-${{ github.event.pull_request.head.sha }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
pr-checks:
|
|
18
|
+
name: Test and Build
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- name: Checkout
|
|
22
|
+
uses: actions/checkout@v4
|
|
23
|
+
|
|
24
|
+
- name: Setup Node.js
|
|
25
|
+
uses: actions/setup-node@v4
|
|
26
|
+
with:
|
|
27
|
+
node-version: 20
|
|
28
|
+
cache: yarn
|
|
29
|
+
|
|
30
|
+
- name: Install dependencies
|
|
31
|
+
run: |
|
|
32
|
+
corepack enable
|
|
33
|
+
yarn --version
|
|
34
|
+
yarn install --frozen-lockfile
|
|
35
|
+
|
|
36
|
+
- name: Run lint
|
|
37
|
+
run: |
|
|
38
|
+
yarn lint
|
|
39
|
+
|
|
40
|
+
- name: Run unit tests
|
|
41
|
+
run: |
|
|
42
|
+
yarn test
|
|
43
|
+
|
|
44
|
+
- name: Build (lib + demo + types)
|
|
45
|
+
run: |
|
|
46
|
+
yarn build:all
|
|
47
|
+
|
|
48
|
+
- name: Verify npm pack (dry-run)
|
|
49
|
+
run: |
|
|
50
|
+
npm pack --dry-run
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
name: Publish to npm (main/dev)
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
publish:
|
|
13
|
+
name: Build and Publish
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
# 拉取代码
|
|
17
|
+
- name: Checkout
|
|
18
|
+
uses: actions/checkout@v4
|
|
19
|
+
with:
|
|
20
|
+
fetch-depth: 0
|
|
21
|
+
|
|
22
|
+
# 解析标签类型并设定预期分支与 npm dist-tag
|
|
23
|
+
# 规则:
|
|
24
|
+
# - 正式版:vX.Y.Z -> 仅当该提交在 main 分支上时发布,dist-tag=latest
|
|
25
|
+
# - 预发布:vX.Y.Z-dev.N -> 仅当该提交在 dev 分支上时发布,dist-tag=dev
|
|
26
|
+
- name: Classify tag and prepare env
|
|
27
|
+
run: |
|
|
28
|
+
TAG="${GITHUB_REF#refs/tags/}"
|
|
29
|
+
echo "Detected tag: $TAG"
|
|
30
|
+
if [[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
31
|
+
echo "PUBLISH_TAG=latest" >> "$GITHUB_ENV"
|
|
32
|
+
echo "EXPECTED_BRANCH=master" >> "$GITHUB_ENV"
|
|
33
|
+
echo "SHOULD_PUBLISH=true" >> "$GITHUB_ENV"
|
|
34
|
+
elif [[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-dev\.[0-9]+$ ]]; then
|
|
35
|
+
echo "PUBLISH_TAG=dev" >> "$GITHUB_ENV"
|
|
36
|
+
echo "EXPECTED_BRANCH=dev" >> "$GITHUB_ENV"
|
|
37
|
+
echo "SHOULD_PUBLISH=true" >> "$GITHUB_ENV"
|
|
38
|
+
else
|
|
39
|
+
echo "Tag format not supported for publishing. Skip."
|
|
40
|
+
echo "SHOULD_PUBLISH=false" >> "$GITHUB_ENV"
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# 验证:被打标签的提交是否包含在期望分支中(origin/main 或 origin/dev)
|
|
44
|
+
- name: Verify tag commit is contained in expected branch
|
|
45
|
+
if: env.SHOULD_PUBLISH == 'true'
|
|
46
|
+
run: |
|
|
47
|
+
set -e
|
|
48
|
+
git fetch origin "+refs/heads/*:refs/remotes/origin/*"
|
|
49
|
+
if git branch -r --contains "$GITHUB_SHA" | grep -E "origin/${EXPECTED_BRANCH}" >/dev/null; then
|
|
50
|
+
echo "Commit $GITHUB_SHA is contained in ${EXPECTED_BRANCH}."
|
|
51
|
+
else
|
|
52
|
+
echo "Commit $GITHUB_SHA is NOT contained in ${EXPECTED_BRANCH}. Will skip publishing."
|
|
53
|
+
echo "SHOULD_PUBLISH=false" >> "$GITHUB_ENV"
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
# 安装 Node,并配置 npm registry(用于 npm publish 鉴权)
|
|
57
|
+
- name: Setup Node.js
|
|
58
|
+
uses: actions/setup-node@v4
|
|
59
|
+
if: env.SHOULD_PUBLISH == 'true'
|
|
60
|
+
with:
|
|
61
|
+
node-version: 20
|
|
62
|
+
registry-url: https://registry.npmjs.org
|
|
63
|
+
cache: yarn
|
|
64
|
+
|
|
65
|
+
# 使用 Yarn 安装依赖(项目包含 yarn.lock)
|
|
66
|
+
- name: Install dependencies
|
|
67
|
+
if: env.SHOULD_PUBLISH == 'true'
|
|
68
|
+
run: |
|
|
69
|
+
corepack enable
|
|
70
|
+
yarn --version
|
|
71
|
+
yarn install --frozen-lockfile
|
|
72
|
+
|
|
73
|
+
# 读取 package.json 的 name 与 version,并检查该版本是否已发布
|
|
74
|
+
# 已发布则跳过后续发布步骤,避免重复发布导致失败
|
|
75
|
+
- name: Check if version already published
|
|
76
|
+
id: version
|
|
77
|
+
shell: bash
|
|
78
|
+
if: env.SHOULD_PUBLISH == 'true'
|
|
79
|
+
run: |
|
|
80
|
+
PKG_NAME=$(node -e "console.log(JSON.parse(require('fs').readFileSync('package.json','utf8')).name)")
|
|
81
|
+
VERSION=$(node -e "console.log(JSON.parse(require('fs').readFileSync('package.json','utf8')).version)")
|
|
82
|
+
echo "Package: $PKG_NAME"
|
|
83
|
+
echo "Version: $VERSION"
|
|
84
|
+
if npm view "$PKG_NAME@$VERSION" version > /dev/null 2>&1; then
|
|
85
|
+
echo "should_publish=false" >> "$GITHUB_OUTPUT"
|
|
86
|
+
echo "Version $VERSION already exists on npm, skip publishing."
|
|
87
|
+
else
|
|
88
|
+
echo "should_publish=true" >> "$GITHUB_OUTPUT"
|
|
89
|
+
echo "Version $VERSION not found on npm, will publish."
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
# 可选:预先运行单元测试与构建,提前暴露错误
|
|
93
|
+
# 注意:npm publish 会触发 prepublishOnly(其中也会执行 test & build)
|
|
94
|
+
- name: Run tests and build (optional precheck)
|
|
95
|
+
if: env.SHOULD_PUBLISH == 'true' && steps.version.outputs.should_publish == 'true'
|
|
96
|
+
run: |
|
|
97
|
+
yarn test
|
|
98
|
+
yarn build:all
|
|
99
|
+
|
|
100
|
+
# 发布到 npm。main 使用 latest tag,dev 使用 dev tag。
|
|
101
|
+
# 需要在项目 Secrets 配置 NPM_TOKEN(具有发布权限的 npm 令牌)。
|
|
102
|
+
- name: Publish to npm
|
|
103
|
+
if: env.SHOULD_PUBLISH == 'true' && steps.version.outputs.should_publish == 'true' && github.event_name == 'push'
|
|
104
|
+
env:
|
|
105
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
106
|
+
run: |
|
|
107
|
+
# 使用 npm publish 以触发 prepublishOnly(包含测试与构建),并指定 tag 与访问级别
|
|
108
|
+
npm publish --tag "$PUBLISH_TAG" --access public
|
|
109
|
+
|
|
110
|
+
# 无论是否发布成功,只要是 dev 预发布标签,都确保 dist-tag=dev 指向当前 version
|
|
111
|
+
- name: Ensure dev dist-tag
|
|
112
|
+
if: env.SHOULD_PUBLISH == 'true' && env.PUBLISH_TAG == 'dev' && github.event_name == 'push'
|
|
113
|
+
env:
|
|
114
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
115
|
+
run: |
|
|
116
|
+
PKG_NAME=$(node -e "console.log(JSON.parse(require('fs').readFileSync('package.json','utf8')).name)")
|
|
117
|
+
VERSION=$(node -e "console.log(JSON.parse(require('fs').readFileSync('package.json','utf8')).version)")
|
|
118
|
+
echo "Ensure dist-tag: dev -> $VERSION"
|
|
119
|
+
# 若版本已存在,也可重复设置 tag;若已指向则不变
|
|
120
|
+
npm dist-tag add "$PKG_NAME@$VERSION" dev || true
|
|
121
|
+
npm dist-tag ls "$PKG_NAME"
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
name: Sync master to dev
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- master
|
|
7
|
+
- main
|
|
8
|
+
pull_request:
|
|
9
|
+
branches:
|
|
10
|
+
- master
|
|
11
|
+
- main
|
|
12
|
+
types: [opened, synchronize, reopened]
|
|
13
|
+
|
|
14
|
+
permissions:
|
|
15
|
+
contents: write
|
|
16
|
+
pull-requests: write
|
|
17
|
+
|
|
18
|
+
concurrency:
|
|
19
|
+
group: sync-master-to-dev
|
|
20
|
+
cancel-in-progress: false
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
sync:
|
|
24
|
+
name: Merge master/main into dev
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
steps:
|
|
27
|
+
- name: Checkout repository
|
|
28
|
+
uses: actions/checkout@v4
|
|
29
|
+
with:
|
|
30
|
+
fetch-depth: 0
|
|
31
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
32
|
+
|
|
33
|
+
- name: Configure Git user
|
|
34
|
+
run: |
|
|
35
|
+
git config user.name "github-actions[bot]"
|
|
36
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
37
|
+
|
|
38
|
+
- name: Fetch branches
|
|
39
|
+
run: |
|
|
40
|
+
git remote set-url origin "${{ github.server_url }}/${{ github.repository }}.git"
|
|
41
|
+
git fetch origin --prune
|
|
42
|
+
# Try to fetch both possible default branch names
|
|
43
|
+
git fetch origin master || true
|
|
44
|
+
git fetch origin main || true
|
|
45
|
+
git fetch origin dev || true
|
|
46
|
+
|
|
47
|
+
- name: Detect default branch (master/main)
|
|
48
|
+
id: detect
|
|
49
|
+
shell: bash
|
|
50
|
+
run: |
|
|
51
|
+
if git ls-remote --exit-code --heads origin master >/dev/null 2>&1; then
|
|
52
|
+
echo "name=master" >> "$GITHUB_OUTPUT"
|
|
53
|
+
elif git ls-remote --exit-code --heads origin main >/dev/null 2>&1; then
|
|
54
|
+
echo "name=main" >> "$GITHUB_OUTPUT"
|
|
55
|
+
else
|
|
56
|
+
echo "::error::Neither master nor main branch exists on origin."
|
|
57
|
+
exit 1
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
- name: Checkout dev branch (create if missing)
|
|
61
|
+
shell: bash
|
|
62
|
+
run: |
|
|
63
|
+
# If dev exists on origin, base our local branch on it; else create from the default branch
|
|
64
|
+
if git ls-remote --exit-code --heads origin dev >/dev/null 2>&1; then
|
|
65
|
+
git checkout -B dev origin/dev
|
|
66
|
+
else
|
|
67
|
+
echo "dev branch does not exist on origin, creating it based on ${{ steps.detect.outputs.name }}"
|
|
68
|
+
git checkout -B dev "origin/${{ steps.detect.outputs.name }}"
|
|
69
|
+
git push -u origin dev
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
- name: Merge default branch into dev
|
|
73
|
+
shell: bash
|
|
74
|
+
run: |
|
|
75
|
+
set -e
|
|
76
|
+
BASE_BRANCH="${{ steps.detect.outputs.name }}"
|
|
77
|
+
echo "Merging origin/${BASE_BRANCH} into dev..."
|
|
78
|
+
# Ensure we have the latest base branch state
|
|
79
|
+
git fetch origin "$BASE_BRANCH"
|
|
80
|
+
|
|
81
|
+
# Attempt merge
|
|
82
|
+
if git merge --no-edit "origin/${BASE_BRANCH}"; then
|
|
83
|
+
echo "Merge succeeded."
|
|
84
|
+
else
|
|
85
|
+
echo "::error::Merge conflict when merging ${BASE_BRANCH} into dev. Please resolve conflicts manually."
|
|
86
|
+
# Abort merge to avoid committing conflict markers
|
|
87
|
+
git merge --abort || true
|
|
88
|
+
exit 1
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
- name: Push changes to dev (if any)
|
|
92
|
+
shell: bash
|
|
93
|
+
run: |
|
|
94
|
+
# Only push if there are commits ahead of origin/dev
|
|
95
|
+
if [ -n "$(git log --oneline origin/dev..HEAD)" ]; then
|
|
96
|
+
echo "Pushing updates to origin/dev..."
|
|
97
|
+
git push origin dev
|
|
98
|
+
else
|
|
99
|
+
echo "No updates needed. dev is already up to date with ${{ steps.detect.outputs.name }}"
|
|
100
|
+
fi
|
package/AGENTS.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# 项目介绍
|
|
2
|
+
|
|
3
|
+
wheel-ai 是一个面向本地工程的 AI 驱动迭代开发工具,基于 Node.js + commander,结合外部 AI CLI 串联需求澄清、计划生成、编码、自审、测试与 PR。
|
|
4
|
+
|
|
5
|
+
## 核心能力
|
|
6
|
+
- 通过统一提示驱动外部 AI CLI 执行迭代流程
|
|
7
|
+
- 自动化 git worktree 分支与 gh PR 协作
|
|
8
|
+
- 运行单元测试与 e2e 测试并记录结果
|
|
9
|
+
- 通过 plan/notes 持久化多轮迭代记忆
|
|
10
|
+
|
|
11
|
+
## 关键目录
|
|
12
|
+
- `docs/ai-workflow.md`:AI 工作流基线提示
|
|
13
|
+
- `memory/plan.md` / `memory/notes.md`:计划与迭代记录
|
|
14
|
+
- `src/`:CLI 实现
|
|
15
|
+
- `tests/`:测试用例
|
|
16
|
+
|
|
17
|
+
## 使用约束
|
|
18
|
+
- 包管理优先使用 `yarn`
|
|
19
|
+
- 文档与注释保持中文
|
|
20
|
+
- PR/Actions 相关操作仅使用 `gh` 命令
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
本项目遵循语义化版本,变更日志以时间倒序记录。
|
|
4
|
+
|
|
5
|
+
## [0.1.0] - 2025-12-23
|
|
6
|
+
### Added
|
|
7
|
+
- 基于 commander 的 AI 驱动 CLI,支持通过外部 AI CLI 运行迭代流程。
|
|
8
|
+
- 集成 git worktree 与 `gh`,自动化创建分支、推送与 PR。
|
|
9
|
+
- 支持单元测试与 e2e 测试的统一触发与结果收集。
|
|
10
|
+
- 提供计划与记录持久化(`memory/plan.md`、`memory/notes.md`),便于多轮迭代复用。
|
|
11
|
+
- 支持 webhook 通知、日志查看与本地配置快捷指令,提升可观测性与易用性。
|
|
12
|
+
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Z.X
|
|
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,90 @@
|
|
|
1
|
+
# hamster-wheel-cli
|
|
2
|
+
|
|
3
|
+
基于 Node.js + commander 的持续迭代开发工具,结合外部 AI CLI(运行时指定)驱动完整软件交付流程:需求澄清、计划生成、编码、自审、测试(单元+e2e)、推送与 PR。
|
|
4
|
+
|
|
5
|
+
## 安装与构建
|
|
6
|
+
```bash
|
|
7
|
+
yarn install
|
|
8
|
+
yarn build
|
|
9
|
+
```
|
|
10
|
+
生成的可执行文件位于 `dist/cli.js`,也可通过 `yarn dev` 直接运行 TypeScript 源码。
|
|
11
|
+
|
|
12
|
+
## 快速开始
|
|
13
|
+
```bash
|
|
14
|
+
node dist/cli.js run \
|
|
15
|
+
--task "为现有项目补充自动化 CI" \
|
|
16
|
+
--ai-cli "claude" \
|
|
17
|
+
--ai-args "--model" "claude-3-opus" \
|
|
18
|
+
--worktree \
|
|
19
|
+
--base-branch main \
|
|
20
|
+
--branch wheel-ai/ci-upgrade \
|
|
21
|
+
--run-tests --run-e2e \
|
|
22
|
+
--auto-commit --auto-push \
|
|
23
|
+
--pr --pr-title "chore: 自动化 CI" \
|
|
24
|
+
--stop-signal "<<DONE>>"
|
|
25
|
+
```
|
|
26
|
+
- `--ai-cli`/`--ai-args`:指向系统已有的 AI CLI,提示文本通过 stdin(或 `--ai-prompt-arg`)传入。
|
|
27
|
+
- `--worktree`:在独立分支 worktree 中作业;基线分支通过 `--base-branch` 指定。
|
|
28
|
+
- 使用 `--worktree` 创建的临时工作目录,在确认分支已提交、推送且存在 PR 后会自动清理(仅删除本次创建的 worktree)。
|
|
29
|
+
- `--run-tests`/`--run-e2e`:运行测试命令(默认 `yarn test`、`yarn e2e`)。
|
|
30
|
+
- `--auto-commit`/`--auto-push`:迭代结束后自动提交与推送。
|
|
31
|
+
- `--pr`:使用 `gh pr create` 创建 PR,可配合 `--pr-title`/`--pr-body`/`--draft`/`--reviewer`,未提供标题时会自动生成默认标题。
|
|
32
|
+
- `--skip-install`:任务启动前跳过依赖检查与自动安装。
|
|
33
|
+
- `--log-file`:将日志写入指定文件(相对路径基于当前工作目录)。
|
|
34
|
+
- `-v, --verbose`:输出完整调试日志(包含执行命令、stdout/stderr),便于开发排查。
|
|
35
|
+
- `--webhook`:配置通知回调地址(可重复设置多个 URL)。
|
|
36
|
+
- `--webhook-timeout`:webhook 请求超时(毫秒),默认 8000。
|
|
37
|
+
|
|
38
|
+
## 全局配置快捷指令
|
|
39
|
+
支持在 `~/.wheel-ai/config.toml` 配置一个快捷指令,用于减少重复的命令行参数书写。
|
|
40
|
+
|
|
41
|
+
```toml
|
|
42
|
+
[shortcut]
|
|
43
|
+
name = "daily"
|
|
44
|
+
command = "--task \"补充文档\" --ai-cli \"claude\" --ai-args \"--model\" \"claude-3-opus\" --worktree --run-tests"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
使用时只需要输入快捷指令名称,后续参数会追加到快捷指令命令尾部:
|
|
48
|
+
```bash
|
|
49
|
+
wheel-ai daily --run-e2e
|
|
50
|
+
```
|
|
51
|
+
等价于:
|
|
52
|
+
```bash
|
|
53
|
+
wheel-ai run --task "补充文档" --ai-cli "claude" --ai-args "--model" "claude-3-opus" --worktree --run-tests --run-e2e
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
- `command` 中可选包含 `run`,会在展开时自动去除,避免重复。
|
|
57
|
+
- 仅支持一个 `[shortcut]`,且 `name` 不能包含空白字符。
|
|
58
|
+
- 配置文件不存在或内容不合法会被忽略,不影响正常使用。
|
|
59
|
+
|
|
60
|
+
## 持久化记忆
|
|
61
|
+
- `docs/ai-workflow.md`:AI 执行前的工作流基线,需作为提示前置输入。
|
|
62
|
+
- `memory/plan.md`:分阶段计划(可被 AI 重写保持最新)。
|
|
63
|
+
- `memory/notes.md`:每轮迭代的输出、结论、风险与下一步。
|
|
64
|
+
|
|
65
|
+
## Webhook 通知
|
|
66
|
+
可通过 `--webhook` 配置通知回调地址,系统会在任务开始、第 N 轮开始、任务结束时发送 POST JSON。
|
|
67
|
+
|
|
68
|
+
Payload 示例:
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"event": "task_start",
|
|
72
|
+
"task": "修复依赖安装错误",
|
|
73
|
+
"branch": "feat/webhooks",
|
|
74
|
+
"iteration": 0,
|
|
75
|
+
"stage": "任务开始",
|
|
76
|
+
"timestamp": "2024-01-01T00:00:00.000Z"
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
字段说明:
|
|
80
|
+
- `event`:`task_start` / `iteration_start` / `task_end`
|
|
81
|
+
- `task`:任务描述
|
|
82
|
+
- `branch`:分支名(可能为空)
|
|
83
|
+
- `iteration`:当前轮次(任务开始为 0)
|
|
84
|
+
- `stage`:当前节点描述
|
|
85
|
+
- `timestamp`:ISO 时间戳
|
|
86
|
+
|
|
87
|
+
## 开发约束
|
|
88
|
+
- 使用 yarn 管理依赖,TypeScript 避免 `any`。
|
|
89
|
+
- 与 git/PR 相关的命令仅使用 `gh`;工作分支使用 git worktree。
|
|
90
|
+
- 文档与注释保持中文。
|