sumulige-claude 1.0.11 → 1.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.
@@ -14,12 +14,37 @@ cat development/todos/INDEX.md
14
14
 
15
15
  ## Task Operations
16
16
 
17
+ ### Task Types (v2.0)
18
+
19
+ 任务管理系统支持 R-D-T 三阶段生命周期:
20
+
21
+ ```
22
+ Research (研究) → Develop (开发) → Test (测试) → Done (完成)
23
+ ```
24
+
25
+ | 类型 | 图标 | 目录 | 说明 |
26
+ |------|------|------|------|
27
+ | Research | 📊 | `active/research/` | 调研/设计/探索 |
28
+ | Develop | 💻 | `active/develop/` | 实现/编码/重构 |
29
+ | Test | 🧪 | `active/test/` | 测试/验证/QA |
30
+
31
+ ### Task Templates
32
+
33
+ 使用 `.claude/templates/tasks/` 中的模板创建任务:
34
+
35
+ - **研究任务**: `.claude/templates/tasks/research.md`
36
+ - **开发任务**: `.claude/templates/tasks/develop.md`
37
+ - **测试任务**: `.claude/templates/tasks/test.md`
38
+
17
39
  ### Create a New Task
18
40
 
19
41
  When user asks to create a task:
20
- 1. Create file in `development/todos/active/`
21
- 2. Use kebab-case for filename (e.g., `user-login.md`)
22
- 3. Use the template format:
42
+ 1. Determine the task type (research/develop/test)
43
+ 2. Create file in `development/todos/active/{type}/`
44
+ 3. Use kebab-case for filename (e.g., `user-authentication.md`)
45
+ 4. Copy from the corresponding template
46
+
47
+ #### Task Template (Legacy Format)
23
48
 
