gsd-lite 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/.claude-plugin/marketplace.json +21 -0
- package/.claude-plugin/mcp.json +8 -0
- package/.claude-plugin/plugin.json +17 -0
- package/README.md +145 -0
- package/agents/gsd-debugger.md +92 -0
- package/agents/gsd-executor.md +86 -0
- package/agents/gsd-researcher.md +41 -0
- package/agents/gsd-reviewer.md +127 -0
- package/cli.js +37 -0
- package/commands/gsd-prd.md +154 -0
- package/commands/gsd-resume.md +216 -0
- package/commands/gsd-start.md +317 -0
- package/commands/gsd-status.md +114 -0
- package/commands/gsd-stop.md +50 -0
- package/hooks/context-monitor.js +64 -0
- package/hooks/hooks.json +19 -0
- package/install.js +151 -0
- package/package.json +51 -0
- package/references/anti-rationalization-full.md +112 -0
- package/references/git-worktrees.md +77 -0
- package/references/questioning.md +103 -0
- package/references/testing-patterns.md +110 -0
- package/src/schema.js +471 -0
- package/src/server.js +240 -0
- package/src/tools/orchestrator.js +986 -0
- package/src/tools/state.js +926 -0
- package/src/tools/verify.js +89 -0
- package/src/utils.js +73 -0
- package/uninstall.js +85 -0
- package/workflows/debugging.md +187 -0
- package/workflows/deviation-rules.md +128 -0
- package/workflows/research.md +139 -0
- package/workflows/review-cycle.md +153 -0
- package/workflows/tdd-cycle.md +154 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gsd-status
|
|
3
|
+
description: Display project progress overview derived from canonical state fields
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<role>
|
|
7
|
+
你是 GSD-Lite 状态展示器。从 state.json 读取 canonical fields,推导并展示项目进度概览。
|
|
8
|
+
用用户输入的语言进行所有后续输出。
|
|
9
|
+
</role>
|
|
10
|
+
|
|
11
|
+
<process>
|
|
12
|
+
|
|
13
|
+
## STEP 1: 读取状态
|
|
14
|
+
|
|
15
|
+
读取 `.gsd/state.json`:
|
|
16
|
+
- 如果文件不存在 → 告知用户 "未找到 GSD 项目状态,请先运行 /gsd:start 或 /gsd:prd",停止
|
|
17
|
+
- 如果文件损坏 → 告知用户并停止
|
|
18
|
+
|
|
19
|
+
## STEP 2: 展示进度面板
|
|
20
|
+
|
|
21
|
+
从 canonical fields 实时推导所有展示数据 (不使用任何 derived/cached 值):
|
|
22
|
+
|
|
23
|
+
### 项目概览
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
项目: {project}
|
|
27
|
+
工作流模式: {workflow_mode}
|
|
28
|
+
计划版本: {plan_version}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 总体进度
|
|
32
|
+
|
|
33
|
+
- 从 `phases` 数组推导:
|
|
34
|
+
- 总 phase 数: `total_phases`
|
|
35
|
+
- 已完成 phase 数: lifecycle=accepted 的 phase 数量
|
|
36
|
+
- 总 task 数: 所有 phase 的 `tasks` 之和
|
|
37
|
+
- 已完成 task 数: 所有 phase 的 `done` 之和
|
|
38
|
+
- 进度百分比: `已完成 task / 总 task * 100`
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
进度: ████████░░░░ {done}/{total} tasks ({percentage}%)
|
|
42
|
+
阶段: {completed_phases}/{total_phases} phases
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 各阶段状态
|
|
46
|
+
|
|
47
|
+
遍历 `phases` 数组,展示每个 phase:
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
Phase {id}: {name}
|
|
51
|
+
状态: {lifecycle}
|
|
52
|
+
任务: {done}/{tasks}
|
|
53
|
+
审查: {phase_review.status} (如有)
|
|
54
|
+
交接: {phase_handoff 各项状态}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 当前活跃任务
|
|
58
|
+
|
|
59
|
+
- 从 `current_phase` + `current_task` 推导:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
当前任务: {current_task} — {task_name}
|
|
63
|
+
任务状态: {task.lifecycle}
|
|
64
|
+
审查级别: {task.level}
|
|
65
|
+
重试次数: {task.retry_count}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 审查状态
|
|
69
|
+
|
|
70
|
+
- 如果 `current_review` 存在:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
审查中: {current_review.scope} — {current_review.scope_id}
|
|
74
|
+
审查阶段: {current_review.stage}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Blocked 摘要
|
|
78
|
+
|
|
79
|
+
- 遍历当前 phase 的 todo,找出 lifecycle=blocked 的 task:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
Blocked 任务:
|
|
83
|
+
- {task_id}: {blocked_reason}
|
|
84
|
+
解除条件: {unblock_condition}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
如无 blocked task → 不显示此段
|
|
88
|
+
|
|
89
|
+
### 下一步操作建议
|
|
90
|
+
|
|
91
|
+
根据 `workflow_mode` 推导:
|
|
92
|
+
|
|
93
|
+
| workflow_mode | 建议 |
|
|
94
|
+
|---|---|
|
|
95
|
+
| executing_task | "自动执行中,等待完成" |
|
|
96
|
+
| reviewing_task | "L2 审查进行中" |
|
|
97
|
+
| reviewing_phase | "L1 阶段审查进行中" |
|
|
98
|
+
| awaiting_clear | "请执行 /clear 然后 /gsd:resume 继续" |
|
|
99
|
+
| awaiting_user | "有 blocked 问题需要用户决策,运行 /gsd:resume 查看详情" |
|
|
100
|
+
| paused_by_user | "已暂停,运行 /gsd:resume 继续" |
|
|
101
|
+
| reconcile_workspace | "工作区不一致,运行 /gsd:resume 进行 reconcile" |
|
|
102
|
+
| replan_required | "计划需要更新,运行 /gsd:resume 查看详情" |
|
|
103
|
+
| research_refresh_needed | "研究已过期,运行 /gsd:resume 刷新" |
|
|
104
|
+
| completed | "项目已完成" |
|
|
105
|
+
| failed | "项目执行失败,运行 /gsd:resume 查看详情" |
|
|
106
|
+
|
|
107
|
+
</process>
|
|
108
|
+
|
|
109
|
+
<rules>
|
|
110
|
+
- 只读操作: 不修改 state.json,不修改任何文件
|
|
111
|
+
- 只使用 canonical fields: 所有展示数据从 canonical fields 实时推导
|
|
112
|
+
- 不展示 derived/cached 值: 每次执行时重新计算
|
|
113
|
+
- 不展示敏感信息: evidence 中的命令输出仅展示摘要
|
|
114
|
+
</rules>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gsd-stop
|
|
3
|
+
description: Save current state and pause project execution
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<role>
|
|
7
|
+
你是 GSD-Lite 编排器。保存当前项目完整状态并暂停执行。
|
|
8
|
+
用用户输入的语言进行所有后续输出。
|
|
9
|
+
</role>
|
|
10
|
+
|
|
11
|
+
<process>
|
|
12
|
+
|
|
13
|
+
## STEP 1: 保存完整状态
|
|
14
|
+
|
|
15
|
+
读取并更新 `.gsd/state.json`:
|
|
16
|
+
- 如果文件不存在 → 告知用户 "未找到 GSD 项目状态,无需停止",停止
|
|
17
|
+
|
|
18
|
+
确保以下信息已保存到 state.json:
|
|
19
|
+
- `current_phase` / `current_task` — 当前执行位置
|
|
20
|
+
- `current_review` — 当前审查状态 (如有进行中的审查)
|
|
21
|
+
- 当前 phase 的 todo 列表中每个 task 的 lifecycle 状态
|
|
22
|
+
- 所有 blocked task 的 `blocked_reason` 和 `unblock_condition`
|
|
23
|
+
- `git_head` — 更新为当前 `git rev-parse HEAD`
|
|
24
|
+
- `context.last_session` — 更新为当前时间
|
|
25
|
+
|
|
26
|
+
## STEP 2: 写入暂停状态
|
|
27
|
+
|
|
28
|
+
将 `workflow_mode` 设置为 `paused_by_user`
|
|
29
|
+
|
|
30
|
+
使用原子写入: 先写 `.gsd/state.json.tmp`,成功后 rename 为 `.gsd/state.json`
|
|
31
|
+
|
|
32
|
+
## STEP 3: 确认输出
|
|
33
|
+
|
|
34
|
+
输出: "已暂停。运行 /gsd:resume 继续"
|
|
35
|
+
|
|
36
|
+
附带简要进度 (从 canonical fields 推导):
|
|
37
|
+
```
|
|
38
|
+
项目: {project}
|
|
39
|
+
停在: Phase {current_phase} / Task {current_task}
|
|
40
|
+
进度: {done}/{total} tasks
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
</process>
|
|
44
|
+
|
|
45
|
+
<rules>
|
|
46
|
+
- 原子写入: 先写 .tmp 再 rename,避免写入中断导致状态损坏
|
|
47
|
+
- 只更新 canonical fields: 不写入 derived fields
|
|
48
|
+
- 不执行任何代码/测试/构建操作
|
|
49
|
+
- 不清理任何临时文件 (让 /gsd:resume 恢复时处理)
|
|
50
|
+
</rules>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// hooks/context-monitor.js
|
|
2
|
+
// This file exports TWO hook handlers used by Claude Code's hooks system.
|
|
3
|
+
// Can also be invoked via CLI: node context-monitor.js <statusLine|postToolUse>
|
|
4
|
+
|
|
5
|
+
import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* StatusLine hook — called after each tool use.
|
|
10
|
+
* Reads remaining_percentage and writes to .gsd/.context-health
|
|
11
|
+
*/
|
|
12
|
+
export function statusLine(data, basePath) {
|
|
13
|
+
try {
|
|
14
|
+
const remaining = data?.context_window?.remaining_percentage;
|
|
15
|
+
if (remaining == null) return;
|
|
16
|
+
|
|
17
|
+
const gsdDir = join(basePath || process.cwd(), '.gsd');
|
|
18
|
+
mkdirSync(gsdDir, { recursive: true });
|
|
19
|
+
writeFileSync(join(gsdDir, '.context-health'), String(remaining));
|
|
20
|
+
} catch (err) {
|
|
21
|
+
if (process.env.GSD_DEBUG) console.error('[context-monitor:statusLine]', err);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* PostToolUse hook — called after each tool use.
|
|
27
|
+
* Reads .context-health and returns warning/stop text if threshold breached.
|
|
28
|
+
*/
|
|
29
|
+
export function postToolUse(basePath) {
|
|
30
|
+
try {
|
|
31
|
+
const gsdDir = join(basePath || process.cwd(), '.gsd');
|
|
32
|
+
const health = parseInt(readFileSync(join(gsdDir, '.context-health'), 'utf-8'), 10);
|
|
33
|
+
|
|
34
|
+
if (health < 20) {
|
|
35
|
+
return `🛑 CONTEXT EMERGENCY (${health}% remaining): Save state NOW. Set workflow_mode = awaiting_clear. Tell user to /clear then /gsd:resume.`;
|
|
36
|
+
}
|
|
37
|
+
if (health < 40) {
|
|
38
|
+
return `⚠️ CONTEXT LOW (${health}% remaining): Complete current task, save state, set workflow_mode = awaiting_clear. Tell user to /clear then /gsd:resume.`;
|
|
39
|
+
}
|
|
40
|
+
} catch (err) {
|
|
41
|
+
if (process.env.GSD_DEBUG) console.error('[context-monitor:postToolUse]', err);
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// I-6: CLI dispatch — allows hook registration as shell command
|
|
47
|
+
const cmd = process.argv[2];
|
|
48
|
+
if (cmd === 'statusLine') {
|
|
49
|
+
// Read JSON data from stdin for statusLine
|
|
50
|
+
let input = '';
|
|
51
|
+
process.stdin.setEncoding('utf-8');
|
|
52
|
+
process.stdin.on('data', chunk => { input += chunk; });
|
|
53
|
+
process.stdin.on('end', () => {
|
|
54
|
+
try {
|
|
55
|
+
const data = JSON.parse(input);
|
|
56
|
+
statusLine(data);
|
|
57
|
+
} catch (err) {
|
|
58
|
+
if (process.env.GSD_DEBUG) console.error('[context-monitor:cli]', err);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
} else if (cmd === 'postToolUse') {
|
|
62
|
+
const result = postToolUse();
|
|
63
|
+
if (result) console.log(result);
|
|
64
|
+
}
|
package/hooks/hooks.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"PostToolUse": [
|
|
4
|
+
{
|
|
5
|
+
"matcher": "*",
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/context-monitor.js\" postToolUse"
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
"statusLine": {
|
|
16
|
+
"type": "command",
|
|
17
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/context-monitor.js\" statusLine"
|
|
18
|
+
}
|
|
19
|
+
}
|
package/install.js
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Plugin installer for GSD-Lite
|
|
3
|
+
|
|
4
|
+
import { existsSync, mkdirSync, cpSync, readFileSync, writeFileSync, rmSync } from 'node:fs';
|
|
5
|
+
import { join, dirname } from 'node:path';
|
|
6
|
+
import { homedir } from 'node:os';
|
|
7
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
8
|
+
|
|
9
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const CLAUDE_DIR = join(homedir(), '.claude');
|
|
11
|
+
const RUNTIME_DIR = join(CLAUDE_DIR, 'gsd-lite');
|
|
12
|
+
const DRY_RUN = process.argv.includes('--dry-run');
|
|
13
|
+
|
|
14
|
+
function log(msg) { console.log(msg); }
|
|
15
|
+
|
|
16
|
+
function formatHookCommand(scriptPath, hookName) {
|
|
17
|
+
return `node ${JSON.stringify(scriptPath)} ${hookName}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function registerStatusLine(settings, hookPath) {
|
|
21
|
+
const command = formatHookCommand(hookPath, 'statusLine');
|
|
22
|
+
// Don't overwrite non-GSD statusLine
|
|
23
|
+
if (settings.statusLine && typeof settings.statusLine === 'object'
|
|
24
|
+
&& !settings.statusLine.command?.includes('context-monitor.js')) {
|
|
25
|
+
log(' ! Preserved existing statusLine');
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
settings.statusLine = { type: 'command', command };
|
|
29
|
+
// Clean up legacy format (was incorrectly placed in hooks)
|
|
30
|
+
if (settings.hooks?.StatusLine) delete settings.hooks.StatusLine;
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function registerPostToolUseHook(hooks, hookPath) {
|
|
35
|
+
const command = formatHookCommand(hookPath, 'postToolUse');
|
|
36
|
+
const entry = { matcher: '*', hooks: [{ type: 'command', command }] };
|
|
37
|
+
if (!hooks.PostToolUse) {
|
|
38
|
+
hooks.PostToolUse = [entry];
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
// Handle legacy string format
|
|
42
|
+
if (typeof hooks.PostToolUse === 'string') {
|
|
43
|
+
if (!hooks.PostToolUse.includes('context-monitor.js')) {
|
|
44
|
+
log(' ! Preserved existing PostToolUse hook');
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
hooks.PostToolUse = [entry];
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
if (Array.isArray(hooks.PostToolUse)) {
|
|
51
|
+
const idx = hooks.PostToolUse.findIndex(e =>
|
|
52
|
+
e.hooks?.some(h => h.command?.includes('context-monitor.js')));
|
|
53
|
+
if (idx >= 0) hooks.PostToolUse[idx] = entry;
|
|
54
|
+
else hooks.PostToolUse.push(entry);
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function copyDir(src, dest, label) {
|
|
61
|
+
if (DRY_RUN) {
|
|
62
|
+
log(` [dry-run] Would copy ${src} → ${dest}`);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
mkdirSync(dest, { recursive: true });
|
|
66
|
+
cpSync(src, dest, { recursive: true });
|
|
67
|
+
log(` ✓ ${label}`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function copyFile(src, dest, label) {
|
|
71
|
+
if (DRY_RUN) {
|
|
72
|
+
log(` [dry-run] Would copy ${src} → ${dest}`);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
76
|
+
cpSync(src, dest);
|
|
77
|
+
log(` ✓ ${label}`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function main() {
|
|
81
|
+
log('GSD-Lite Installer\n');
|
|
82
|
+
|
|
83
|
+
if (!existsSync(CLAUDE_DIR)) {
|
|
84
|
+
log(`Error: ${CLAUDE_DIR} not found. Is Claude Code installed?`);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
log('Installing files...');
|
|
89
|
+
|
|
90
|
+
// Reset managed runtime directory to avoid stale files on reinstall
|
|
91
|
+
if (!DRY_RUN && existsSync(RUNTIME_DIR)) {
|
|
92
|
+
rmSync(RUNTIME_DIR, { recursive: true, force: true });
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// 1. Commands
|
|
96
|
+
copyDir(join(__dirname, 'commands'), join(CLAUDE_DIR, 'commands', 'gsd'), 'commands → ~/.claude/commands/gsd/');
|
|
97
|
+
|
|
98
|
+
// 2. Agents (namespaced under gsd/ to avoid collisions) [I-5]
|
|
99
|
+
copyDir(join(__dirname, 'agents'), join(CLAUDE_DIR, 'agents', 'gsd'), 'agents → ~/.claude/agents/gsd/');
|
|
100
|
+
|
|
101
|
+
// 3. Workflows
|
|
102
|
+
copyDir(join(__dirname, 'workflows'), join(CLAUDE_DIR, 'workflows', 'gsd'), 'workflows → ~/.claude/workflows/gsd/');
|
|
103
|
+
|
|
104
|
+
// 4. References
|
|
105
|
+
copyDir(join(__dirname, 'references'), join(CLAUDE_DIR, 'references', 'gsd'), 'references → ~/.claude/references/gsd/');
|
|
106
|
+
|
|
107
|
+
// 5. Hooks
|
|
108
|
+
copyDir(join(__dirname, 'hooks'), join(CLAUDE_DIR, 'hooks'), 'hooks → ~/.claude/hooks/');
|
|
109
|
+
|
|
110
|
+
// 6. Stable runtime for MCP server
|
|
111
|
+
copyDir(join(__dirname, 'src'), join(RUNTIME_DIR, 'src'), 'runtime/src → ~/.claude/gsd-lite/src/');
|
|
112
|
+
copyDir(join(__dirname, 'node_modules'), join(RUNTIME_DIR, 'node_modules'), 'runtime/node_modules → ~/.claude/gsd-lite/node_modules/');
|
|
113
|
+
copyFile(join(__dirname, 'package.json'), join(RUNTIME_DIR, 'package.json'), 'runtime/package.json → ~/.claude/gsd-lite/package.json');
|
|
114
|
+
|
|
115
|
+
// 7. Register MCP server in settings.json
|
|
116
|
+
const settingsPath = join(CLAUDE_DIR, 'settings.json');
|
|
117
|
+
if (!DRY_RUN) {
|
|
118
|
+
let settings = {};
|
|
119
|
+
try {
|
|
120
|
+
settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
|
|
121
|
+
} catch {}
|
|
122
|
+
|
|
123
|
+
if (!settings.mcpServers) settings.mcpServers = {};
|
|
124
|
+
settings.mcpServers['gsd-lite'] = {
|
|
125
|
+
command: 'node',
|
|
126
|
+
args: [join(RUNTIME_DIR, 'src', 'server.js')],
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// Register statusLine (top-level setting) and PostToolUse hook
|
|
130
|
+
if (!settings.hooks) settings.hooks = {};
|
|
131
|
+
const hookPath = join(CLAUDE_DIR, 'hooks', 'context-monitor.js');
|
|
132
|
+
const statusLineRegistered = registerStatusLine(settings, hookPath);
|
|
133
|
+
const postToolUseRegistered = registerPostToolUseHook(settings.hooks, hookPath);
|
|
134
|
+
|
|
135
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
|
|
136
|
+
log(' ✓ MCP server registered in settings.json');
|
|
137
|
+
if (statusLineRegistered || postToolUseRegistered) {
|
|
138
|
+
log(' ✓ GSD-Lite hooks registered in settings.json');
|
|
139
|
+
}
|
|
140
|
+
} else {
|
|
141
|
+
log(' [dry-run] Would register MCP server in settings.json');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
log('\n✓ GSD-Lite installed successfully!');
|
|
145
|
+
log(' Use /gsd:start to begin a new project');
|
|
146
|
+
log(' Use /gsd:resume to continue an existing project');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
150
|
+
main();
|
|
151
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "gsd-lite",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "AI orchestration tool for Claude Code — GSD management shell + Superpowers quality core",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"gsd-lite": "./cli.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "node --test tests/*.test.js",
|
|
11
|
+
"test:coverage": "c8 --reporter=text --reporter=lcov node --test tests/*.test.js",
|
|
12
|
+
"lint": "biome check src/ tests/ hooks/",
|
|
13
|
+
"lint:fix": "biome check --write src/ tests/ hooks/",
|
|
14
|
+
"start": "node src/server.js"
|
|
15
|
+
},
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/sdsrss/gsd-lite"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"claude",
|
|
22
|
+
"claude-code",
|
|
23
|
+
"mcp",
|
|
24
|
+
"orchestration",
|
|
25
|
+
"ai-agent",
|
|
26
|
+
"task-management"
|
|
27
|
+
],
|
|
28
|
+
"files": [
|
|
29
|
+
".claude-plugin/",
|
|
30
|
+
"src/",
|
|
31
|
+
"commands/",
|
|
32
|
+
"agents/",
|
|
33
|
+
"workflows/",
|
|
34
|
+
"references/",
|
|
35
|
+
"hooks/",
|
|
36
|
+
"cli.js",
|
|
37
|
+
"install.js",
|
|
38
|
+
"uninstall.js"
|
|
39
|
+
],
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=20.0.0"
|
|
42
|
+
},
|
|
43
|
+
"license": "MIT",
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@modelcontextprotocol/sdk": "^1.27.1"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@biomejs/biome": "^2.4.6",
|
|
49
|
+
"c8": "^11.0.0"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# 反合理化完整参考 (Anti-Rationalization Full Reference)
|
|
2
|
+
|
|
3
|
+
> 本文档是所有 Agent 红旗/合理化模式的 **主参考**。
|
|
4
|
+
> Agent 内联版本为精简摘要;本文档为完整版,供按需读取。
|
|
5
|
+
> 目的: 识别并阻断 AI 跳过质量流程的合理化思维。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Executor 红旗 (测试相关)
|
|
10
|
+
|
|
11
|
+
| 想法 (Thought) | 现实 (Reality) | 行动 (Action) |
|
|
12
|
+
|----------------|---------------|---------------|
|
|
13
|
+
| "太简单了不需要测试" | 简单代码也会出错。复杂度不是跳过测试的理由。 | 检查 TDD 例外列表。不在例外中 → 写测试。 |
|
|
14
|
+
| "我先写完再测试" | 后写的测试立即通过,证明不了任何东西。它只是在验证你写的代码"能跑",不是在验证"正确"。 | 回到 RED-GREEN-REFACTOR。先写失败测试。 |
|
|
15
|
+
| "就这一次跳过" | 你在合理化。每一次"就这一次"都是纪律崩溃的开始。 | 停止。回到正确流程。没有例外。 |
|
|
16
|
+
| "我已经手动测试过了" | 手动测试不可重复,不可验证,不能防回归。 | 写自动测试。手动验证只是补充,不是替代。 |
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 2. Reviewer 红旗 (证据相关)
|
|
21
|
+
|
|
22
|
+
| 想法 (Thought) | 现实 (Reality) | 行动 (Action) |
|
|
23
|
+
|----------------|---------------|---------------|
|
|
24
|
+
| "executor 说测试通过了" | 你是独立审查器。不信任任何人的报告。 | 自己运行测试,用自己的眼睛看结果。 |
|
|
25
|
+
| "看起来没问题" | "看起来"不是证据。没有具体观察结果的判断是无效的。 | 列出具体检查项和观察到的结果。 |
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 3. Debugger 红旗 (根因相关)
|
|
30
|
+
|
|
31
|
+
| 想法 (Thought) | 现实 (Reality) | 行动 (Action) |
|
|
32
|
+
|----------------|---------------|---------------|
|
|
33
|
+
| "快速修一下先" | 你在跳过根因调查。没有根因分析的修复是在赌博。 | 停止。完成 Phase 1 (根因调查) 后再提修复方案。 |
|
|
34
|
+
| "应该是 X 的问题" | 没有证据的假设。直觉在调试中不可靠。 | 先调查。用数据和日志支撑假设,不是猜测。 |
|
|
35
|
+
| "再试一个修复" (已尝试 2+) | 盲目重试说明你没有理解根因。 | 停止尝试修复。退后一步,质疑架构假设。 |
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 4. 通用合理化模式
|
|
40
|
+
|
|
41
|
+
### 4.1 流程跳过类
|
|
42
|
+
|
|
43
|
+
| 想法 (Thought) | 现实 (Reality) | 行动 (Action) |
|
|
44
|
+
|----------------|---------------|---------------|
|
|
45
|
+
| "这个改动太小了,不需要走流程" | 小改动也可能引入 bug。流程的价值不取决于改动大小。 | 按任务级别走对应流程 (L0/L1/L2)。 |
|
|
46
|
+
| "赶时间,先跳过审查" | 跳过审查省的时间,远小于修 bug 花的时间。 | 审查是必经步骤,不是可选项。 |
|
|
47
|
+
| "我很确定这是对的" | 确信不等于正确。验证铁律: 必须有 fresh evidence。 | 运行验证,用结果说话。 |
|
|
48
|
+
|
|
49
|
+
### 4.2 质量妥协类
|
|
50
|
+
|
|
51
|
+
| 想法 (Thought) | 现实 (Reality) | 行动 (Action) |
|
|
52
|
+
|----------------|---------------|---------------|
|
|
53
|
+
| "先让它能跑,之后再重构" | "之后"几乎不会到来。技术债是复利。 | 现在就写干净的代码。REFACTOR 是 TDD 循环的一部分。 |
|
|
54
|
+
| "这只是 POC/原型" | 原型代码常常变成生产代码。 | 即使是原型,也遵守基本质量标准。 |
|
|
55
|
+
| "测试覆盖率够了" | 覆盖率是数字,不是质量指标。100% 覆盖率的测试可能全是无意义的。 | 关注测试质量: 是否覆盖了边界条件和错误路径? |
|
|
56
|
+
|
|
57
|
+
### 4.3 范围蔓延类
|
|
58
|
+
|
|
59
|
+
| 想法 (Thought) | 现实 (Reality) | 行动 (Action) |
|
|
60
|
+
|----------------|---------------|---------------|
|
|
61
|
+
| "顺便把这个也改了" | 范围蔓延。未计划的修改可能引入意外问题。 | 标注 `[DECISION]` 或返回编排器确认。 |
|
|
62
|
+
| "这个 bug 我现在就能修" | 如果不在当前 task 范围内,它就不是你现在的工作。 | 记录到 blockers 或建议后续 task。 |
|
|
63
|
+
| "加个小功能不影响" | 每个"小功能"都增加测试、维护和复杂度。 | 遵守 YAGNI。当前 task 只做计划内的事。 |
|
|
64
|
+
|
|
65
|
+
### 4.4 知识盲区类
|
|
66
|
+
|
|
67
|
+
| 想法 (Thought) | 现实 (Reality) | 行动 (Action) |
|
|
68
|
+
|----------------|---------------|---------------|
|
|
69
|
+
| "文档里没说不行" | 文档没覆盖 ≠ 允许。缺失信息应当确认,不是默认通过。 | 查阅源码或测试验证实际行为。 |
|
|
70
|
+
| "这个 API 应该是这样用的" | "应该"是假设。API 行为以官方文档和实际测试为准。 | 写集成测试验证 API 行为。 |
|
|
71
|
+
| "以前都是这样做的" | 惯性不等于正确。技术和需求在变化。 | 评估当前上下文,确认做法仍然适用。 |
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 5. 识别合理化的信号
|
|
76
|
+
|
|
77
|
+
当你发现自己在想以下内容时,你正在合理化:
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
"只是..." → 在最小化问题的严重性
|
|
81
|
+
"应该..." → 在用假设替代验证
|
|
82
|
+
"先...后..." → 在推迟质量步骤 (且"后"几乎不会到来)
|
|
83
|
+
"太...了" → 在用极端程度作为跳过的借口
|
|
84
|
+
"这次..." → 在为破例寻找理由
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 6. 应对策略
|
|
90
|
+
|
|
91
|
+
1. **意识到** → 识别合理化想法 (参考上方表格)
|
|
92
|
+
2. **停止** → 不要继续当前动作
|
|
93
|
+
3. **回到流程** → 找到正确的下一步 (参考 agent 内联规则)
|
|
94
|
+
4. **如果不确定** → 返回 `[BLOCKED]`,让编排器决策
|
|
95
|
+
|
|
96
|
+
> 铁律: 流程存在的原因是防止你在"感觉对"的时候犯错。
|
|
97
|
+
> 当你想跳过流程时,恰恰是最需要流程的时候。
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## 7. 快速自检清单
|
|
102
|
+
|
|
103
|
+
每次完成任务前,过一遍:
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
□ 我是否跳过了任何测试? (检查 §1)
|
|
107
|
+
□ 我的证据是自己验证的,还是别人告诉我的? (检查 §2)
|
|
108
|
+
□ 我是否在没有根因分析的情况下提出修复? (检查 §3)
|
|
109
|
+
□ 我是否做了计划外的修改? (检查 §4.3)
|
|
110
|
+
□ 我的脑中是否出现过 §5 中的信号词?
|
|
111
|
+
→ 任何一项为"是" → 停止,回到流程
|
|
112
|
+
```
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Git Worktree 工作流参考 (Git Worktrees Reference)
|
|
2
|
+
|
|
3
|
+
> 本文档介绍 Git Worktree 在隔离开发中的用法。
|
|
4
|
+
> 适用场景: 需要在不影响当前工作的情况下创建独立开发环境。
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 1. 什么是 Worktree
|
|
9
|
+
|
|
10
|
+
Git Worktree 允许你从同一个仓库创建多个工作目录,每个目录关联不同分支。
|
|
11
|
+
好处: 切换任务时不需要 stash/commit 当前工作,每个 worktree 完全独立。
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
主仓库: /project (main branch)
|
|
15
|
+
Worktree: /project-feat-auth (feat/auth branch)
|
|
16
|
+
Worktree: /project-fix-bug (fix/login-bug branch)
|
|
17
|
+
→ 三个目录独立工作,共享同一个 .git 数据
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 2. 何时使用
|
|
23
|
+
|
|
24
|
+
| 场景 | 推荐 |
|
|
25
|
+
|------|------|
|
|
26
|
+
| 紧急 bug 修复,但当前分支有未完成工作 | Worktree |
|
|
27
|
+
| 需要同时对比两个分支的运行结果 | Worktree |
|
|
28
|
+
| 长期特性开发 + 日常维护并行 | Worktree |
|
|
29
|
+
| 简单的分支切换 (无未提交修改) | `git checkout` 即可 |
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 3. 基本操作
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# 创建 (基于现有分支)
|
|
37
|
+
git worktree add ../project-feat-auth feat/auth
|
|
38
|
+
|
|
39
|
+
# 创建 (新分支)
|
|
40
|
+
git worktree add -b feat/new-feature ../project-new-feature main
|
|
41
|
+
|
|
42
|
+
# 查看所有 worktree
|
|
43
|
+
git worktree list
|
|
44
|
+
|
|
45
|
+
# 在 worktree 中工作 (正常 git 操作)
|
|
46
|
+
cd ../project-feat-auth
|
|
47
|
+
git add . && git commit -m "feat(auth): add JWT validation"
|
|
48
|
+
git push -u origin feat/auth
|
|
49
|
+
|
|
50
|
+
# 删除 worktree
|
|
51
|
+
git worktree remove ../project-feat-auth # 正常删除
|
|
52
|
+
git worktree remove --force ../project-feat-auth # 有未提交修改时
|
|
53
|
+
|
|
54
|
+
# 清理无效引用 (手动删除目录后)
|
|
55
|
+
git worktree prune
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 4. 常见问题和解决方案
|
|
61
|
+
|
|
62
|
+
| 问题 | 原因 | 解决 |
|
|
63
|
+
|------|------|------|
|
|
64
|
+
| `fatal: 'branch' is already checked out` | 同一分支不能同时被两个 worktree checkout | 创建新分支,或先在另一个 worktree 切换分支 |
|
|
65
|
+
| Worktree 中 `node_modules` 缺失 | 每个 worktree 需要独立安装依赖 | 在 worktree 目录中运行 `npm install` (或对应包管理器) |
|
|
66
|
+
| Worktree 中 IDE 打开错误项目 | IDE 可能缓存了主仓库路径 | 用 `code ../project-feat-auth` 打开新窗口 |
|
|
67
|
+
| 删除 worktree 后分支还在 | `worktree remove` 不删除分支 | 按需手动删除: `git branch -d feat/auth` |
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 5. 最佳实践
|
|
72
|
+
|
|
73
|
+
- **命名规范:** worktree 目录名用 `项目名-分支描述`,便于识别
|
|
74
|
+
- **及时清理:** 分支合并后立即删除对应 worktree
|
|
75
|
+
- **独立依赖:** 每个 worktree 安装独立的 `node_modules` (不要软链接)
|
|
76
|
+
- **避免嵌套:** 不要在 worktree 内创建 worktree
|
|
77
|
+
- **用 list 检查:** 定期 `git worktree list` 清理废弃的 worktree
|