sumulige-claude 1.2.0 → 1.3.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.
Files changed (77) hide show
  1. package/.claude/.kickoff-hint.txt +3 -2
  2. package/.claude/AGENTS.md +6 -6
  3. package/.claude/CLAUDE.md +138 -0
  4. package/.claude/README.md +234 -43
  5. package/.claude/USAGE.md +175 -0
  6. package/.claude/boris-optimizations.md +167 -0
  7. package/.claude/commands/fix.md +83 -0
  8. package/.claude/commands/plan.md +88 -0
  9. package/.claude/commands/refactor.md +102 -0
  10. package/.claude/commands/todos.md +6 -41
  11. package/.claude/hooks/code-formatter.cjs +2 -7
  12. package/.claude/hooks/conversation-logger.cjs +222 -0
  13. package/.claude/hooks/multi-session.cjs +3 -9
  14. package/.claude/hooks/pre-push.cjs +3 -2
  15. package/.claude/hooks/project-kickoff.cjs +198 -20
  16. package/.claude/hooks/rag-skill-loader.cjs +0 -7
  17. package/.claude/hooks/session-restore.cjs +0 -0
  18. package/.claude/hooks/session-save.cjs +0 -0
  19. package/.claude/hooks/thinking-silent.cjs +3 -9
  20. package/.claude/hooks/todo-manager.cjs +142 -269
  21. package/.claude/hooks/verify-work.cjs +4 -10
  22. package/.claude/rag/skill-index.json +147 -8
  23. package/.claude/rules/coding-style.md +119 -0
  24. package/.claude/rules/hooks.md +288 -0
  25. package/.claude/rules/performance.md +78 -0
  26. package/.claude/rules/security.md +56 -0
  27. package/.claude/rules/testing.md +89 -0
  28. package/.claude/settings.json +115 -0
  29. package/.claude/settings.local.json +19 -1
  30. package/.claude/skills/SKILLS.md +145 -0
  31. package/.claude/skills/design-brain/SKILL.md +190 -0
  32. package/.claude/skills/design-brain/metadata.yaml +26 -0
  33. package/.claude/skills/examples/README.md +47 -0
  34. package/.claude/skills/examples/basic-task.md +67 -0
  35. package/.claude/skills/examples/bug-fix-workflow.md +92 -0
  36. package/.claude/skills/examples/feature-development.md +81 -0
  37. package/.claude/skills/manus-kickoff/SKILL.md +128 -0
  38. package/.claude/skills/manus-kickoff/examples/basic.md +84 -0
  39. package/.claude/skills/manus-kickoff/metadata.yaml +33 -0
  40. package/.claude/skills/manus-kickoff/templates/PROJECT_KICKOFF.md +89 -0
  41. package/.claude/skills/manus-kickoff/templates/PROJECT_PROPOSAL.md +227 -0
  42. package/.claude/skills/manus-kickoff/templates/TASK_PLAN.md +121 -0
  43. package/.claude/skills/quality-guard/SKILL.md +138 -0
  44. package/.claude/skills/quality-guard/metadata.yaml +27 -0
  45. package/.claude/skills/quick-fix/SKILL.md +138 -0
  46. package/.claude/skills/quick-fix/metadata.yaml +26 -0
  47. package/.claude/skills/test-master/SKILL.md +186 -0
  48. package/.claude/skills/test-master/metadata.yaml +29 -0
  49. package/.claude/templates/PROJECT_KICKOFF.md +89 -0
  50. package/.claude/templates/PROJECT_PROPOSAL.md +227 -0
  51. package/.claude/templates/TASK_PLAN.md +121 -0
  52. package/.claude-plugin/marketplace.json +2 -2
  53. package/AGENTS.md +49 -7
  54. package/CHANGELOG.md +56 -2
  55. package/CLAUDE-template.md +114 -0
  56. package/README.md +73 -1
  57. package/config/official-skills.json +2 -2
  58. package/development/knowledge-base/.index.clean.json +1 -0
  59. package/jest.config.js +3 -1
  60. package/lib/commands.js +1626 -1207
  61. package/lib/marketplace.js +1 -0
  62. package/package.json +1 -1
  63. package/project-paradigm.md +313 -0
  64. package/prompts/how-to-find.md +163 -0
  65. package/tests/commands.test.js +940 -17
  66. package/tests/config-schema.test.js +425 -0
  67. package/tests/marketplace.test.js +330 -214
  68. package/tests/sync-external.test.js +214 -0
  69. package/tests/update-registry.test.js +251 -0
  70. package/tests/utils.test.js +12 -8
  71. package/tests/web-search.test.js +392 -0
  72. package/thinkinglens-silent.md +138 -0
  73. package/.claude/skills/api-tester/SKILL.md +0 -90
  74. package/.claude/skills/api-tester/examples/basic.md +0 -3
  75. package/.claude/skills/api-tester/metadata.yaml +0 -30
  76. package/.claude/skills/api-tester/templates/default.md +0 -3
  77. package/.claude/skills/template/SKILL.md +0 -6
