evo-skills 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.
Files changed (188) hide show
  1. package/.eslintrc.json +36 -0
  2. package/.prettierrc +11 -0
  3. package/README.md +227 -0
  4. package/USER-GUIDE.md +382 -0
  5. package/dist/cli/commands/diff.d.ts +7 -0
  6. package/dist/cli/commands/diff.d.ts.map +1 -0
  7. package/dist/cli/commands/diff.js +126 -0
  8. package/dist/cli/commands/diff.js.map +1 -0
  9. package/dist/cli/commands/freeze.d.ts +12 -0
  10. package/dist/cli/commands/freeze.d.ts.map +1 -0
  11. package/dist/cli/commands/freeze.js +93 -0
  12. package/dist/cli/commands/freeze.js.map +1 -0
  13. package/dist/cli/commands/log.d.ts +7 -0
  14. package/dist/cli/commands/log.d.ts.map +1 -0
  15. package/dist/cli/commands/log.js +76 -0
  16. package/dist/cli/commands/log.js.map +1 -0
  17. package/dist/cli/commands/rollback.d.ts +7 -0
  18. package/dist/cli/commands/rollback.d.ts.map +1 -0
  19. package/dist/cli/commands/rollback.js +92 -0
  20. package/dist/cli/commands/rollback.js.map +1 -0
  21. package/dist/cli/commands/status.d.ts +7 -0
  22. package/dist/cli/commands/status.d.ts.map +1 -0
  23. package/dist/cli/commands/status.js +88 -0
  24. package/dist/cli/commands/status.js.map +1 -0
  25. package/dist/cli/index.d.ts +3 -0
  26. package/dist/cli/index.d.ts.map +1 -0
  27. package/dist/cli/index.js +25 -0
  28. package/dist/cli/index.js.map +1 -0
  29. package/dist/config/defaults.d.ts +6 -0
  30. package/dist/config/defaults.d.ts.map +1 -0
  31. package/dist/config/defaults.js +31 -0
  32. package/dist/config/defaults.js.map +1 -0
  33. package/dist/config/index.d.ts +68 -0
  34. package/dist/config/index.d.ts.map +1 -0
  35. package/dist/config/index.js +195 -0
  36. package/dist/config/index.js.map +1 -0
  37. package/dist/core/evaluator/base-rule.d.ts +50 -0
  38. package/dist/core/evaluator/base-rule.d.ts.map +1 -0
  39. package/dist/core/evaluator/base-rule.js +69 -0
  40. package/dist/core/evaluator/base-rule.js.map +1 -0
  41. package/dist/core/evaluator/index.d.ts +33 -0
  42. package/dist/core/evaluator/index.d.ts.map +1 -0
  43. package/dist/core/evaluator/index.js +74 -0
  44. package/dist/core/evaluator/index.js.map +1 -0
  45. package/dist/core/evaluator/rules/repeated-drift.d.ts +19 -0
  46. package/dist/core/evaluator/rules/repeated-drift.d.ts.map +1 -0
  47. package/dist/core/evaluator/rules/repeated-drift.js +82 -0
  48. package/dist/core/evaluator/rules/repeated-drift.js.map +1 -0
  49. package/dist/core/evaluator/rules/repeated-manual-fix.d.ts +23 -0
  50. package/dist/core/evaluator/rules/repeated-manual-fix.d.ts.map +1 -0
  51. package/dist/core/evaluator/rules/repeated-manual-fix.js +97 -0
  52. package/dist/core/evaluator/rules/repeated-manual-fix.js.map +1 -0
  53. package/dist/core/journal/index.d.ts +76 -0
  54. package/dist/core/journal/index.d.ts.map +1 -0
  55. package/dist/core/journal/index.js +207 -0
  56. package/dist/core/journal/index.js.map +1 -0
  57. package/dist/core/observer/base-observer.d.ts +64 -0
  58. package/dist/core/observer/base-observer.d.ts.map +1 -0
  59. package/dist/core/observer/base-observer.js +142 -0
  60. package/dist/core/observer/base-observer.js.map +1 -0
  61. package/dist/core/observer/codex-observer.d.ts +71 -0
  62. package/dist/core/observer/codex-observer.d.ts.map +1 -0
  63. package/dist/core/observer/codex-observer.js +248 -0
  64. package/dist/core/observer/codex-observer.js.map +1 -0
  65. package/dist/core/observer/index.d.ts +7 -0
  66. package/dist/core/observer/index.d.ts.map +1 -0
  67. package/dist/core/observer/index.js +7 -0
  68. package/dist/core/observer/index.js.map +1 -0
  69. package/dist/core/observer/trace-manager.d.ts +82 -0
  70. package/dist/core/observer/trace-manager.d.ts.map +1 -0
  71. package/dist/core/observer/trace-manager.js +196 -0
  72. package/dist/core/observer/trace-manager.js.map +1 -0
  73. package/dist/core/origin-registry/index.d.ts +59 -0
  74. package/dist/core/origin-registry/index.d.ts.map +1 -0
  75. package/dist/core/origin-registry/index.js +235 -0
  76. package/dist/core/origin-registry/index.js.map +1 -0
  77. package/dist/core/patch-generator/base-strategy.d.ts +35 -0
  78. package/dist/core/patch-generator/base-strategy.d.ts.map +1 -0
  79. package/dist/core/patch-generator/base-strategy.js +55 -0
  80. package/dist/core/patch-generator/base-strategy.js.map +1 -0
  81. package/dist/core/patch-generator/index.d.ts +32 -0
  82. package/dist/core/patch-generator/index.d.ts.map +1 -0
  83. package/dist/core/patch-generator/index.js +101 -0
  84. package/dist/core/patch-generator/index.js.map +1 -0
  85. package/dist/core/patch-generator/strategies/add-fallback.d.ts +11 -0
  86. package/dist/core/patch-generator/strategies/add-fallback.d.ts.map +1 -0
  87. package/dist/core/patch-generator/strategies/add-fallback.js +57 -0
  88. package/dist/core/patch-generator/strategies/add-fallback.js.map +1 -0
  89. package/dist/core/patch-generator/strategies/prune-noise.d.ts +11 -0
  90. package/dist/core/patch-generator/strategies/prune-noise.d.ts.map +1 -0
  91. package/dist/core/patch-generator/strategies/prune-noise.js +48 -0
  92. package/dist/core/patch-generator/strategies/prune-noise.js.map +1 -0
  93. package/dist/core/shadow-manager/index.d.ts +65 -0
  94. package/dist/core/shadow-manager/index.d.ts.map +1 -0
  95. package/dist/core/shadow-manager/index.js +229 -0
  96. package/dist/core/shadow-manager/index.js.map +1 -0
  97. package/dist/core/shadow-registry/index.d.ts +68 -0
  98. package/dist/core/shadow-registry/index.d.ts.map +1 -0
  99. package/dist/core/shadow-registry/index.js +173 -0
  100. package/dist/core/shadow-registry/index.js.map +1 -0
  101. package/dist/daemon/index.d.ts +43 -0
  102. package/dist/daemon/index.d.ts.map +1 -0
  103. package/dist/daemon/index.js +144 -0
  104. package/dist/daemon/index.js.map +1 -0
  105. package/dist/storage/index.d.ts +7 -0
  106. package/dist/storage/index.d.ts.map +1 -0
  107. package/dist/storage/index.js +7 -0
  108. package/dist/storage/index.js.map +1 -0
  109. package/dist/storage/markdown.d.ts +66 -0
  110. package/dist/storage/markdown.d.ts.map +1 -0
  111. package/dist/storage/markdown.js +227 -0
  112. package/dist/storage/markdown.js.map +1 -0
  113. package/dist/storage/ndjson.d.ts +118 -0
  114. package/dist/storage/ndjson.d.ts.map +1 -0
  115. package/dist/storage/ndjson.js +238 -0
  116. package/dist/storage/ndjson.js.map +1 -0
  117. package/dist/storage/sqlite.d.ts +131 -0
  118. package/dist/storage/sqlite.d.ts.map +1 -0
  119. package/dist/storage/sqlite.js +415 -0
  120. package/dist/storage/sqlite.js.map +1 -0
  121. package/dist/types/index.d.ts +158 -0
  122. package/dist/types/index.d.ts.map +1 -0
  123. package/dist/types/index.js +5 -0
  124. package/dist/types/index.js.map +1 -0
  125. package/dist/utils/diff.d.ts +20 -0
  126. package/dist/utils/diff.d.ts.map +1 -0
  127. package/dist/utils/diff.js +47 -0
  128. package/dist/utils/diff.js.map +1 -0
  129. package/dist/utils/hash.d.ts +17 -0
  130. package/dist/utils/hash.d.ts.map +1 -0
  131. package/dist/utils/hash.js +28 -0
  132. package/dist/utils/hash.js.map +1 -0
  133. package/dist/utils/index.d.ts +8 -0
  134. package/dist/utils/index.d.ts.map +1 -0
  135. package/dist/utils/index.js +8 -0
  136. package/dist/utils/index.js.map +1 -0
  137. package/dist/utils/logger.d.ts +11 -0
  138. package/dist/utils/logger.d.ts.map +1 -0
  139. package/dist/utils/logger.js +64 -0
  140. package/dist/utils/logger.js.map +1 -0
  141. package/dist/utils/path.d.ts +67 -0
  142. package/dist/utils/path.d.ts.map +1 -0
  143. package/dist/utils/path.js +115 -0
  144. package/dist/utils/path.js.map +1 -0
  145. package/docs/ENGINEERING_PLAN.md +1065 -0
  146. package/docs/PRD.md +1004 -0
  147. package/docs/PROGRESS.md +523 -0
  148. package/package.json +60 -0
  149. package/src/cli/commands/diff.ts +158 -0
  150. package/src/cli/commands/freeze.ts +108 -0
  151. package/src/cli/commands/log.ts +87 -0
  152. package/src/cli/commands/rollback.ts +99 -0
  153. package/src/cli/commands/status.ts +101 -0
  154. package/src/cli/index.ts +31 -0
  155. package/src/config/defaults.ts +32 -0
  156. package/src/config/index.ts +220 -0
  157. package/src/core/evaluator/base-rule.ts +90 -0
  158. package/src/core/evaluator/index.ts +86 -0
  159. package/src/core/evaluator/rules/repeated-drift.ts +109 -0
  160. package/src/core/evaluator/rules/repeated-manual-fix.ts +129 -0
  161. package/src/core/journal/index.ts +286 -0
  162. package/src/core/observer/base-observer.ts +200 -0
  163. package/src/core/observer/codex-observer.ts +309 -0
  164. package/src/core/observer/index.ts +7 -0
  165. package/src/core/observer/trace-manager.ts +250 -0
  166. package/src/core/origin-registry/index.ts +264 -0
  167. package/src/core/patch-generator/base-strategy.ts +67 -0
  168. package/src/core/patch-generator/index.ts +118 -0
  169. package/src/core/patch-generator/strategies/add-fallback.ts +69 -0
  170. package/src/core/patch-generator/strategies/prune-noise.ts +65 -0
  171. package/src/core/shadow-manager/index.ts +278 -0
  172. package/src/core/shadow-registry/index.ts +200 -0
  173. package/src/daemon/index.ts +174 -0
  174. package/src/storage/index.ts +7 -0
  175. package/src/storage/markdown.ts +267 -0
  176. package/src/storage/ndjson.ts +273 -0
  177. package/src/storage/sqlite.ts +555 -0
  178. package/src/types/index.ts +212 -0
  179. package/src/utils/diff.ts +60 -0
  180. package/src/utils/hash.ts +31 -0
  181. package/src/utils/index.ts +8 -0
  182. package/src/utils/logger.ts +78 -0
  183. package/src/utils/path.ts +129 -0
  184. package/tests/unit/config.test.ts +65 -0
  185. package/tests/unit/path.test.ts +89 -0
  186. package/tests/unit/utils.test.ts +45 -0
  187. package/tsconfig.json +31 -0
  188. package/vitest.config.ts +19 -0
