sumulige-claude 1.3.3 → 1.4.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/.sumulige-claude-version +1 -0
- package/.claude/AGENTS.md +6 -6
- package/.claude/commands/workflow.md +81 -0
- package/.claude/hooks/auto-handoff.cjs +0 -0
- package/.claude/hooks/hook-dispatcher.cjs +304 -0
- package/.claude/hooks/hook-registry.json +73 -0
- package/.claude/hooks/lib/cache.cjs +161 -0
- package/.claude/hooks/lib/fs-utils.cjs +133 -0
- package/.claude/hooks/memory-loader.cjs +0 -0
- package/.claude/hooks/memory-saver.cjs +0 -0
- package/.claude/hooks/rag-skill-loader.cjs +84 -4
- package/.claude/settings.json +8 -82
- package/.claude/settings.local.json +4 -1
- package/CHANGELOG.md +55 -0
- package/README.md +96 -1
- package/config/version-manifest.json +85 -0
- package/lib/commands.js +56 -0
- package/lib/incremental-sync.js +274 -0
- package/lib/version-manifest.js +171 -0
- package/package.json +1 -1
- package/template/.claude/commands/workflow.md +81 -0
- package/template/.claude/hooks/hook-dispatcher.cjs +304 -0
- package/template/.claude/hooks/hook-registry.json +73 -0
- package/template/.claude/hooks/lib/cache.cjs +161 -0
- package/template/.claude/hooks/lib/fs-utils.cjs +133 -0
- package/template/.claude/hooks/rag-skill-loader.cjs +84 -4
- package/template/.claude/settings.json +8 -82
- package/template/CHANGELOG.md +297 -0
- package/template/README.md +558 -88
package/lib/commands.js
CHANGED
|
@@ -336,6 +336,51 @@ const commands = {
|
|
|
336
336
|
sync: async (...args) => {
|
|
337
337
|
const forceCheckUpdate = args.includes("--check-update");
|
|
338
338
|
const syncHooks = args.includes("--hooks");
|
|
339
|
+
const incrementalSync = args.includes("--incremental");
|
|
340
|
+
const forceSync = args.includes("--force");
|
|
341
|
+
|
|
342
|
+
// 增量同步模式
|
|
343
|
+
if (incrementalSync) {
|
|
344
|
+
console.log("🔄 Running incremental sync...");
|
|
345
|
+
console.log("");
|
|
346
|
+
|
|
347
|
+
const projectDir = process.cwd();
|
|
348
|
+
const incrementalLib = require("./incremental-sync");
|
|
349
|
+
const result = incrementalLib.incrementalSync(projectDir, { force: forceSync });
|
|
350
|
+
|
|
351
|
+
if (result.needsFullSync) {
|
|
352
|
+
console.log("ℹ️ " + result.message);
|
|
353
|
+
console.log(" Run: smc sync (without --incremental)");
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if (result.hasBreakingChanges) {
|
|
358
|
+
console.log("⚠️ " + result.message);
|
|
359
|
+
console.log("");
|
|
360
|
+
result.changes.forEach((c) => {
|
|
361
|
+
if (c.breaking) {
|
|
362
|
+
console.log(` 🔴 v${c.version}: Breaking changes`);
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if (!result.success) {
|
|
369
|
+
console.log("❌ " + result.message);
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
console.log(`✅ ${result.message}`);
|
|
374
|
+
if (result.results) {
|
|
375
|
+
const applied = result.results.filter((r) => r.result.success && !r.result.skipped);
|
|
376
|
+
applied.forEach((r) => {
|
|
377
|
+
console.log(` ✅ [${r.version}] ${r.change.type}: ${r.change.name || r.change.feature}`);
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
console.log("");
|
|
381
|
+
console.log("✅ Incremental sync complete!");
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
339
384
|
|
|
340
385
|
console.log("🔄 Syncing Sumulige Claude to current project...");
|
|
341
386
|
console.log("");
|
|
@@ -486,6 +531,17 @@ const commands = {
|
|
|
486
531
|
console.log("⚠️ Failed to sync skills");
|
|
487
532
|
}
|
|
488
533
|
|
|
534
|
+
// Update project version after full sync
|
|
535
|
+
try {
|
|
536
|
+
const versionManifest = require("./version-manifest");
|
|
537
|
+
const currentVersion = versionManifest.getCurrentVersion();
|
|
538
|
+
if (currentVersion) {
|
|
539
|
+
versionManifest.setProjectVersion(projectDir, currentVersion);
|
|
540
|
+
}
|
|
541
|
+
} catch (e) {
|
|
542
|
+
// Version manifest not available, ignore
|
|
543
|
+
}
|
|
544
|
+
|
|
489
545
|
console.log("");
|
|
490
546
|
console.log("✅ Sync complete!");
|
|
491
547
|
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Incremental Sync Manager
|
|
3
|
+
*
|
|
4
|
+
* 增量同步功能,只同步变更的文件
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const versionManifest = require('./version-manifest');
|
|
10
|
+
|
|
11
|
+
const TEMPLATE_DIR = path.join(__dirname, '../template');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 复制文件
|
|
15
|
+
*/
|
|
16
|
+
function copyFile(src, dest) {
|
|
17
|
+
const dir = path.dirname(dest);
|
|
18
|
+
if (!fs.existsSync(dir)) {
|
|
19
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
20
|
+
}
|
|
21
|
+
fs.copyFileSync(src, dest);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 合并 JSON 配置
|
|
26
|
+
*/
|
|
27
|
+
function mergeJsonConfig(src, dest) {
|
|
28
|
+
let existing = {};
|
|
29
|
+
if (fs.existsSync(dest)) {
|
|
30
|
+
try {
|
|
31
|
+
existing = JSON.parse(fs.readFileSync(dest, 'utf-8'));
|
|
32
|
+
} catch (e) {
|
|
33
|
+
existing = {};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const newConfig = JSON.parse(fs.readFileSync(src, 'utf-8'));
|
|
38
|
+
|
|
39
|
+
// 深度合并
|
|
40
|
+
const merged = deepMerge(existing, newConfig);
|
|
41
|
+
|
|
42
|
+
const dir = path.dirname(dest);
|
|
43
|
+
if (!fs.existsSync(dir)) {
|
|
44
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
45
|
+
}
|
|
46
|
+
fs.writeFileSync(dest, JSON.stringify(merged, null, 2));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 深度合并对象
|
|
51
|
+
*/
|
|
52
|
+
function deepMerge(target, source) {
|
|
53
|
+
const result = { ...target };
|
|
54
|
+
|
|
55
|
+
for (const key of Object.keys(source)) {
|
|
56
|
+
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
|
|
57
|
+
result[key] = deepMerge(result[key] || {}, source[key]);
|
|
58
|
+
} else {
|
|
59
|
+
result[key] = source[key];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* 应用单个变更
|
|
68
|
+
*/
|
|
69
|
+
function applyChange(change, projectDir, rules) {
|
|
70
|
+
const rule = rules[change.type];
|
|
71
|
+
if (!rule) return { success: false, reason: 'Unknown change type' };
|
|
72
|
+
|
|
73
|
+
const action = rule[change.action];
|
|
74
|
+
if (!action) return { success: false, reason: 'Unknown action' };
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
switch (change.type) {
|
|
78
|
+
case 'hook':
|
|
79
|
+
return applyHookChange(change, projectDir, action);
|
|
80
|
+
case 'config':
|
|
81
|
+
return applyConfigChange(change, projectDir, action);
|
|
82
|
+
case 'command':
|
|
83
|
+
return applyCommandChange(change, projectDir, action);
|
|
84
|
+
case 'lib':
|
|
85
|
+
return applyLibChange(change, projectDir, action);
|
|
86
|
+
case 'skill':
|
|
87
|
+
return applySkillChange(change, projectDir, action);
|
|
88
|
+
default:
|
|
89
|
+
return { success: true, skipped: true };
|
|
90
|
+
}
|
|
91
|
+
} catch (e) {
|
|
92
|
+
return { success: false, reason: e.message };
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 应用 hook 变更
|
|
98
|
+
*/
|
|
99
|
+
function applyHookChange(change, projectDir, action) {
|
|
100
|
+
const hookName = change.name;
|
|
101
|
+
const src = path.join(TEMPLATE_DIR, '.claude/hooks', `${hookName}.cjs`);
|
|
102
|
+
const dest = path.join(projectDir, '.claude/hooks', `${hookName}.cjs`);
|
|
103
|
+
|
|
104
|
+
if (action === 'copy') {
|
|
105
|
+
if (fs.existsSync(src)) {
|
|
106
|
+
copyFile(src, dest);
|
|
107
|
+
return { success: true, action: 'copied', file: dest };
|
|
108
|
+
}
|
|
109
|
+
return { success: false, reason: 'Source file not found' };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (action === 'delete') {
|
|
113
|
+
if (fs.existsSync(dest)) {
|
|
114
|
+
fs.unlinkSync(dest);
|
|
115
|
+
return { success: true, action: 'deleted', file: dest };
|
|
116
|
+
}
|
|
117
|
+
return { success: true, skipped: true };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return { success: true, skipped: true };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* 应用配置变更
|
|
125
|
+
*/
|
|
126
|
+
function applyConfigChange(change, projectDir, action) {
|
|
127
|
+
const configName = change.name;
|
|
128
|
+
let src, dest;
|
|
129
|
+
|
|
130
|
+
if (configName === 'settings.json') {
|
|
131
|
+
src = path.join(TEMPLATE_DIR, '.claude/settings.json');
|
|
132
|
+
dest = path.join(projectDir, '.claude/settings.json');
|
|
133
|
+
} else if (configName === 'hook-registry.json') {
|
|
134
|
+
src = path.join(TEMPLATE_DIR, '.claude/hooks/hook-registry.json');
|
|
135
|
+
dest = path.join(projectDir, '.claude/hooks/hook-registry.json');
|
|
136
|
+
} else {
|
|
137
|
+
src = path.join(TEMPLATE_DIR, '.claude', configName);
|
|
138
|
+
dest = path.join(projectDir, '.claude', configName);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (action === 'copy') {
|
|
142
|
+
if (fs.existsSync(src)) {
|
|
143
|
+
copyFile(src, dest);
|
|
144
|
+
return { success: true, action: 'copied', file: dest };
|
|
145
|
+
}
|
|
146
|
+
return { success: false, reason: 'Source file not found' };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (action === 'merge') {
|
|
150
|
+
if (fs.existsSync(src)) {
|
|
151
|
+
mergeJsonConfig(src, dest);
|
|
152
|
+
return { success: true, action: 'merged', file: dest };
|
|
153
|
+
}
|
|
154
|
+
return { success: false, reason: 'Source file not found' };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return { success: true, skipped: true };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* 应用命令变更
|
|
162
|
+
*/
|
|
163
|
+
function applyCommandChange(change, projectDir, action) {
|
|
164
|
+
const commandName = change.name;
|
|
165
|
+
const src = path.join(TEMPLATE_DIR, '.claude/commands', `${commandName}.md`);
|
|
166
|
+
const dest = path.join(projectDir, '.claude/commands', `${commandName}.md`);
|
|
167
|
+
|
|
168
|
+
if (action === 'copy') {
|
|
169
|
+
if (fs.existsSync(src)) {
|
|
170
|
+
copyFile(src, dest);
|
|
171
|
+
return { success: true, action: 'copied', file: dest };
|
|
172
|
+
}
|
|
173
|
+
return { success: false, reason: 'Source file not found' };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return { success: true, skipped: true };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* 应用库文件变更
|
|
181
|
+
*/
|
|
182
|
+
function applyLibChange(change, projectDir, action) {
|
|
183
|
+
const libPath = change.name;
|
|
184
|
+
const src = path.join(TEMPLATE_DIR, '.claude', libPath);
|
|
185
|
+
const dest = path.join(projectDir, '.claude', libPath);
|
|
186
|
+
|
|
187
|
+
if (action === 'copy') {
|
|
188
|
+
if (fs.existsSync(src)) {
|
|
189
|
+
copyFile(src, dest);
|
|
190
|
+
return { success: true, action: 'copied', file: dest };
|
|
191
|
+
}
|
|
192
|
+
return { success: false, reason: 'Source file not found' };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return { success: true, skipped: true };
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* 应用技能变更
|
|
200
|
+
*/
|
|
201
|
+
function applySkillChange(change, projectDir, action) {
|
|
202
|
+
// 技能同步由现有的 sync 命令处理
|
|
203
|
+
return { success: true, skipped: true, reason: 'Skills handled by full sync' };
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* 执行增量同步
|
|
208
|
+
*/
|
|
209
|
+
function incrementalSync(projectDir, options = {}) {
|
|
210
|
+
const summary = versionManifest.getUpdateSummary(projectDir);
|
|
211
|
+
|
|
212
|
+
if (!summary.needsUpdate) {
|
|
213
|
+
return {
|
|
214
|
+
success: true,
|
|
215
|
+
message: 'Already up to date',
|
|
216
|
+
changes: []
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (summary.isNewInstall) {
|
|
221
|
+
return {
|
|
222
|
+
success: false,
|
|
223
|
+
message: 'New installation detected. Please run full sync first.',
|
|
224
|
+
needsFullSync: true
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (summary.hasBreakingChanges && !options.force) {
|
|
229
|
+
return {
|
|
230
|
+
success: false,
|
|
231
|
+
message: 'Breaking changes detected. Use --force to continue.',
|
|
232
|
+
hasBreakingChanges: true,
|
|
233
|
+
changes: summary.changes
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const rules = versionManifest.getSyncRules();
|
|
238
|
+
const results = [];
|
|
239
|
+
|
|
240
|
+
for (const versionChange of summary.changes) {
|
|
241
|
+
for (const change of versionChange.changes) {
|
|
242
|
+
const result = applyChange(change, projectDir, rules);
|
|
243
|
+
results.push({
|
|
244
|
+
version: versionChange.version,
|
|
245
|
+
change,
|
|
246
|
+
result
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// 更新项目版本
|
|
252
|
+
versionManifest.setProjectVersion(projectDir, summary.toVersion);
|
|
253
|
+
|
|
254
|
+
return {
|
|
255
|
+
success: true,
|
|
256
|
+
message: `Updated from ${summary.fromVersion} to ${summary.toVersion}`,
|
|
257
|
+
fromVersion: summary.fromVersion,
|
|
258
|
+
toVersion: summary.toVersion,
|
|
259
|
+
results: results
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* 检查更新
|
|
265
|
+
*/
|
|
266
|
+
function checkForUpdates(projectDir) {
|
|
267
|
+
return versionManifest.getUpdateSummary(projectDir);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
module.exports = {
|
|
271
|
+
incrementalSync,
|
|
272
|
+
checkForUpdates,
|
|
273
|
+
applyChange
|
|
274
|
+
};
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version Manifest Manager
|
|
3
|
+
*
|
|
4
|
+
* 管理版本清单,支持增量同步
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
const MANIFEST_FILE = path.join(__dirname, '../config/version-manifest.json');
|
|
11
|
+
const VERSION_FILE_NAME = '.sumulige-claude-version';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 加载版本清单
|
|
15
|
+
*/
|
|
16
|
+
function loadManifest() {
|
|
17
|
+
if (!fs.existsSync(MANIFEST_FILE)) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
return JSON.parse(fs.readFileSync(MANIFEST_FILE, 'utf-8'));
|
|
22
|
+
} catch (e) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 获取项目当前版本
|
|
29
|
+
*/
|
|
30
|
+
function getProjectVersion(projectDir) {
|
|
31
|
+
const versionFile = path.join(projectDir, '.claude', VERSION_FILE_NAME);
|
|
32
|
+
if (!fs.existsSync(versionFile)) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
return fs.readFileSync(versionFile, 'utf-8').trim();
|
|
37
|
+
} catch (e) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 设置项目版本
|
|
44
|
+
*/
|
|
45
|
+
function setProjectVersion(projectDir, version) {
|
|
46
|
+
const versionFile = path.join(projectDir, '.claude', VERSION_FILE_NAME);
|
|
47
|
+
const dir = path.dirname(versionFile);
|
|
48
|
+
if (!fs.existsSync(dir)) {
|
|
49
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
50
|
+
}
|
|
51
|
+
fs.writeFileSync(versionFile, version);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* 比较版本号
|
|
56
|
+
* @returns -1 if a < b, 0 if a == b, 1 if a > b
|
|
57
|
+
*/
|
|
58
|
+
function compareVersions(a, b) {
|
|
59
|
+
const partsA = a.split('.').map(Number);
|
|
60
|
+
const partsB = b.split('.').map(Number);
|
|
61
|
+
|
|
62
|
+
for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {
|
|
63
|
+
const numA = partsA[i] || 0;
|
|
64
|
+
const numB = partsB[i] || 0;
|
|
65
|
+
if (numA < numB) return -1;
|
|
66
|
+
if (numA > numB) return 1;
|
|
67
|
+
}
|
|
68
|
+
return 0;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* 获取版本之间的变更
|
|
73
|
+
*/
|
|
74
|
+
function getChangesSince(fromVersion, toVersion = null) {
|
|
75
|
+
const manifest = loadManifest();
|
|
76
|
+
if (!manifest) return [];
|
|
77
|
+
|
|
78
|
+
const targetVersion = toVersion || manifest.current;
|
|
79
|
+
const changes = [];
|
|
80
|
+
|
|
81
|
+
for (const entry of manifest.history) {
|
|
82
|
+
if (compareVersions(entry.version, fromVersion) > 0 &&
|
|
83
|
+
compareVersions(entry.version, targetVersion) <= 0) {
|
|
84
|
+
changes.push({
|
|
85
|
+
version: entry.version,
|
|
86
|
+
date: entry.date,
|
|
87
|
+
breaking: entry.breaking,
|
|
88
|
+
changes: entry.changes
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return changes.sort((a, b) => compareVersions(a.version, b.version));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 检测是否有 breaking changes
|
|
98
|
+
*/
|
|
99
|
+
function hasBreakingChanges(fromVersion, toVersion = null) {
|
|
100
|
+
const changes = getChangesSince(fromVersion, toVersion);
|
|
101
|
+
return changes.some(c => c.breaking);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* 获取当前版本
|
|
106
|
+
*/
|
|
107
|
+
function getCurrentVersion() {
|
|
108
|
+
const manifest = loadManifest();
|
|
109
|
+
return manifest ? manifest.current : null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 获取同步规则
|
|
114
|
+
*/
|
|
115
|
+
function getSyncRules() {
|
|
116
|
+
const manifest = loadManifest();
|
|
117
|
+
return manifest ? manifest.syncRules : null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* 检查是否需要更新
|
|
122
|
+
*/
|
|
123
|
+
function needsUpdate(projectDir) {
|
|
124
|
+
const projectVersion = getProjectVersion(projectDir);
|
|
125
|
+
if (!projectVersion) return true;
|
|
126
|
+
|
|
127
|
+
const currentVersion = getCurrentVersion();
|
|
128
|
+
if (!currentVersion) return false;
|
|
129
|
+
|
|
130
|
+
return compareVersions(projectVersion, currentVersion) < 0;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* 获取更新摘要
|
|
135
|
+
*/
|
|
136
|
+
function getUpdateSummary(projectDir) {
|
|
137
|
+
const projectVersion = getProjectVersion(projectDir);
|
|
138
|
+
if (!projectVersion) {
|
|
139
|
+
return {
|
|
140
|
+
needsUpdate: true,
|
|
141
|
+
isNewInstall: true,
|
|
142
|
+
changes: []
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const currentVersion = getCurrentVersion();
|
|
147
|
+
const changes = getChangesSince(projectVersion);
|
|
148
|
+
const hasBreaking = changes.some(c => c.breaking);
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
needsUpdate: changes.length > 0,
|
|
152
|
+
isNewInstall: false,
|
|
153
|
+
fromVersion: projectVersion,
|
|
154
|
+
toVersion: currentVersion,
|
|
155
|
+
hasBreakingChanges: hasBreaking,
|
|
156
|
+
changes: changes
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
module.exports = {
|
|
161
|
+
loadManifest,
|
|
162
|
+
getProjectVersion,
|
|
163
|
+
setProjectVersion,
|
|
164
|
+
compareVersions,
|
|
165
|
+
getChangesSince,
|
|
166
|
+
hasBreakingChanges,
|
|
167
|
+
getCurrentVersion,
|
|
168
|
+
getSyncRules,
|
|
169
|
+
needsUpdate,
|
|
170
|
+
getUpdateSummary
|
|
171
|
+
};
|
package/package.json
CHANGED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# /workflow - 统一工作流命令
|
|
2
|
+
|
|
3
|
+
一键执行常见工作流操作。
|
|
4
|
+
|
|
5
|
+
## 可用子命令
|
|
6
|
+
|
|
7
|
+
### `/workflow check` - 检查状态
|
|
8
|
+
检查 sumulige-claude 更新和项目状态。
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
# 检查版本和更新
|
|
12
|
+
smc sync --check-update
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### `/workflow pull` - 拉取更新
|
|
16
|
+
增量同步 sumulige-claude 更新到当前项目。
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# 增量同步(推荐)
|
|
20
|
+
smc sync --incremental
|
|
21
|
+
|
|
22
|
+
# 强制全量同步
|
|
23
|
+
smc sync --hooks
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### `/workflow task <description>` - 执行任务
|
|
27
|
+
标准任务执行流程:
|
|
28
|
+
1. 分析任务需求
|
|
29
|
+
2. 创建 TODO 列表
|
|
30
|
+
3. 逐步实现
|
|
31
|
+
4. 更新文档
|
|
32
|
+
|
|
33
|
+
### `/workflow sync` - 同步文档
|
|
34
|
+
更新项目文档和记忆:
|
|
35
|
+
- MEMORY.md - 最新变更
|
|
36
|
+
- PROJECT_LOG.md - 历史记录
|
|
37
|
+
- CHANGELOG.md - 版本日志
|
|
38
|
+
|
|
39
|
+
### `/workflow commit <message>` - 提交变更
|
|
40
|
+
Git 提交工作流:
|
|
41
|
+
1. 检查变更状态
|
|
42
|
+
2. 暂存相关文件
|
|
43
|
+
3. 提交并生成消息
|
|
44
|
+
|
|
45
|
+
### `/workflow push` - 推送远程
|
|
46
|
+
将本地变更推送到远程仓库。
|
|
47
|
+
|
|
48
|
+
### `/workflow full <description>` - 一键完整流程
|
|
49
|
+
执行完整的开发工作流:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
1. 检查更新 → 2. 增量同步 → 3. 执行任务 → 4. 更新文档 → 5. 提交 → 6. 推送
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
示例:
|
|
56
|
+
```
|
|
57
|
+
/workflow full "实现用户认证功能"
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## 使用示例
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
# 日常任务
|
|
64
|
+
/workflow task "修复登录 bug"
|
|
65
|
+
|
|
66
|
+
# 完整流程
|
|
67
|
+
/workflow full "添加暗黑模式"
|
|
68
|
+
|
|
69
|
+
# 仅同步文档
|
|
70
|
+
/workflow sync
|
|
71
|
+
|
|
72
|
+
# 仅提交
|
|
73
|
+
/workflow commit "fix: 修复登录问题"
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 注意事项
|
|
77
|
+
|
|
78
|
+
- 任务执行前会自动检查更新
|
|
79
|
+
- 增量同步只更新变更的文件
|
|
80
|
+
- 文档同步包括 MEMORY.md 和 PROJECT_LOG.md
|
|
81
|
+
- 提交前会自动运行测试(如配置)
|