@@ -0,0 +1,222 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Conversation Logger - 增强版对话记录器
4
+ *
5
+ * 自动记录每次对话到 DAILY_CONVERSATION.md
6
+ * 按日期分组,无需手动触发
7
+ *
8
+ * 功能:
9
+ * - 捕获用户输入和 AI 输出
10
+ * - 记录工具使用
11
+ * - 按日期自动分组
12
+ * - 实时追加到日志
13
+ */
14
+
15
+ const fs = require('fs');
16
+ const path = require('path');
17
+
18
+ const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
19
+ const CONVERSATION_LOG = path.join(PROJECT_DIR, '.claude', 'DAILY_CONVERSATION.md');
20
+ const THINKING_DIR = path.join(PROJECT_DIR, '.claude', 'thinking-routes');
21
+ const FLOW_FILE = path.join(THINKING_DIR, '.conversation-flow.json');
22
+
23
+ // 确保目录存在
24
+ try { fs.mkdirSync(THINKING_DIR, { recursive: true }); } catch (e) {}
25
+
26
+ // 获取当前日期字符串 (YYYY-MM-DD)
27
+ function getDateStr() {
28
+ const now = new Date();
29
+ const year = now.getFullYear();
30
+ const month = String(now.getMonth() + 1).padStart(2, '0');
31
+ const day = String(now.getDate()).padStart(2, '0');
32
+ return `${year}-${month}-${day}`;
33
+ }
34
+
35
+ // 获取当前时间字符串 (HH:MM)
36
+ function getTimeStr() {
37
+ const now = new Date();
38
+ const hours = String(now.getHours()).padStart(2, '0');
39
+ const minutes = String(now.getMinutes()).padStart(2, '0');
40
+ return `${hours}:${minutes}`;
41
+ }
42
+
43
+ // 转义 Markdown 特殊字符
44
+ function escapeMarkdown(text) {
45
+ if (!text) return '';
46
+ return text
47
+ .replace(/\|/g, '\\|')
48
+ .replace(/\n/g, ' ')
49
+ .slice(0, 500); // 限制长度
50
+ }
51
+
52
+ // 初始化日志文件
53
+ function initLogFile() {
54
+ if (!fs.existsSync(CONVERSATION_LOG)) {
55
+ const header = `# 每日对话记录
56
+
57
+ > 此文件由 conversation-logger.cjs 自动生成
58
+ > 记录与 AI 的每次对话
59
+
60
+ ---
61
+ `;
62
+ fs.writeFileSync(CONVERSATION_LOG, header, 'utf-8');
63
+ }
64
+ }
65
+
66
+ // 追加对话到日志
67
+ function appendConversation(role, content, toolInfo = '') {
68
+ initLogFile();
69
+
70
+ const dateStr = getDateStr();
71
+ const timeStr = getTimeStr();
72
+ const roleLabel = role === 'user' ? '👤 用户' : role === 'assistant' ? '🤖 AI' : '🔧 工具';
73
+ const safeContent = escapeMarkdown(content);
74
+
75
+ const entry = `### ${timeStr} - ${roleLabel}
76
+ ${safeContent}${toolInfo ? `\n> ${toolInfo}` : ''}
77
+
78
+ `;
79
+
80
+ // 读取现有内容
81
+ let logContent = fs.readFileSync(CONVERSATION_LOG, 'utf-8');
82
+
83
+ // 检查今天是否已有日期头
84
+ const todayHeader = `## ${dateStr}`;
85
+ const todayIndex = logContent.indexOf(todayHeader);
86
+
87
+ if (todayIndex === -1) {
88
+ // 今天还没有记录,添加新的日期头
89
+ const todaySection = `
90
+ ---
91
+
92
+ ## ${dateStr}
93
+
94
+ ${entry}
95
+ `;
96
+ logContent += todaySection;
97
+ } else {
98
+ // 找到今天的记录位置,在末尾追加
99
+ // 使用正则确保只匹配 ## 开头的日期行,而不是 ### 开头的条目
100
+ const afterToday = logContent.slice(todayIndex + todayHeader.length);
101
+ const dateMatch = afterToday.match(/^## \d{4}-\d{2}-\d{2}/m);
102
+ const nextDateIndex = dateMatch ? todayIndex + todayHeader.length + dateMatch.index : -1;
103
+
104
+ if (nextDateIndex === -1) {
105
+ // 今天是最后一天,直接追加到文件末尾
106
+ logContent += entry;
107
+ } else {
108
+ // 在下一天之前插入
109
+ logContent = logContent.slice(0, nextDateIndex) + entry + logContent.slice(nextDateIndex);
110
+ }
111
+ }
112
+
113
+ // 写回文件
114
+ fs.writeFileSync(CONVERSATION_LOG, logContent, 'utf-8');
115
+ }
116
+
117
+ // 从思维轨迹读取并记录完整对话
118
+ function syncFromFlowFile() {
119
+ if (!fs.existsSync(FLOW_FILE)) {
120
+ return;
121
+ }
122
+
123
+ try {
124
+ const flow = JSON.parse(fs.readFileSync(FLOW_FILE, 'utf-8'));
125
+ const turns = flow.turns || [];
126
+
127
+ if (turns.length === 0) return;
128
+
129
+ // 读取现有日志,记录已处理的 turn
130
+ const logContent = fs.existsSync(CONVERSATION_LOG)
131
+ ? fs.readFileSync(CONVERSATION_LOG, 'utf-8')
132
+ : '';
133
+ initLogFile();
134
+
135
+ // 简单的追踪:只记录最新的几次交互
136
+ const recentTurns = turns.slice(-5);
137
+
138
+ recentTurns.forEach(turn => {
139
+ const time = turn.time ? new Date(turn.time).toISOString() : '';
140
+ const toolName = turn.toolName || '';
141
+ const type = turn.type || '';
142
+
143
+ // 根据 turn 类型记录
144
+ if (type === 'potential-action' && toolName) {
145
+ appendConversation('tool', `[${toolName}]`, turn.description || '');
146
+ }
147
+ });
148
+ } catch (e) {
149
+ // 静默处理错误
150
+ }
151
+ }
152
+
153
+ // 主函数
154
+ function main() {
155
+ try {
156
+ const eventType = process.env.CLAUDE_EVENT_TYPE || '';
157
+ const toolName = process.env.CLAUDE_TOOL_NAME || '';
158
+ const toolInput = process.env.CLAUDE_TOOL_INPUT || '';
159
+ const textOutput = process.env.CLAUDE_TEXT_OUTPUT || '';
160
+
161
+ // 根据事件类型记录
162
+ switch (eventType) {
163
+ case 'UserPromptSubmit':
164
+ // 用户提交输入
165
+ if (toolInput) {
166
+ appendConversation('user', toolInput);
167
+ }
168
+ break;
169
+
170
+ case 'TextOutput':
171
+ // AI 输出文本
172
+ if (textOutput) {
173
+ appendConversation('assistant', textOutput);
174
+ }
175
+ break;
176
+
177
+ case 'PostToolUse':
178
+ // 工具使用后
179
+ if (toolName) {
180
+ appendConversation('tool', toolInput, `使用工具: ${toolName}`);
181
+ }
182
+ break;
183
+
184
+ case 'AgentStop':
185
+ // 会话结束,同步思维轨迹
186
+ syncFromFlowFile();
187
+ break;
188
+ }
189
+
190
+ } catch (e) {
191
+ // 静默处理错误,不干扰正常对话
192
+ }
193
+
194
+ process.exit(0);
195
+ }
196
+
197
+ // 如果直接运行,执行同步
198
+ if (require.main === module) {
199
+ if (process.argv.includes('--sync')) {
200
+ syncFromFlowFile();
201
+ console.log('✅ 已同步对话记录');
202
+ } else if (process.argv.includes('--view')) {
203
+ // 查看今日对话
204
+ if (fs.existsSync(CONVERSATION_LOG)) {
205
+ const content = fs.readFileSync(CONVERSATION_LOG, 'utf-8');
206
+ const today = getDateStr();
207
+ const start = content.indexOf(`## ${today}`);
208
+ if (start !== -1) {
209
+ const end = content.indexOf('## ', start + 10);
210
+ console.log(content.slice(start, end === -1 ? undefined : end));
211
+ } else {
212
+ console.log('📭 今天暂无对话记录');
213
+ }
214
+ } else {
215
+ console.log('📭 暂无对话记录');
216
+ }
217
+ } else {
218
+ main();
219
+ }
220
+ }
221
+
222
+ module.exports = { main, syncFromFlowFile, appendConversation };
@@ -16,12 +16,6 @@ const path = require('path');
16
16
  const os = require('os');
17
17
 
18
18
  const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
19
-
20
- // 如果不在 Claude Code 环境中运行,静默退出
21
- if (!process.env.CLAUDE_PROJECT_DIR) {
22
- process.exit(0);
23
- }
24
-
25
19
  const SESSIONS_DIR = path.join(PROJECT_DIR, '.claude', 'sessions');
26
20
  const ACTIVE_SESSIONS_FILE = path.join(SESSIONS_DIR, 'active-sessions.json');
27
21
  const SESSION_LOCK_FILE = path.join(SESSIONS_DIR, '.session-lock');
@@ -129,13 +123,13 @@ function displaySessionStatus() {
129
123
  console.log(` 主机: ${getSessionIdentifier()}`);
130
124
 
131
125
  if (sessions.length > 1) {
132
- console.error(`\n 其他活跃会话:`);
126
+ console.log(`\n 其他活跃会话:`);
133
127
  sessions
134
128
  .filter(s => s.id !== currentId)
135
129
  .forEach(s => {
136
130
  const number = s.number || '?';
137
131
  const duration = Math.round((Date.now() - s.startedAt) / 1000 / 60);
138
- console.error(` - 会话 #${number}: ${s.identifier} (${duration}分钟前启动)`);
132
+ console.log(` - 会话 #${number}: ${s.identifier} (${duration}分钟前启动)`);
139
133
  });
140
134
  }
141
135
 
@@ -156,7 +150,7 @@ function main() {
156
150
  if (eventType === 'UserPromptSubmit' && toolInput.length > 20) {
157
151
  // 只在较长的用户输入时显示,避免噪音
158
152
  if (sessions.length > 1 || process.env.SHOW_SESSION_STATUS) {
159
- console.error(`\n🔄 [会话 #${sessionNumber}] 活跃会话: ${sessions.length}\n`);
153
+ console.log(`\n🔄 [会话 #${sessionNumber}] 活跃会话: ${sessions.length}\n`);
160
154
  }
161
155
  }
162
156
 
@@ -41,7 +41,8 @@ async function main() {
41
41
  stdio: 'pipe'
42
42
  }).trim() || 'origin/main';
43
43
 
44
- const output = execSync(`git diff --name-only ${upstream}...HEAD`, {
44
+ // Use --diff-filter=ACMR to exclude deleted files (D)
45
+ const output = execSync(`git diff --name-only --diff-filter=ACMR ${upstream}...HEAD`, {
45
46
  encoding: 'utf-8',
46
47
  stdio: 'pipe'
47
48
  });
@@ -85,7 +86,7 @@ async function main() {
85
86
 
86
87
  const result = await gate.check({
87
88
  files: checkable.map(f => path.join(projectDir, f)),
88
- severity: 'warn' // Block on warnings too for push
89
+ severity: 'error' // Only block on errors, not warnings
89
90
  });
90
91
 
91
92
  if (!result.passed) {
@@ -9,23 +9,28 @@
9
9
  * 功能:
10
10
  * - 检查项目是否已启动
11
11
  * - 如果未启动,提示 AI 进行项目规划
12
+ * - 生成规划文档后,自动创建任务到 backlog/
12
13
  */
13
14
 
14
15
  const fs = require('fs');
15
16
  const path = require('path');
17
+ const { execSync } = require('child_process');
16
18
 
17
19
  const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
18
-
19
- // 如果不在 Claude Code 环境中运行,静默退出
20
- if (!process.env.CLAUDE_PROJECT_DIR) {
21
- process.exit(0);
22
- }
23
-
24
20
  const TEMPLATES_DIR = path.join(PROJECT_DIR, '.claude/templates');
25
21
  const KICKOFF_FILE = path.join(PROJECT_DIR, 'PROJECT_KICKOFF.md');
26
22
  const PLAN_FILE = path.join(PROJECT_DIR, 'TASK_PLAN.md');
27
23
  const PROPOSAL_FILE = path.join(PROJECT_DIR, 'PROJECT_PROPOSAL.md');
28
24
  const HINT_FILE = path.join(PROJECT_DIR, '.claude/.kickoff-hint.txt');
25
+ const TODOS_DIR = path.join(PROJECT_DIR, 'development/todos');
26
+ const BACKLOG_DIR = path.join(TODOS_DIR, 'backlog');
27
+
28
+ // 任务类型图标
29
+ const TASK_TYPES = {
30
+ research: { icon: '📊', dir: 'research', name: 'Research' },
31
+ develop: { icon: '💻', dir: 'develop', name: 'Develop' },
32
+ test: { icon: '🧪', dir: 'test', name: 'Test' }
33
+ };
29
34
 
30
35
  // 检查项目是否已启动
31
36
  function isProjectStarted() {
@@ -41,6 +46,169 @@ function isForceKickoff() {
41
46
  toolInput.includes('重新规划');
42
47
  }
43
48
 
49
+ // 检查任务规划文档是否存在
50
+ function hasTaskPlan() {
51
+ return fs.existsSync(PLAN_FILE);
52
+ }
53
+
54
+ // 解析 TASK_PLAN.md 中的任务
55
+ function parseTasksFromPlan() {
56
+ if (!fs.existsSync(PLAN_FILE)) {
57
+ return { research: [], develop: [], test: [] };
58
+ }
59
+
60
+ const content = fs.readFileSync(PLAN_FILE, 'utf-8');
61
+ const tasks = { research: [], develop: [], test: [] };
62
+
63
+ // 匹配任务项 - 支持 - [ ] 和 - [x] 格式
64
+ const taskRegex = /-\s*\[[ x]?\]\s*(?:\[([P0-3])\])?\s*(.+)/g;
65
+ let match;
66
+
67
+ // 当前任务类型上下文
68
+ let currentType = 'develop'; // 默认为开发任务
69
+
70
+ // 检测章节标题来确定任务类型
71
+ const lines = content.split('\n');
72
+ lines.forEach(line => {
73
+ const trimmed = line.trim();
74
+
75
+ // 检测章节标题
76
+ if (trimmed.includes('研究') || trimmed.includes('Research') || trimmed.includes('调研')) {
77
+ currentType = 'research';
78
+ } else if (trimmed.includes('开发') || trimmed.includes('Develop') || trimmed.includes('实现')) {
79
+ currentType = 'develop';
80
+ } else if (trimmed.includes('测试') || trimmed.includes('Test') || trimmed.includes('验证')) {
81
+ currentType = 'test';
82
+ }
83
+
84
+ // 匹配任务项
85
+ const taskMatch = trimmed.match(/^-\s*\[([ x])\]\s*(?:\[([P0-3])\])?\s*(.+)/);
86
+ if (taskMatch) {
87
+ const [, checked, priority, title] = taskMatch;
88
+ tasks[currentType].push({
89
+ title: title.trim(),
90
+ priority: priority || 'P2',
91
+ checked: checked === 'x'
92
+ });
93
+ }
94
+ });
95
+
96
+ return tasks;
97
+ }
98
+
99
+ // 创建任务文件
100
+ function createTaskFile(task, type, index) {
101
+ const typeConfig = TASK_TYPES[type];
102
+ const slug = titleToSlug(task.title);
103
+ const fileName = `${index}-${slug}.md`;
104
+ const filePath = path.join(BACKLOG_DIR, typeConfig.dir, fileName);
105
+ const now = new Date().toISOString().split('T')[0];
106
+
107
+ // 读取对应模板
108
+ const templatePath = path.join(__dirname, '../../../development/todos/_templates', `${typeConfig.dir}.md`);
109
+ let template = '';
110
+
111
+ if (fs.existsSync(templatePath)) {
112
+ template = fs.readFileSync(templatePath, 'utf-8');
113
+ } else {
114
+ // 简化模板
115
+ template = `# ${task.title}
116
+
117
+ > **类型**: ${typeConfig.icon} ${typeConfig.name} | ${getTypeDescription(type)}
118
+ > **状态**: 待规划
119
+ > **优先级**: ${task.priority}
120
+ > **创建时间**: ${now}
121
+ > **来源**: PROJECT_KICKOFF
122
+
123
+ ---
124
+
125
+ ## 📋 任务描述
126
+
127
+ ${task.title}
128
+
129
+ ---
130
+
131
+ ## 🎯 验收标准
132
+
133
+ - [ ] 验收标准 1
134
+ - [ ] 验收标准 2
135
+
136
+ ---
137
+
138
+ ## 📝 备注
139
+
140
+ 来自项目启动规划。
141
+ `;
142
+ }
143
+
144
+ // 创建目录
145
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
146
+
147
+ // 写入任务文件
148
+ fs.writeFileSync(filePath, template);
149
+
150
+ return fileName;
151
+ }
152
+
153
+ // 将标题转换为文件名友好的 slug
154
+ function titleToSlug(title) {
155
+ return title
156
+ .toLowerCase()
157
+ .replace(/[^\u4e00-\u9fa5a-z0-9]+/g, '-')
158
+ .replace(/^-+|-+$/g, '')
159
+ .substring(0, 50);
160
+ }
161
+
162
+ // 获取任务类型描述
163
+ function getTypeDescription(type) {
164
+ const descriptions = {
165
+ research: '调研/设计/探索',
166
+ develop: '实现/编码/重构',
167
+ test: '测试/验证/QA'
168
+ };
169
+ return descriptions[type] || '';
170
+ }
171
+
172
+ // 从规划创建任务到 backlog
173
+ function createTasksFromPlan() {
174
+ const tasks = parseTasksFromPlan();
175
+ let createdCount = 0;
176
+
177
+ // 确保目录存在
178
+ Object.values(TASK_TYPES).forEach(type => {
179
+ fs.mkdirSync(path.join(BACKLOG_DIR, type.dir), { recursive: true });
180
+ });
181
+
182
+ // 创建各类任务
183
+ Object.entries(tasks).forEach(([type, taskList]) => {
184
+ taskList.forEach((task, index) => {
185
+ if (!task.checked) { // 跳过已完成任务
186
+ const fileName = createTaskFile(task, type, index + 1);
187
+ createdCount++;
188
+ console.log(` ✅ 创建 ${type} 任务: ${fileName}`);
189
+ }
190
+ });
191
+ });
192
+
193
+ return createdCount;
194
+ }
195
+
196
+ // 刷新任务索引
197
+ function refreshTaskIndex() {
198
+ const todoManagerPath = path.join(PROJECT_DIR, '.claude/hooks/todo-manager.cjs');
199
+ if (fs.existsSync(todoManagerPath)) {
200
+ try {
201
+ execSync(`node "${todoManagerPath}" --force`, {
202
+ cwd: PROJECT_DIR,
203
+ stdio: 'pipe'
204
+ });
205
+ console.log(' ✅ 任务索引已更新');
206
+ } catch (e) {
207
+ // 忽略错误
208
+ }
209
+ }
210
+ }
211
+
44
212
  // 生成启动提示
45
213
  function generateKickoffHint() {
46
214
  const now = new Date().toISOString().split('T')[0];
@@ -89,7 +257,8 @@ function generateKickoffHint() {
89
257
  ✅ 生成 PROJECT_KICKOFF.md
90
258
  ✅ 生成 TASK_PLAN.md
91
259
  ✅ 生成 PROJECT_PROPOSAL.md
92
- 等待你的确认后开始执行
260
+ 🆕 自动创建任务到 development/todos/backlog/
261
+ ✅ 🆕 刷新任务索引
93
262
 
94
263
  ═══════════════════════════════════════════════════════════════════════
95
264
 
@@ -101,24 +270,33 @@ function generateKickoffHint() {
101
270
 
102
271
  // 主函数
103
272
  function main() {
104
- try {
105
- // 如果项目已启动且不是强制模式,静默退出
106
- if (isProjectStarted() && !isForceKickoff()) {
107
- process.exit(0);
108
- }
273
+ // 如果项目已启动且不是强制模式,静默退出
274
+ if (isProjectStarted() && !isForceKickoff()) {
275
+ process.exit(0);
276
+ }
109
277
 
110
- // 生成提示文件
111
- const hint = generateKickoffHint();
112
- fs.mkdirSync(path.dirname(HINT_FILE), { recursive: true });
113
- fs.writeFileSync(HINT_FILE, hint);
278
+ // 如果已经有任务规划,自动创建任务
279
+ if (hasTaskPlan()) {
280
+ console.log('📋 检测到 TASK_PLAN.md,正在创建任务...');
114
281
 
115
- // 同时输出到 stdout (供 AI 直接读取)
116
- console.log(hint);
282
+ const createdCount = createTasksFromPlan();
117
283
 
118
- } catch (e) {
119
- // 静默处理错误
284
+ if (createdCount > 0) {
285
+ console.log(`✅ 已创建 ${createdCount} 个任务到 backlog/`);
286
+ refreshTaskIndex();
287
+ } else {
288
+ console.log('ℹ️ 所有任务已完成或为空');
289
+ }
120
290
  }
121
291
 
292
+ // 生成提示文件
293
+ const hint = generateKickoffHint();
294
+ fs.mkdirSync(path.dirname(HINT_FILE), { recursive: true });
295
+ fs.writeFileSync(HINT_FILE, hint);
296
+
297
+ // 同时输出到 stdout (供 AI 直接读取)
298
+ console.log(hint);
299
+
122
300
  process.exit(0);
123
301
  }
124
302
 
@@ -10,12 +10,6 @@ const fs = require('fs');
10
10
  const path = require('path');
11
11
 
12
12
  const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
13
-
14
- // 如果不在 Claude Code 环境中运行,静默退出
15
- if (!process.env.CLAUDE_PROJECT_DIR) {
16
- process.exit(0);
17
- }
18
-
19
13
  const RAG_DIR = path.join(PROJECT_DIR, '.claude/rag');
20
14
  const SKILL_INDEX_FILE = path.join(RAG_DIR, 'skill-index.json');
21
15
  const SKILLS_DIR = path.join(PROJECT_DIR, '.claude/skills');
@@ -153,7 +147,6 @@ function main() {
153
147
  // 将提示写入文件供 AI 阅读
154
148
  const hint = generateSkillLoadHint(matches);
155
149
  const hintFile = path.join(RAG_DIR, '.skill-hint.txt');
156
- fs.mkdirSync(path.dirname(hintFile), { recursive: true });
157
150
  fs.writeFileSync(hintFile, hint + '\n');
158
151
 
159
152
  } catch (e) {
File without changes
File without changes
@@ -14,13 +14,7 @@ const fs = require('fs');
14
14
  const path = require('path');
15
15
  const { spawn } = require('child_process');
16
16
 
17
- // 环境变量检查 - 如果不是在项目环境中运行,静默退出
18
- const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
19
- if (!process.env.CLAUDE_PROJECT_DIR) {
20
- process.exit(0);
21
- }
22
-
23
- const THINKING_DIR = path.join(PROJECT_DIR, '.claude/thinking-routes');
17
+ const THINKING_DIR = path.join(process.env.CLAUDE_PROJECT_DIR, '.claude/thinking-routes');
24
18
  const ACTIVITY_FILE = path.join(THINKING_DIR, '.conversation-flow.json');
25
19
  const SESSION_FILE = path.join(THINKING_DIR, '.current-session');
26
20
  const SYNC_MARKER_FILE = path.join(THINKING_DIR, '.last-sync');
@@ -37,7 +31,7 @@ function getSession() {
37
31
 
38
32
  if (!sessionId) {
39
33
  const date = new Date().toISOString().split('T')[0].replace(/-/g, '');
40
- const project = path.basename(PROJECT_DIR).slice(0, 10);
34
+ const project = path.basename(process.env.CLAUDE_PROJECT_DIR).slice(0, 10);
41
35
  sessionId = `s-${date}-${project}`;
42
36
  fs.writeFileSync(SESSION_FILE, sessionId);
43
37
  }
@@ -81,7 +75,7 @@ function markSynced(turnCount) {
81
75
 
82
76
  // 静默同步到 PROJECT_LOG.md
83
77
  function syncToLog() {
84
- const syncScript = path.join(PROJECT_DIR, '.claude/hooks/sync-to-log.sh');
78
+ const syncScript = path.join(process.env.CLAUDE_PROJECT_DIR, '.claude/hooks/sync-to-log.sh');
85
79
  if (fs.existsSync(syncScript)) {
86
80
  try {
87
81
  // 使用 spawn 静默执行,不输出任何内容