@@ -0,0 +1,158 @@
1
+ import { Command } from 'commander';
2
+ import { join } from 'node:path';
3
+ import { existsSync, readFileSync } from 'node:fs';
4
+ import { createShadowRegistry } from '../../core/shadow-registry/index.js';
5
+ import { createJournalManager } from '../../core/journal/index.js';
6
+ import { originRegistry } from '../../core/origin-registry/index.js';
7
+ import { createUnifiedDiff } from '../../utils/diff.js';
8
+
9
+ /**
10
+ * Diff 命令
11
+ * 查看当前内容与 origin 的 diff
12
+ */
13
+ export function createDiffCommand(): Command {
14
+ const diff = new Command('diff');
15
+
16
+ diff
17
+ .description('Show diff between shadow skill and origin')
18
+ .argument('<skill>', 'Skill ID to show diff for')
19
+ .option('-r, --revision <number>', 'Compare with specific revision')
20
+ .option('-o, --origin', 'Compare with origin skill')
21
+ .option('-p, --project <path>', 'Project root path', process.cwd())
22
+ .action(async (skillId: string, options) => {
23
+ try {
24
+ const projectRoot = options.project;
25
+
26
+ // 检查 .sea 目录是否存在
27
+ const seaDir = join(projectRoot, '.sea');
28
+ if (!existsSync(seaDir)) {
29
+ console.error('Error: .sea directory not found. Is this a SEA project?');
30
+ process.exit(1);
31
+ }
32
+
33
+ // 初始化组件
34
+ const shadowRegistry = createShadowRegistry(projectRoot);
35
+ const journalManager = createJournalManager(projectRoot);
36
+
37
+ await shadowRegistry.init();
38
+ await journalManager.init();
39
+
40
+ // 检查 shadow 是否存在
41
+ const shadow = await shadowRegistry.get(skillId);
42
+ if (!shadow) {
43
+ console.error(`Error: Shadow skill "${skillId}" not found`);
44
+ process.exit(1);
45
+ }
46
+
47
+ // 读取当前内容
48
+ const currentContent = await shadowRegistry.readContent(skillId);
49
+ if (!currentContent) {
50
+ console.error(`Error: Cannot read shadow content for "${skillId}"`);
51
+ process.exit(1);
52
+ }
53
+
54
+ const shadowId = `${skillId}@${projectRoot}`;
55
+
56
+ if (options.origin) {
57
+ // 与 origin 比较
58
+ await originRegistry.scan();
59
+ const origin = originRegistry.get(skillId);
60
+
61
+ if (!origin) {
62
+ console.error(`Error: Origin skill "${skillId}" not found`);
63
+ process.exit(1);
64
+ }
65
+
66
+ const originContent = originRegistry.readContent(skillId);
67
+ if (!originContent) {
68
+ console.error(`Error: Cannot read origin content for "${skillId}"`);
69
+ process.exit(1);
70
+ }
71
+
72
+ const diffOutput = createUnifiedDiff(
73
+ `origin/${skillId}`,
74
+ originContent,
75
+ currentContent,
76
+ 'origin',
77
+ 'shadow'
78
+ );
79
+
80
+ if (diffOutput) {
81
+ console.log(`Diff between origin and shadow for "${skillId}":\n`);
82
+ console.log(diffOutput);
83
+ } else {
84
+ console.log(`No differences found between origin and shadow for "${skillId}"`);
85
+ }
86
+ } else if (options.revision) {
87
+ // 与指定 revision 比较
88
+ const targetRevision = parseInt(options.revision, 10);
89
+ const record = await journalManager.getRecordByRevision(shadowId, targetRevision);
90
+
91
+ if (!record) {
92
+ console.error(`Error: Revision ${targetRevision} not found`);
93
+ process.exit(1);
94
+ }
95
+
96
+ // 从 snapshot 读取旧内容
97
+ const snapshots = journalManager.getSnapshots(shadowId);
98
+ const snapshot = snapshots.find((s) => s.revision === targetRevision);
99
+
100
+ if (!snapshot) {
101
+ console.error(`Error: Snapshot for revision ${targetRevision} not found`);
102
+ process.exit(1);
103
+ }
104
+
105
+ const oldContent = readFileSync(snapshot.file_path, 'utf-8');
106
+ const diffOutput = createUnifiedDiff(
107
+ `${skillId}@rev${targetRevision}`,
108
+ oldContent,
109
+ currentContent,
110
+ `rev${targetRevision}`,
111
+ 'current'
112
+ );
113
+
114
+ if (diffOutput) {
115
+ console.log(`Diff between revision ${targetRevision} and current for "${skillId}":\n`);
116
+ console.log(diffOutput);
117
+ } else {
118
+ console.log(`No differences found between revision ${targetRevision} and current`);
119
+ }
120
+ } else {
121
+ // 默认显示与 origin 的 diff
122
+ await originRegistry.scan();
123
+ const origin = originRegistry.get(skillId);
124
+
125
+ if (!origin) {
126
+ console.log(`Origin skill "${skillId}" not found, cannot show diff`);
127
+ } else {
128
+ const originContent = originRegistry.readContent(skillId);
129
+ if (originContent) {
130
+ const diffOutput = createUnifiedDiff(
131
+ `origin/${skillId}`,
132
+ originContent,
133
+ currentContent,
134
+ 'origin',
135
+ 'shadow'
136
+ );
137
+
138
+ if (diffOutput) {
139
+ console.log(`Diff between origin and shadow for "${skillId}":\n`);
140
+ console.log(diffOutput);
141
+ } else {
142
+ console.log(`No differences found between origin and shadow for "${skillId}"`);
143
+ }
144
+ }
145
+ }
146
+ }
147
+
148
+ // 关闭
149
+ shadowRegistry.close();
150
+ journalManager.close();
151
+ } catch (error) {
152
+ console.error(`Error: ${error}`);
153
+ process.exit(1);
154
+ }
155
+ });
156
+
157
+ return diff;
158
+ }
@@ -0,0 +1,108 @@
1
+ import { Command } from 'commander';
2
+ import { join } from 'node:path';
3
+ import { existsSync } from 'node:fs';
4
+ import { createShadowRegistry } from '../../core/shadow-registry/index.js';
5
+
6
+ /**
7
+ * Freeze 命令
8
+ * 暂停某个 skill 的自动优化
9
+ */
10
+ export function createFreezeCommand(): Command {
11
+ const freeze = new Command('freeze');
12
+
13
+ freeze
14
+ .description('Pause automatic optimization for a shadow skill')
15
+ .argument('<skill>', 'Skill ID to freeze')
16
+ .option('-p, --project <path>', 'Project root path', process.cwd())
17
+ .action(async (skillId: string, options) => {
18
+ try {
19
+ const projectRoot = options.project;
20
+
21
+ // 检查 .sea 目录是否存在
22
+ const seaDir = join(projectRoot, '.sea');
23
+ if (!existsSync(seaDir)) {
24
+ console.error('Error: .sea directory not found. Is this a SEA project?');
25
+ process.exit(1);
26
+ }
27
+
28
+ // 初始化组件
29
+ const shadowRegistry = createShadowRegistry(projectRoot);
30
+ await shadowRegistry.init();
31
+
32
+ // 检查 shadow 是否存在
33
+ const shadow = await shadowRegistry.get(skillId);
34
+ if (!shadow) {
35
+ console.error(`Error: Shadow skill "${skillId}" not found`);
36
+ process.exit(1);
37
+ }
38
+
39
+ // 更新状态为 frozen
40
+ const shadowId = `${skillId}@${projectRoot}`;
41
+ await shadowRegistry.updateStatus(shadowId, 'frozen');
42
+
43
+ console.log(`✅ Shadow skill "${skillId}" has been frozen`);
44
+ console.log('Automatic optimization is now paused for this skill');
45
+ console.log('\nTo unfreeze, use:');
46
+ console.log(` sea skills unfreeze ${skillId}`);
47
+
48
+ // 关闭
49
+ shadowRegistry.close();
50
+ } catch (error) {
51
+ console.error(`Error: ${error}`);
52
+ process.exit(1);
53
+ }
54
+ });
55
+
56
+ return freeze;
57
+ }
58
+
59
+ /**
60
+ * Unfreeze 命令
61
+ * 恢复某个 skill 的自动优化
62
+ */
63
+ export function createUnfreezeCommand(): Command {
64
+ const unfreeze = new Command('unfreeze');
65
+
66
+ unfreeze
67
+ .description('Resume automatic optimization for a shadow skill')
68
+ .argument('<skill>', 'Skill ID to unfreeze')
69
+ .option('-p, --project <path>', 'Project root path', process.cwd())
70
+ .action(async (skillId: string, options) => {
71
+ try {
72
+ const projectRoot = options.project;
73
+
74
+ // 检查 .sea 目录是否存在
75
+ const seaDir = join(projectRoot, '.sea');
76
+ if (!existsSync(seaDir)) {
77
+ console.error('Error: .sea directory not found. Is this a SEA project?');
78
+ process.exit(1);
79
+ }
80
+
81
+ // 初始化组件
82
+ const shadowRegistry = createShadowRegistry(projectRoot);
83
+ await shadowRegistry.init();
84
+
85
+ // 检查 shadow 是否存在
86
+ const shadow = await shadowRegistry.get(skillId);
87
+ if (!shadow) {
88
+ console.error(`Error: Shadow skill "${skillId}" not found`);
89
+ process.exit(1);
90
+ }
91
+
92
+ // 更新状态为 active
93
+ const shadowId = `${skillId}@${projectRoot}`;
94
+ await shadowRegistry.updateStatus(shadowId, 'active');
95
+
96
+ console.log(`✅ Shadow skill "${skillId}" has been unfrozen`);
97
+ console.log('Automatic optimization is now resumed for this skill');
98
+
99
+ // 关闭
100
+ shadowRegistry.close();
101
+ } catch (error) {
102
+ console.error(`Error: ${error}`);
103
+ process.exit(1);
104
+ }
105
+ });
106
+
107
+ return unfreeze;
108
+ }
@@ -0,0 +1,87 @@
1
+ import { Command } from 'commander';
2
+ import { join } from 'node:path';
3
+ import { existsSync } from 'node:fs';
4
+ import { createShadowRegistry } from '../../core/shadow-registry/index.js';
5
+ import { createJournalManager } from '../../core/journal/index.js';
6
+
7
+ /**
8
+ * Log 命令
9
+ * 查看某个 skill 的演化日志
10
+ */
11
+ export function createLogCommand(): Command {
12
+ const log = new Command('log');
13
+
14
+ log
15
+ .description('Show evolution log for a shadow skill')
16
+ .argument('<skill>', 'Skill ID to show log for')
17
+ .option('-n, --limit <number>', 'Number of records to show', '20')
18
+ .option('-f, --follow', 'Follow log output (like tail -f)')
19
+ .option('-t, --type <type>', 'Filter by change type')
20
+ .option('-p, --project <path>', 'Project root path', process.cwd())
21
+ .action(async (skillId: string, options) => {
22
+ try {
23
+ const projectRoot = options.project;
24
+
25
+ // 检查 .sea 目录是否存在
26
+ const seaDir = join(projectRoot, '.sea');
27
+ if (!existsSync(seaDir)) {
28
+ console.error('Error: .sea directory not found. Is this a SEA project?');
29
+ process.exit(1);
30
+ }
31
+
32
+ // 初始化组件
33
+ const shadowRegistry = createShadowRegistry(projectRoot);
34
+ const journalManager = createJournalManager(projectRoot);
35
+
36
+ await shadowRegistry.init();
37
+ await journalManager.init();
38
+
39
+ // 检查 shadow 是否存在
40
+ const shadow = await shadowRegistry.get(skillId);
41
+ if (!shadow) {
42
+ console.error(`Error: Shadow skill "${skillId}" not found`);
43
+ process.exit(1);
44
+ }
45
+
46
+ const shadowId = `${skillId}@${projectRoot}`;
47
+ const limit = parseInt(options.limit, 10);
48
+
49
+ // 获取 journal 记录
50
+ const records = await journalManager.getJournalRecords(shadowId, {
51
+ limit,
52
+ changeType: options.type as any,
53
+ });
54
+
55
+ if (records.length === 0) {
56
+ console.log(`No evolution records found for "${skillId}"`);
57
+ } else {
58
+ console.log(`Evolution log for "${skillId}":\n`);
59
+
60
+ for (const record of records) {
61
+ const date = new Date(record.timestamp).toLocaleString();
62
+ const changeType = record.change_type.toUpperCase();
63
+ const appliedBy = record.applied_by === 'auto' ? '🤖' : '👤';
64
+
65
+ console.log(`${appliedBy} rev_${String(record.revision).padStart(4, '0')} - ${date}`);
66
+ console.log(` Type: ${changeType}`);
67
+ console.log(` Reason: ${record.reason}`);
68
+ console.log(` Sessions: ${record.source_sessions.length}`);
69
+ console.log('');
70
+ }
71
+
72
+ console.log(`Showing ${records.length} of ${limit} most recent records`);
73
+ console.log('\nFor more details, use:');
74
+ console.log(` sea skills diff ${skillId} --from <revision>`);
75
+ }
76
+
77
+ // 关闭
78
+ shadowRegistry.close();
79
+ journalManager.close();
80
+ } catch (error) {
81
+ console.error(`Error: ${error}`);
82
+ process.exit(1);
83
+ }
84
+ });
85
+
86
+ return log;
87
+ }
@@ -0,0 +1,99 @@
1
+ import { Command } from 'commander';
2
+ import { join } from 'node:path';
3
+ import { existsSync } from 'node:fs';
4
+ import { createShadowRegistry } from '../../core/shadow-registry/index.js';
5
+ import { createJournalManager } from '../../core/journal/index.js';
6
+
7
+ /**
8
+ * Rollback 命令
9
+ * 回滚 shadow skill 到指定版本
10
+ */
11
+ export function createRollbackCommand(): Command {
12
+ const rollback = new Command('rollback');
13
+
14
+ rollback
15
+ .description('Rollback a shadow skill to a previous version')
16
+ .argument('<skill>', 'Skill ID to rollback')
17
+ .option('-t, --to <revision>', 'Rollback to specific revision')
18
+ .option('-s, --snapshot', 'Rollback to latest snapshot')
19
+ .option('-i, --initial', 'Rollback to initial version (revision 0)')
20
+ .option('-p, --project <path>', 'Project root path', process.cwd())
21
+ .action(async (skillId: string, options) => {
22
+ try {
23
+ const projectRoot = options.project;
24
+
25
+ // 检查 .sea 目录是否存在
26
+ const seaDir = join(projectRoot, '.sea');
27
+ if (!existsSync(seaDir)) {
28
+ console.error('Error: .sea directory not found. Is this a SEA project?');
29
+ process.exit(1);
30
+ }
31
+
32
+ // 初始化组件
33
+ const shadowRegistry = createShadowRegistry(projectRoot);
34
+ const journalManager = createJournalManager(projectRoot);
35
+
36
+ await shadowRegistry.init();
37
+ await journalManager.init();
38
+
39
+ // 检查 shadow 是否存在
40
+ const shadow = await shadowRegistry.get(skillId);
41
+ if (!shadow) {
42
+ console.error(`Error: Shadow skill "${skillId}" not found`);
43
+ process.exit(1);
44
+ }
45
+
46
+ const shadowId = `${skillId}@${projectRoot}`;
47
+
48
+ // 确定回滚目标
49
+ if (options.initial) {
50
+ // 回滚到初始版本
51
+ console.log(`Rolling back "${skillId}" to initial version...`);
52
+ await journalManager.rollback(shadowId, 0);
53
+ console.log(`✅ Successfully rolled back to initial version`);
54
+ } else if (options.snapshot) {
55
+ // 回滚到最新 snapshot
56
+ console.log(`Rolling back "${skillId}" to latest snapshot...`);
57
+ await journalManager.rollbackToSnapshot(shadowId);
58
+ console.log(`✅ Successfully rolled back to latest snapshot`);
59
+ } else if (options.to) {
60
+ // 回滚到指定 revision
61
+ const targetRevision = parseInt(options.to, 10);
62
+ if (isNaN(targetRevision)) {
63
+ console.error('Error: Invalid revision number');
64
+ process.exit(1);
65
+ }
66
+
67
+ console.log(`Rolling back "${skillId}" to revision ${targetRevision}...`);
68
+ await journalManager.rollback(shadowId, targetRevision);
69
+ console.log(`✅ Successfully rolled back to revision ${targetRevision}`);
70
+ } else {
71
+ // 显示可用的 revisions
72
+ console.log(`Available snapshots for "${skillId}":\n`);
73
+ const snapshots = journalManager.getSnapshots(shadowId);
74
+
75
+ if (snapshots.length === 0) {
76
+ console.log('No snapshots available');
77
+ } else {
78
+ for (const snapshot of snapshots) {
79
+ console.log(` rev_${String(snapshot.revision).padStart(4, '0')} - ${snapshot.timestamp}`);
80
+ }
81
+ }
82
+
83
+ console.log('\nUsage:');
84
+ console.log(` sea skills rollback ${skillId} --to <revision>`);
85
+ console.log(` sea skills rollback ${skillId} --snapshot`);
86
+ console.log(` sea skills rollback ${skillId} --initial`);
87
+ }
88
+
89
+ // 关闭
90
+ shadowRegistry.close();
91
+ journalManager.close();
92
+ } catch (error) {
93
+ console.error(`Error: ${error}`);
94
+ process.exit(1);
95
+ }
96
+ });
97
+
98
+ return rollback;
99
+ }
@@ -0,0 +1,101 @@
1
+ import { Command } from 'commander';
2
+ import { join } from 'node:path';
3
+ import { existsSync } from 'node:fs';
4
+ import { createShadowRegistry } from '../../core/shadow-registry/index.js';
5
+ import { createJournalManager } from '../../core/journal/index.js';
6
+
7
+ /**
8
+ * Status 命令
9
+ * 查看当前项目 shadow skills 状态
10
+ */
11
+ export function createStatusCommand(): Command {
12
+ const status = new Command('status');
13
+
14
+ status
15
+ .description('Show status of shadow skills in current project')
16
+ .option('-p, --project <path>', 'Project root path', process.cwd())
17
+ .option('-s, --skill <id>', 'Show detailed status for specific skill')
18
+ .action(async (options) => {
19
+ try {
20
+ const projectRoot = options.project;
21
+
22
+ // 检查 .sea 目录是否存在
23
+ const seaDir = join(projectRoot, '.sea');
24
+ if (!existsSync(seaDir)) {
25
+ console.error('Error: .sea directory not found. Is this a SEA project?');
26
+ process.exit(1);
27
+ }
28
+
29
+ // 初始化组件
30
+ const shadowRegistry = createShadowRegistry(projectRoot);
31
+ const journalManager = createJournalManager(projectRoot);
32
+
33
+ await shadowRegistry.init();
34
+ await journalManager.init();
35
+
36
+ if (options.skill) {
37
+ // 显示特定 skill 的详细状态
38
+ const shadow = await shadowRegistry.get(options.skill);
39
+ if (!shadow) {
40
+ console.error(`Error: Shadow skill "${options.skill}" not found`);
41
+ process.exit(1);
42
+ }
43
+
44
+ const shadowId = `${options.skill}@${projectRoot}`;
45
+ const latestRevision = await journalManager.getLatestRevision(shadowId);
46
+ const snapshots = journalManager.getSnapshots(shadowId);
47
+
48
+ console.log(`Shadow Skill: ${options.skill}`);
49
+ console.log(`Status: ${shadow.status}`);
50
+ console.log(`Current Revision: ${latestRevision}`);
51
+ console.log(`Created: ${shadow.created_at}`);
52
+ console.log(`Last Optimized: ${shadow.last_optimized_at || 'Never'}`);
53
+ console.log(`Snapshots: ${snapshots.length}`);
54
+
55
+ if (snapshots.length > 0) {
56
+ console.log('\nRecent Snapshots:');
57
+ for (const snapshot of snapshots.slice(0, 5)) {
58
+ console.log(` rev_${String(snapshot.revision).padStart(4, '0')} - ${snapshot.timestamp}`);
59
+ }
60
+ }
61
+ } else {
62
+ // 列出所有 shadow skills
63
+ const shadows = await shadowRegistry.list();
64
+
65
+ if (shadows.length === 0) {
66
+ console.log('No shadow skills found in this project');
67
+ console.log('\nTo create a shadow skill, use:');
68
+ console.log(' sea skills fork <skill-id>');
69
+ } else {
70
+ console.log(`Shadow Skills in ${projectRoot}:\n`);
71
+ console.log('Skill ID Status Revision Last Optimized');
72
+ console.log('─'.repeat(70));
73
+
74
+ for (const shadow of shadows) {
75
+ const shadowId = `${shadow.skill_id}@${projectRoot}`;
76
+ const latestRevision = await journalManager.getLatestRevision(shadowId);
77
+ const lastOptimized = shadow.last_optimized_at
78
+ ? new Date(shadow.last_optimized_at).toLocaleDateString()
79
+ : 'Never';
80
+
81
+ console.log(
82
+ `${shadow.skill_id.padEnd(22)} ${shadow.status.padEnd(11)} ${String(latestRevision).padEnd(9)} ${lastOptimized}`
83
+ );
84
+ }
85
+
86
+ console.log('\nFor detailed status of a specific skill:');
87
+ console.log(' sea skills status --skill <skill-id>');
88
+ }
89
+ }
90
+
91
+ // 关闭
92
+ shadowRegistry.close();
93
+ journalManager.close();
94
+ } catch (error) {
95
+ console.error(`Error: ${error}`);
96
+ process.exit(1);
97
+ }
98
+ });
99
+
100
+ return status;
101
+ }
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import { createStatusCommand } from './commands/status.js';
5
+ import { createRollbackCommand } from './commands/rollback.js';
6
+ import { createLogCommand } from './commands/log.js';
7
+ import { createDiffCommand } from './commands/diff.js';
8
+ import { createFreezeCommand, createUnfreezeCommand } from './commands/freeze.js';
9
+
10
+ const program = new Command();
11
+
12
+ program
13
+ .name('evo')
14
+ .description('EVO Skills - Skill Evolution Agent')
15
+ .version('0.1.0');
16
+
17
+ // Skills 子命令
18
+ const skills = new Command('skills')
19
+ .description('Manage shadow skills');
20
+
21
+ skills.addCommand(createStatusCommand());
22
+ skills.addCommand(createRollbackCommand());
23
+ skills.addCommand(createLogCommand());
24
+ skills.addCommand(createDiffCommand());
25
+ skills.addCommand(createFreezeCommand());
26
+ skills.addCommand(createUnfreezeCommand());
27
+
28
+ program.addCommand(skills);
29
+
30
+ // 解析命令行参数
31
+ program.parse();
@@ -0,0 +1,32 @@
1
+ import type { EVOConfig } from '../types/index.js';
2
+
3
+ /**
4
+ * 默认配置
5
+ */
6
+ export const DEFAULT_CONFIG: EVOConfig = {
7
+ origin_paths: {
8
+ paths: ['~/.skills', '~/.claude/skills'],
9
+ },
10
+ observer: {
11
+ enabled_runtimes: ['codex', 'opencode', 'claude'],
12
+ trace_retention_days: 30,
13
+ },
14
+ evaluator: {
15
+ min_signal_count: 3,
16
+ min_source_sessions: 2,
17
+ min_confidence: 0.7,
18
+ },
19
+ patch: {
20
+ allowed_types: ['append_context', 'tighten_trigger', 'add_fallback', 'prune_noise'],
21
+ cooldown_hours: 24,
22
+ max_patches_per_day: 3,
23
+ },
24
+ journal: {
25
+ snapshot_interval: 5,
26
+ max_snapshots: 20,
27
+ },
28
+ daemon: {
29
+ auto_start: true,
30
+ log_level: 'info',
31
+ },
32
+ };