24
49
  ```markdown
25
50
  # [Task Name]
@@ -59,9 +84,19 @@ When user asks to create a task:
59
84
  ### Update Task Status
60
85
 
61
86
  To move a task:
62
- - **Complete**: Move from `active/` to `completed/`
63
- - **Backlog**: Move from `active/` to `backlog/`
64
- - **Archive**: Move from `completed/` to `archived/`
87
+ - **Complete**: Move from `active/{type}/` to `completed/{type}/`
88
+ - **Backlog**: Move from `active/{type}/` to `backlog/{type}/`
89
+ - **Archive**: Move from `completed/{type}/` to `archived/{type}/`
90
+
91
+ Example: Move `active/develop/auth.md` → `completed/develop/auth.md`
92
+
93
+ ### Auto-Transition Suggestions
94
+
95
+ When a develop task is completed, the todo-manager will suggest creating a corresponding test task. Check with:
96
+
97
+ ```bash
98
+ node .claude/hooks/todo-manager.cjs --suggest
99
+ ```
65
100
 
66
101
  ### Update Task Progress
67
102
 
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Session Restore Hook - Restore conversation context from file
4
+ *
5
+ * Provides context continuity across sessions
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+
11
+ const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
12
+ const SESSIONS_DIR = path.join(PROJECT_DIR, '.claude', 'sessions');
13
+ const MEMORY_FILE = path.join(PROJECT_DIR, '.claude', 'MEMORY.md');
14
+
15
+ /**
16
+ * Get latest session
17
+ */
18
+ function getLatestSession() {
19
+ if (!fs.existsSync(SESSIONS_DIR)) {
20
+ return null;
21
+ }
22
+
23
+ const files = fs.readdirSync(SESSIONS_DIR)
24
+ .filter(f => f.startsWith('session_') && f.endsWith('.md'))
25
+ .sort()
26
+ .reverse();
27
+
28
+ if (files.length === 0) {
29
+ return null;
30
+ }
31
+
32
+ const latestFile = files[0];
33
+ const filepath = path.join(SESSIONS_DIR, latestFile);
34
+ const content = fs.readFileSync(filepath, 'utf-8');
35
+
36
+ return {
37
+ file: latestFile,
38
+ path: filepath,
39
+ content: content
40
+ };
41
+ }
42
+
43
+ /**
44
+ * Get recent memory entries
45
+ */
46
+ function getRecentMemory(days = 7) {
47
+ if (!fs.existsSync(MEMORY_FILE)) {
48
+ return '';
49
+ }
50
+
51
+ const content = fs.readFileSync(MEMORY_FILE, 'utf-8');
52
+ const entries = content.split('## ').slice(1, days + 1);
53
+
54
+ return entries.join('## ');
55
+ }
56
+
57
+ /**
58
+ * Format context summary for display
59
+ */
60
+ function formatContextSummary(latestSession, recentMemory) {
61
+ let summary = '';
62
+
63
+ if (latestSession) {
64
+ summary += `\n📁 Last Session: ${latestSession.file}\n`;
65
+ summary += ` Date: ${fs.statSync(latestSession.path).mtime.toLocaleString()}\n`;
66
+ }
67
+
68
+ const memoryEntries = recentMemory.split('\n').filter(l => l.trim()).length;
69
+ if (memoryEntries > 0) {
70
+ summary += `\n💾 Memory Entries: ${memoryEntries}\n`;
71
+ }
72
+
73
+ return summary;
74
+ }
75
+
76
+ // Main execution
77
+ if (require.main === module) {
78
+ const args = process.argv.slice(2);
79
+
80
+ if (args[0] === '--latest') {
81
+ const session = getLatestSession();
82
+ if (session) {
83
+ console.log(session.content);
84
+ } else {
85
+ console.log('No sessions found.');
86
+ }
87
+ } else if (args[0] === '--memory') {
88
+ const memory = getRecentMemory(parseInt(args[1]) || 7);
89
+ console.log('# Recent Memory\n');
90
+ console.log(memory);
91
+ } else if (args[0] === '--summary') {
92
+ const session = getLatestSession();
93
+ const memory = getRecentMemory();
94
+ console.log(formatContextSummary(session, memory));
95
+ } else {
96
+ console.log('Usage: node session-restore.cjs [--latest|--memory|--summary]');
97
+ }
98
+ }
99
+
100
+ exports.getLatestSession = getLatestSession;
101
+ exports.getRecentMemory = getRecentMemory;
102
+ exports.formatContextSummary = formatContextSummary;
@@ -0,0 +1,164 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Session Save Hook - Save conversation context to file
4
+ *
5
+ * Triggered after each conversation turn
6
+ * Saves conversation history, context, and state
7
+ */
8
+
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+
12
+ const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
13
+ const SESSIONS_DIR = path.join(PROJECT_DIR, '.claude', 'sessions');
14
+ const MEMORY_FILE = path.join(PROJECT_DIR, '.claude', 'MEMORY.md');
15
+
16
+ // Ensure sessions directory exists
17
+ if (!fs.existsSync(SESSIONS_DIR)) {
18
+ fs.mkdirSync(SESSIONS_DIR, { recursive: true });
19
+ }
20
+
21
+ /**
22
+ * Generate session filename
23
+ */
24
+ function getSessionFilename() {
25
+ const now = new Date();
26
+ const date = now.toISOString().split('T')[0];
27
+ const time = now.toTimeString().split(' ')[0].replace(/:/g, '-');
28
+ return `session_${date}_${time}.md`;
29
+ }
30
+
31
+ /**
32
+ * Save session context
33
+ */
34
+ function saveSession(context) {
35
+ const filename = getSessionFilename();
36
+ const filepath = path.join(SESSIONS_DIR, filename);
37
+
38
+ const content = `# Session - ${new Date().toISOString()}
39
+
40
+ > Type: ${context.type || 'chat'}
41
+ > Model: ${context.model || 'unknown'}
42
+ > Duration: ${context.duration || 'unknown'}
43
+
44
+ ---
45
+
46
+ ## Summary
47
+
48
+ ${context.summary || 'No summary provided'}
49
+
50
+ ---
51
+
52
+ ## Context
53
+
54
+ \`\`\`json
55
+ ${JSON.stringify(context.metadata || {}, null, 2)}
56
+ \`\`\`
57
+
58
+ ---
59
+
60
+ ## Key Points
61
+
62
+ ${(context.keyPoints || []).map((p, i) => `${i + 1}. ${p}`).join('\n')}
63
+
64
+ ---
65
+
66
+ ## Artifacts
67
+
68
+ ${(context.artifacts || []).map(a => `- ${a}`).join('\n') || 'None'}
69
+
70
+ ---
71
+
72
+ ## Next Steps
73
+
74
+ ${context.nextSteps || 'None'}
75
+
76
+ ---
77
+
78
+ *Session saved at: ${new Date().toISOString()}*
79
+ `;
80
+
81
+ fs.writeFileSync(filepath, content, 'utf-8');
82
+
83
+ // Update sessions index
84
+ updateSessionsIndex();
85
+
86
+ return filename;
87
+ }
88
+
89
+ /**
90
+ * Update sessions index
91
+ */
92
+ function updateSessionsIndex() {
93
+ const files = fs.readdirSync(SESSIONS_DIR)
94
+ .filter(f => f.endsWith('.md'))
95
+ .sort()
96
+ .reverse();
97
+
98
+ const indexPath = path.join(SESSIONS_DIR, 'INDEX.md');
99
+
100
+ let content = `# Sessions Index
101
+
102
+ > Total sessions: ${files.length}
103
+ > Last updated: ${new Date().toISOString()}
104
+
105
+ ---
106
+
107
+ ## Recent Sessions
108
+
109
+ ${files.slice(0, 20).map(f => {
110
+ const filepath = path.join(SESSIONS_DIR, f);
111
+ const stat = fs.statSync(filepath);
112
+ return `- [${f}](${f}) - ${stat.mtime.toISOString()}`;
113
+ }).join('\n')}
114
+
115
+ ---
116
+ `;
117
+
118
+ fs.writeFileSync(indexPath, content, 'utf-8');
119
+ }
120
+
121
+ /**
122
+ * Update MEMORY.md with latest context
123
+ */
124
+ function updateMemory(context) {
125
+ const timestamp = new Date().toISOString();
126
+
127
+ let content = '';
128
+
129
+ if (fs.existsSync(MEMORY_FILE)) {
130
+ content = fs.readFileSync(MEMORY_FILE, 'utf-8');
131
+ }
132
+
133
+ // Check if we need to add a new entry
134
+ const newEntry = `\n## ${timestamp.split('T')[0]}\n\n${
135
+ context.summary || context.keyPoints?.join('\n') || 'No details'
136
+ }\n`;
137
+
138
+ // Keep only last 7 days
139
+ const entries = content.split('## ').slice(1, 8);
140
+ content = '# Memory\n\n<!-- Project memory updated by AI -->\n' +
141
+ '## ' + entries.join('## ') + newEntry;
142
+
143
+ fs.writeFileSync(MEMORY_FILE, content, 'utf-8');
144
+ }
145
+
146
+ // Main execution
147
+ if (require.main === module) {
148
+ const args = process.argv.slice(2);
149
+
150
+ if (args[0] === '--save' && args[1]) {
151
+ const contextData = JSON.parse(fs.readFileSync(args[1], 'utf-8'));
152
+ const filename = saveSession(contextData);
153
+ console.log(`✅ Session saved: ${filename}`);
154
+
155
+ if (contextData.addToMemory !== false) {
156
+ updateMemory(contextData);
157
+ console.log(`✅ Memory updated`);
158
+ }
159
+ }
160
+ }
161
+
162
+ exports.saveSession = saveSession;
163
+ exports.updateMemory = updateMemory;
164
+ exports.updateSessionsIndex = updateSessionsIndex;