@liangjie559567/ultrapower 5.5.5 → 5.5.7

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 (98) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +13 -10
  3. package/dist/hooks/learner/__tests__/index-manager-filter.test.d.ts +14 -0
  4. package/dist/hooks/learner/__tests__/index-manager-filter.test.d.ts.map +1 -0
  5. package/dist/hooks/learner/__tests__/index-manager-filter.test.js +147 -0
  6. package/dist/hooks/learner/__tests__/index-manager-filter.test.js.map +1 -0
  7. package/dist/hooks/learner/__tests__/learning-queue-parser.test.d.ts +10 -0
  8. package/dist/hooks/learner/__tests__/learning-queue-parser.test.d.ts.map +1 -0
  9. package/dist/hooks/learner/__tests__/learning-queue-parser.test.js +131 -0
  10. package/dist/hooks/learner/__tests__/learning-queue-parser.test.js.map +1 -0
  11. package/dist/hooks/learner/__tests__/queue-archiver.test.d.ts +13 -0
  12. package/dist/hooks/learner/__tests__/queue-archiver.test.d.ts.map +1 -0
  13. package/dist/hooks/learner/__tests__/queue-archiver.test.js +162 -0
  14. package/dist/hooks/learner/__tests__/queue-archiver.test.js.map +1 -0
  15. package/dist/hooks/learner/__tests__/reflection-archiver.test.d.ts +14 -0
  16. package/dist/hooks/learner/__tests__/reflection-archiver.test.d.ts.map +1 -0
  17. package/dist/hooks/learner/__tests__/reflection-archiver.test.js +159 -0
  18. package/dist/hooks/learner/__tests__/reflection-archiver.test.js.map +1 -0
  19. package/dist/hooks/learner/__tests__/reflection-parser.test.d.ts +14 -0
  20. package/dist/hooks/learner/__tests__/reflection-parser.test.d.ts.map +1 -0
  21. package/dist/hooks/learner/__tests__/reflection-parser.test.js +201 -0
  22. package/dist/hooks/learner/__tests__/reflection-parser.test.js.map +1 -0
  23. package/dist/hooks/learner/index-manager.d.ts +19 -0
  24. package/dist/hooks/learner/index-manager.d.ts.map +1 -1
  25. package/dist/hooks/learner/index-manager.js +26 -0
  26. package/dist/hooks/learner/index-manager.js.map +1 -1
  27. package/dist/hooks/learner/learning-queue.d.ts +1 -0
  28. package/dist/hooks/learner/learning-queue.d.ts.map +1 -1
  29. package/dist/hooks/learner/learning-queue.js +82 -0
  30. package/dist/hooks/learner/learning-queue.js.map +1 -1
  31. package/dist/hooks/learner/orchestrator.d.ts +12 -1
  32. package/dist/hooks/learner/orchestrator.d.ts.map +1 -1
  33. package/dist/hooks/learner/orchestrator.js +11 -1
  34. package/dist/hooks/learner/orchestrator.js.map +1 -1
  35. package/dist/hooks/learner/queue-archiver.d.ts +21 -0
  36. package/dist/hooks/learner/queue-archiver.d.ts.map +1 -0
  37. package/dist/hooks/learner/queue-archiver.js +147 -0
  38. package/dist/hooks/learner/queue-archiver.js.map +1 -0
  39. package/dist/hooks/learner/reflection-archiver.d.ts +19 -0
  40. package/dist/hooks/learner/reflection-archiver.d.ts.map +1 -0
  41. package/dist/hooks/learner/reflection-archiver.js +113 -0
  42. package/dist/hooks/learner/reflection-archiver.js.map +1 -0
  43. package/dist/hooks/learner/reflection-cleanup.d.ts +22 -0
  44. package/dist/hooks/learner/reflection-cleanup.d.ts.map +1 -0
  45. package/dist/hooks/learner/reflection-cleanup.js +62 -0
  46. package/dist/hooks/learner/reflection-cleanup.js.map +1 -0
  47. package/dist/hooks/learner/reflection-parser.d.ts +26 -0
  48. package/dist/hooks/learner/reflection-parser.d.ts.map +1 -0
  49. package/dist/hooks/learner/reflection-parser.js +139 -0
  50. package/dist/hooks/learner/reflection-parser.js.map +1 -0
  51. package/dist/hooks/learner/reflection.d.ts +8 -1
  52. package/dist/hooks/learner/reflection.d.ts.map +1 -1
  53. package/dist/hooks/learner/reflection.js +19 -2
  54. package/dist/hooks/learner/reflection.js.map +1 -1
  55. package/dist/lib/__tests__/file-lock.test.d.ts +13 -0
  56. package/dist/lib/__tests__/file-lock.test.d.ts.map +1 -0
  57. package/dist/lib/__tests__/file-lock.test.js +122 -0
  58. package/dist/lib/__tests__/file-lock.test.js.map +1 -0
  59. package/dist/lib/file-lock.d.ts +18 -0
  60. package/dist/lib/file-lock.d.ts.map +1 -0
  61. package/dist/lib/file-lock.js +59 -0
  62. package/dist/lib/file-lock.js.map +1 -0
  63. package/docs/ARCHITECTURE.md +541 -162
  64. package/docs/CLAUDE.md +1 -1
  65. package/docs/FEATURES.md +1038 -420
  66. package/docs/REFERENCE.md +860 -787
  67. package/docs/plans/2026-03-02-docs-comprehensive-update-design.md +187 -0
  68. package/docs/plans/2026-03-02-docs-comprehensive-update.md +1395 -0
  69. package/docs/prd/memory-evolution-optimize-rough.md +508 -0
  70. package/docs/reviews/draft-prd-memory-evolution-optimize/review_critic.md +302 -0
  71. package/docs/reviews/draft-prd-memory-evolution-optimize/review_domain.md +237 -0
  72. package/docs/reviews/draft-prd-memory-evolution-optimize/review_product.md +140 -0
  73. package/docs/reviews/draft-prd-memory-evolution-optimize/review_tech.md +240 -0
  74. package/docs/reviews/draft-prd-memory-evolution-optimize/review_ux.md +121 -0
  75. package/docs/reviews/memory-evolution-optimize/summary.md +94 -0
  76. package/docs/standards/AGENTS.md +1 -1
  77. package/docs/standards/README.md +3 -3
  78. package/docs/standards/agent-lifecycle.md +1 -1
  79. package/docs/standards/anti-patterns.md +1 -1
  80. package/docs/standards/audit-report.md +2 -2
  81. package/docs/standards/contribution-guide.md +1 -1
  82. package/docs/standards/hook-execution-order.md +1 -1
  83. package/docs/standards/runtime-protection.md +1 -1
  84. package/docs/standards/state-machine.md +1 -1
  85. package/docs/standards/user-guide.md +1 -1
  86. package/docs/tasks/memory-evolution-optimize/manifest.md +475 -0
  87. package/package.json +1 -1
  88. package/scripts/bump-version.mjs +13 -9
  89. package/scripts/release-steps.mjs +1 -1
  90. package/skills/ax-evolve/SKILL.md +11 -1
  91. package/skills/ax-knowledge/AGENTS.md +27 -2
  92. package/skills/ax-knowledge/SKILL.md +25 -7
  93. package/skills/ax-reflect/SKILL.md +2 -0
  94. package/docs/prd/ultrapower-standards-draft.md +0 -191
  95. package/docs/prd/ultrapower-standards-rough.md +0 -560
  96. package/docs/reviews/draft-prd-ultrapower-pain-fix/review_tech.md +0 -219
  97. package/docs/reviews/draft_prd_pain_points/review_domain.md +0 -215
  98. package/docs/reviews/ultrapower-full-bugfix-plan/review_product.md +0 -135
@@ -8,11 +8,11 @@
8
8
  {
9
9
  "name": "ultrapower",
10
10
  "description": "Disciplined multi-agent orchestration: workflow enforcement + parallel execution",
11
- "version": "5.5.5",
11
+ "version": "5.5.7",
12
12
  "source": {
13
13
  "source": "npm",
14
14
  "package": "@liangjie559567/ultrapower",
15
- "version": "5.5.5"
15
+ "version": "5.5.7"
16
16
  },
17
17
  "author": {
18
18
  "name": "liangjie559567"
@@ -1,20 +1,23 @@
1
1
  {
2
2
  "name": "ultrapower",
3
- "description": "Disciplined multi-agent orchestration: workflow enforcement + parallel execution. Combines superpowers' TDD/debugging discipline with OMC's multi-agent execution capabilities.",
4
- "version": "5.5.5",
3
+ "description": "Disciplined multi-agent orchestration: workflow enforcement + parallel execution",
4
+ "version": "5.5.7",
5
5
  "author": {
6
6
  "name": "liangjie559567"
7
7
  },
8
- "homepage": "https://github.com/liangjie559567/ultrapower",
9
- "repository": "https://github.com/liangjie559567/ultrapower",
8
+ "homepage": "https://github.com/liangjie559567/ultrapower#readme",
9
+ "repository": "git+https://github.com/liangjie559567/ultrapower.git",
10
10
  "license": "MIT",
11
11
  "keywords": [
12
- "skills",
13
- "tdd",
14
- "debugging",
12
+ "claude",
13
+ "claude-code",
14
+ "ai",
15
+ "agent",
15
16
  "multi-agent",
16
17
  "orchestration",
17
- "workflows",
18
- "ultrapower"
18
+ "omc",
19
+ "claudecode",
20
+ "anthropic",
21
+ "llm"
19
22
  ]
20
- }
23
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * index-manager-filter.test.ts
3
+ *
4
+ * 覆盖 T-008 验收标准:
5
+ * - --filter keyword:只返回 Title/Category 含关键词的条目
6
+ * - --category cat:只返回 Category 精确匹配的条目
7
+ * - 无参数(loadIndex):返回全量
8
+ * - 结果统计正确(entries.length, total)
9
+ * - 超 256 字符关键词抛出 Error
10
+ * - 大小写不敏感验证
11
+ * - 空结果(返回 entries=[],total 为全量)
12
+ */
13
+ export {};
14
+ //# sourceMappingURL=index-manager-filter.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-manager-filter.test.d.ts","sourceRoot":"","sources":["../../../../src/hooks/learner/__tests__/index-manager-filter.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
@@ -0,0 +1,147 @@
1
+ /**
2
+ * index-manager-filter.test.ts
3
+ *
4
+ * 覆盖 T-008 验收标准:
5
+ * - --filter keyword:只返回 Title/Category 含关键词的条目
6
+ * - --category cat:只返回 Category 精确匹配的条目
7
+ * - 无参数(loadIndex):返回全量
8
+ * - 结果统计正确(entries.length, total)
9
+ * - 超 256 字符关键词抛出 Error
10
+ * - 大小写不敏感验证
11
+ * - 空结果(返回 entries=[],total 为全量)
12
+ */
13
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
14
+ import * as fs from 'fs';
15
+ import * as os from 'os';
16
+ import * as path from 'path';
17
+ import { KnowledgeIndexManager } from '../index-manager.js';
18
+ // ── 辅助:构造 knowledge_base.md 内容(表格格式,对齐 writeIndex 输出) ───────
19
+ function makeKnowledgeBase(entries) {
20
+ const rows = entries.map(e => `| ${e.id} | ${e.title} | ${e.category} | ${(e.confidence ?? 0.8).toFixed(2)} | ${e.created ?? '2026-01-01'} | active |`);
21
+ return [
22
+ '# Knowledge Base Index',
23
+ '',
24
+ '> Last updated: 2026-03-02 | Total: 3 entries',
25
+ '',
26
+ '## Knowledge Index',
27
+ '',
28
+ '| ID | Title | Category | Confidence | Created | Status |',
29
+ '|---|---|---|---|---|---|',
30
+ ...rows,
31
+ '',
32
+ ].join('\n');
33
+ }
34
+ // ── 示例知识条目 ─────────────────────────────────────────────────────────────
35
+ const SAMPLE_ENTRIES = [
36
+ { id: 'k-001', title: 'TypeScript 严格模式最佳实践', category: 'typescript' },
37
+ { id: 'k-002', title: '原子写入防止并发损坏', category: 'architecture' },
38
+ { id: 'k-003', title: 'TypeScript 路径别名配置', category: 'typescript' },
39
+ { id: 'k-004', title: 'Git 提交规范与原子提交', category: 'git-workflow' },
40
+ { id: 'k-005', title: '文件锁实现互斥访问', category: 'architecture' },
41
+ ];
42
+ // ══════════════════════════════════════════════════════════════════════════════
43
+ describe('KnowledgeIndexManager — filterByKeyword / filterByCategory', () => {
44
+ let tmpDir;
45
+ let manager;
46
+ beforeEach(() => {
47
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'index-filter-test-'));
48
+ // 创建索引文件
49
+ const evolutionDir = path.join(tmpDir, '.omc', 'axiom', 'evolution');
50
+ fs.mkdirSync(evolutionDir, { recursive: true });
51
+ fs.writeFileSync(path.join(evolutionDir, 'knowledge_base.md'), makeKnowledgeBase(SAMPLE_ENTRIES), 'utf8');
52
+ manager = new KnowledgeIndexManager(tmpDir);
53
+ });
54
+ afterEach(() => {
55
+ fs.rmSync(tmpDir, { recursive: true, force: true });
56
+ });
57
+ // ─── 1. loadIndex 全量返回 ─────────────────────────────────────────────────
58
+ it('loadIndex 返回全量 5 条', async () => {
59
+ const entries = await manager.loadIndex();
60
+ expect(entries).toHaveLength(5);
61
+ });
62
+ // ─── 2. filterByKeyword:关键词匹配 title ───────────────────────────────────
63
+ it('--filter typescript 返回 title 含 typescript 的条目', async () => {
64
+ const result = await manager.filterByKeyword('typescript');
65
+ // k-001 和 k-003 的 title 含 TypeScript,category 也是 typescript
66
+ expect(result.entries.length).toBeGreaterThanOrEqual(2);
67
+ expect(result.entries.every(e => e.title.toLowerCase().includes('typescript') || e.category.toLowerCase().includes('typescript'))).toBe(true);
68
+ });
69
+ it('--filter 返回的 total 等于全量条目数', async () => {
70
+ const result = await manager.filterByKeyword('typescript');
71
+ expect(result.total).toBe(5);
72
+ });
73
+ // ─── 3. filterByKeyword:关键词匹配 category ──────────────────────────────
74
+ it('--filter architecture 匹配 category=architecture 的条目', async () => {
75
+ const result = await manager.filterByKeyword('architecture');
76
+ expect(result.entries).toHaveLength(2);
77
+ expect(result.entries.map(e => e.id).sort()).toEqual(['k-002', 'k-005']);
78
+ });
79
+ // ─── 4. filterByKeyword:大小写不敏感 ────────────────────────────────────
80
+ it('--filter TypeScript(大写)与 --filter typescript 结果相同', async () => {
81
+ const lower = await manager.filterByKeyword('typescript');
82
+ const upper = await manager.filterByKeyword('TypeScript');
83
+ expect(lower.entries.map(e => e.id).sort()).toEqual(upper.entries.map(e => e.id).sort());
84
+ });
85
+ it('--filter ARCHITECTURE(全大写)匹配正常', async () => {
86
+ const result = await manager.filterByKeyword('ARCHITECTURE');
87
+ expect(result.entries).toHaveLength(2);
88
+ });
89
+ // ─── 5. filterByKeyword:空结果 ────────────────────────────────────────────
90
+ it('--filter 不存在的关键词返回空数组,total 为全量', async () => {
91
+ const result = await manager.filterByKeyword('python');
92
+ expect(result.entries).toHaveLength(0);
93
+ expect(result.total).toBe(5);
94
+ });
95
+ // ─── 6. filterByKeyword:超 256 字符抛出 Error ────────────────────────────
96
+ it('--filter 超过 256 字符抛出 Error', async () => {
97
+ const longKeyword = 'a'.repeat(257);
98
+ await expect(manager.filterByKeyword(longKeyword)).rejects.toThrow('256');
99
+ });
100
+ it('--filter 恰好 256 字符不抛出', async () => {
101
+ const keyword = 'a'.repeat(256);
102
+ await expect(manager.filterByKeyword(keyword)).resolves.toBeDefined();
103
+ });
104
+ // ─── 7. filterByCategory:精确匹配 ───────────────────────────────────────
105
+ it('--category typescript 只返回 category=typescript 的条目', async () => {
106
+ const result = await manager.filterByCategory('typescript');
107
+ expect(result.entries).toHaveLength(2);
108
+ expect(result.entries.every(e => e.category === 'typescript')).toBe(true);
109
+ expect(result.entries.map(e => e.id).sort()).toEqual(['k-001', 'k-003']);
110
+ });
111
+ it('--category architecture 只返回 category=architecture 的条目', async () => {
112
+ const result = await manager.filterByCategory('architecture');
113
+ expect(result.entries).toHaveLength(2);
114
+ expect(result.entries.map(e => e.id).sort()).toEqual(['k-002', 'k-005']);
115
+ });
116
+ // ─── 8. filterByCategory:大小写不敏感 ──────────────────────────────────
117
+ it('--category TypeScript(混合大小写)与 --category typescript 结果相同', async () => {
118
+ const lower = await manager.filterByCategory('typescript');
119
+ const mixed = await manager.filterByCategory('TypeScript');
120
+ expect(lower.entries.map(e => e.id).sort()).toEqual(mixed.entries.map(e => e.id).sort());
121
+ });
122
+ // ─── 9. filterByCategory:精确匹配不含部分匹配 ───────────────────────────
123
+ it('--category type(只是 typescript 的前缀)不返回 typescript 条目', async () => {
124
+ const result = await manager.filterByCategory('type');
125
+ expect(result.entries).toHaveLength(0);
126
+ });
127
+ // ─── 10. filterByCategory:空结果 ─────────────────────────────────────────
128
+ it('--category 不存在的分类返回空数组,total 为全量', async () => {
129
+ const result = await manager.filterByCategory('nonexistent');
130
+ expect(result.entries).toHaveLength(0);
131
+ expect(result.total).toBe(5);
132
+ });
133
+ // ─── 11. filterByCategory:total 字段 ─────────────────────────────────────
134
+ it('filterByCategory 的 total 等于全量条目数', async () => {
135
+ const result = await manager.filterByCategory('git-workflow');
136
+ expect(result.entries).toHaveLength(1);
137
+ expect(result.total).toBe(5);
138
+ });
139
+ // ─── 12. filterByKeyword 匹配 title 与 category 的联合 ──────────────────
140
+ it('--filter 原子 同时匹配 title 含"原子"的条目', async () => {
141
+ const result = await manager.filterByKeyword('原子');
142
+ // k-002 title 含"原子",k-004 title 含"原子"
143
+ expect(result.entries.map(e => e.id)).toContain('k-002');
144
+ expect(result.entries.map(e => e.id)).toContain('k-004');
145
+ });
146
+ });
147
+ //# sourceMappingURL=index-manager-filter.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-manager-filter.test.js","sourceRoot":"","sources":["../../../../src/hooks/learner/__tests__/index-manager-filter.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * learning-queue-parser.test.ts
3
+ *
4
+ * 覆盖 T-012 验收标准(解析器部分):
5
+ * - 多行块格式解析
6
+ * - 旧表格格式兼容
7
+ * - 字段映射正确
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=learning-queue-parser.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learning-queue-parser.test.d.ts","sourceRoot":"","sources":["../../../../src/hooks/learner/__tests__/learning-queue-parser.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
@@ -0,0 +1,131 @@
1
+ /**
2
+ * learning-queue-parser.test.ts
3
+ *
4
+ * 覆盖 T-012 验收标准(解析器部分):
5
+ * - 多行块格式解析
6
+ * - 旧表格格式兼容
7
+ * - 字段映射正确
8
+ */
9
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
10
+ import * as fs from 'fs';
11
+ import * as os from 'os';
12
+ import * as path from 'path';
13
+ import { LearningQueue } from '../learning-queue.js';
14
+ // ── 测试数据 ─────────────────────────────────────────────────────────────────
15
+ const BLOCK_QUEUE = `# 学习队列
16
+
17
+ ### LQ-001: task-completion
18
+ - 优先级: P1
19
+ - 来源类型: task_completion
20
+ - 状态: pending
21
+ - 添加时间: 2026-01-10
22
+ - 内容: 完成了某个任务
23
+
24
+ ### LQ-002: error-fix
25
+ - 优先级: P2
26
+ - 来源类型: error_fix
27
+ - 状态: done
28
+ - 添加时间: 2026-01-09
29
+ - 内容: 修复了某个错误
30
+
31
+ ### LQ-003: session-insight
32
+ - 优先级: P0
33
+ - 来源类型: session
34
+ - 状态: processing
35
+ - 添加时间: 2026-01-11
36
+ - 内容: 会话洞察
37
+ `;
38
+ const TABLE_QUEUE = `# 学习队列(旧格式)
39
+
40
+ | ID | SourceType | SourceId | Priority | Created | Status | Description |
41
+ |---|---|---|---|---|---|---|
42
+ | Q-001 | task | task-1 | P1 | 2026-01-10 | pending | desc1 |
43
+ | Q-002 | error | error-1 | P2 | 2026-01-09 | done | desc2 |
44
+ `;
45
+ // ══════════════════════════════════════════════════════════════════════════════
46
+ describe('LearningQueue — 解析器', () => {
47
+ let tmpDir;
48
+ let queueFile;
49
+ beforeEach(() => {
50
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'lq-parser-test-'));
51
+ const evolutionDir = path.join(tmpDir, '.omc', 'axiom', 'evolution');
52
+ fs.mkdirSync(evolutionDir, { recursive: true });
53
+ queueFile = path.join(evolutionDir, 'learning_queue.md');
54
+ });
55
+ afterEach(() => {
56
+ fs.rmSync(tmpDir, { recursive: true, force: true });
57
+ });
58
+ // ─── 块格式解析 ────────────────────────────────────────────────────────────
59
+ it('块格式:getStats 返回正确的 total/pending/done 数量', async () => {
60
+ fs.writeFileSync(queueFile, BLOCK_QUEUE, 'utf8');
61
+ const lq = new LearningQueue(tmpDir);
62
+ const stats = await lq.getStats();
63
+ expect(stats.total).toBe(3);
64
+ expect(stats.pending).toBe(1);
65
+ expect(stats.done).toBe(1);
66
+ });
67
+ it('块格式:getNextBatch 只返回 pending 条目', async () => {
68
+ fs.writeFileSync(queueFile, BLOCK_QUEUE, 'utf8');
69
+ const lq = new LearningQueue(tmpDir);
70
+ const batch = await lq.getNextBatch(5);
71
+ expect(batch).toHaveLength(1);
72
+ expect(batch[0]?.id).toBe('LQ-001');
73
+ expect(batch[0]?.status).toBe('pending');
74
+ });
75
+ it('块格式:updateStatus 将 pending 改为 done', async () => {
76
+ fs.writeFileSync(queueFile, BLOCK_QUEUE, 'utf8');
77
+ const lq = new LearningQueue(tmpDir);
78
+ await lq.updateStatus('LQ-001', 'done');
79
+ const stats = await lq.getStats();
80
+ expect(stats.pending).toBe(0);
81
+ expect(stats.done).toBe(2);
82
+ });
83
+ // ─── 字段映射正确 ──────────────────────────────────────────────────────────
84
+ it('块格式字段映射:priority/created/status/description/sourceType 均正确', async () => {
85
+ fs.writeFileSync(queueFile, BLOCK_QUEUE, 'utf8');
86
+ const lq = new LearningQueue(tmpDir);
87
+ const batch = await lq.getNextBatch(1);
88
+ const item = batch[0];
89
+ expect(item?.priority).toBe('P1');
90
+ expect(item?.created).toBe('2026-01-10');
91
+ expect(item?.status).toBe('pending');
92
+ expect(item?.description).toBe('完成了某个任务');
93
+ expect(item?.sourceType).toBe('task_completion');
94
+ });
95
+ it('块格式:priority 无效值回退到 P2', async () => {
96
+ const badPriorityBlock = `# 学习队列\n\n### LQ-X01: bad\n- 优先级: P9\n- 来源类型: test\n- 状态: pending\n- 添加时间: 2026-01-01\n- 内容: x\n`;
97
+ fs.writeFileSync(queueFile, badPriorityBlock, 'utf8');
98
+ const lq = new LearningQueue(tmpDir);
99
+ const batch = await lq.getNextBatch(1);
100
+ expect(batch[0]?.priority).toBe('P2');
101
+ });
102
+ // ─── 旧表格格式兼容 ────────────────────────────────────────────────────────
103
+ it('旧表格格式:getStats 正确解析(降级兼容)', async () => {
104
+ fs.writeFileSync(queueFile, TABLE_QUEUE, 'utf8');
105
+ const lq = new LearningQueue(tmpDir);
106
+ const stats = await lq.getStats();
107
+ expect(stats.total).toBe(2);
108
+ expect(stats.pending).toBe(1);
109
+ expect(stats.done).toBe(1);
110
+ });
111
+ it('旧表格格式:getNextBatch 返回 pending 条目', async () => {
112
+ fs.writeFileSync(queueFile, TABLE_QUEUE, 'utf8');
113
+ const lq = new LearningQueue(tmpDir);
114
+ const batch = await lq.getNextBatch(5);
115
+ expect(batch).toHaveLength(1);
116
+ expect(batch[0]?.id).toBe('Q-001');
117
+ expect(batch[0]?.priority).toBe('P1');
118
+ });
119
+ // ─── addItem 写入块格式 ────────────────────────────────────────────────────
120
+ it('addItem 在块格式文件中追加新块', async () => {
121
+ fs.writeFileSync(queueFile, BLOCK_QUEUE, 'utf8');
122
+ const lq = new LearningQueue(tmpDir);
123
+ await lq.addItem('session', 'new-item', 'P2', '新条目描述');
124
+ const stats = await lq.getStats();
125
+ expect(stats.total).toBe(4);
126
+ const content = fs.readFileSync(queueFile, 'utf8');
127
+ expect(content).toContain('- 来源类型: session');
128
+ expect(content).toContain('- 内容: 新条目描述');
129
+ });
130
+ });
131
+ //# sourceMappingURL=learning-queue-parser.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learning-queue-parser.test.js","sourceRoot":"","sources":["../../../../src/hooks/learner/__tests__/learning-queue-parser.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * queue-archiver.test.ts
3
+ *
4
+ * 覆盖 T-012 验收标准(归档部分):
5
+ * - done=10 不触发 / done=11 触发
6
+ * - 保留最近 10 条 done
7
+ * - pending/in-progress 不受影响
8
+ * - 归档文件 ID 无重复
9
+ * - 手动触发 archiveQueue() 正常工作
10
+ * - 归档 > 5000 行 warning
11
+ */
12
+ export {};
13
+ //# sourceMappingURL=queue-archiver.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue-archiver.test.d.ts","sourceRoot":"","sources":["../../../../src/hooks/learner/__tests__/queue-archiver.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
@@ -0,0 +1,162 @@
1
+ /**
2
+ * queue-archiver.test.ts
3
+ *
4
+ * 覆盖 T-012 验收标准(归档部分):
5
+ * - done=10 不触发 / done=11 触发
6
+ * - 保留最近 10 条 done
7
+ * - pending/in-progress 不受影响
8
+ * - 归档文件 ID 无重复
9
+ * - 手动触发 archiveQueue() 正常工作
10
+ * - 归档 > 5000 行 warning
11
+ */
12
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
13
+ import * as fs from 'fs';
14
+ import * as os from 'os';
15
+ import * as path from 'path';
16
+ import { QueueArchiver } from '../queue-archiver.js';
17
+ // ── 辅助函数 ──────────────────────────────────────────────────────────────────
18
+ function makeBlock(id, status, date, priority = 'P2') {
19
+ return [
20
+ `### ${id}: title-${id}`,
21
+ `- 优先级: ${priority}`,
22
+ `- 来源类型: session`,
23
+ `- 状态: ${status}`,
24
+ `- 添加时间: ${date}`,
25
+ `- 内容: 内容-${id}`,
26
+ ].join('\n');
27
+ }
28
+ function makeQueueFile(blocks) {
29
+ return `# 学习队列\n\n` + blocks.join('\n\n') + '\n';
30
+ }
31
+ function makeId(n) {
32
+ return `LQ-${String(n).padStart(3, '0')}`;
33
+ }
34
+ function makeDate(n) {
35
+ // 生成 2026-01-01 ~ 2026-01-31 格式日期(n 从 1 开始)
36
+ const month = Math.ceil(n / 28);
37
+ const day = ((n - 1) % 28) + 1;
38
+ return `2026-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
39
+ }
40
+ // ══════════════════════════════════════════════════════════════════════════════
41
+ describe('QueueArchiver', () => {
42
+ let tmpDir;
43
+ let evolutionDir;
44
+ let queueFile;
45
+ let archiveFile;
46
+ beforeEach(() => {
47
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'queue-archiver-test-'));
48
+ evolutionDir = path.join(tmpDir, '.omc', 'axiom', 'evolution');
49
+ fs.mkdirSync(evolutionDir, { recursive: true });
50
+ queueFile = path.join(evolutionDir, 'learning_queue.md');
51
+ archiveFile = path.join(evolutionDir, 'learning_queue_archive.md');
52
+ });
53
+ afterEach(() => {
54
+ fs.rmSync(tmpDir, { recursive: true, force: true });
55
+ });
56
+ // ─── 阈值:done=10 不触发 ──────────────────────────────────────────────────
57
+ it('done=10 不触发归档', async () => {
58
+ const blocks = Array.from({ length: 10 }, (_, i) => makeBlock(makeId(i + 1), 'done', makeDate(i + 1)));
59
+ fs.writeFileSync(queueFile, makeQueueFile(blocks), 'utf8');
60
+ const archiver = new QueueArchiver(tmpDir);
61
+ const result = await archiver.archive();
62
+ expect(result.archived).toBe(0);
63
+ expect(fs.existsSync(archiveFile)).toBe(false);
64
+ });
65
+ // ─── 阈值:done=11 触发,归档 1 条 ────────────────────────────────────────
66
+ it('done=11 触发归档,archived=1 kept=10', async () => {
67
+ const blocks = Array.from({ length: 11 }, (_, i) => makeBlock(makeId(i + 1), 'done', makeDate(i + 1)));
68
+ fs.writeFileSync(queueFile, makeQueueFile(blocks), 'utf8');
69
+ const archiver = new QueueArchiver(tmpDir);
70
+ const result = await archiver.archive();
71
+ expect(result.archived).toBe(1);
72
+ expect(result.kept).toBe(10);
73
+ expect(result.message).toContain('已移动 1 条');
74
+ expect(fs.existsSync(archiveFile)).toBe(true);
75
+ });
76
+ // ─── 保留最近 10 条 ────────────────────────────────────────────────────────
77
+ it('done=15 归档最旧 5 条,主文件保留最新 10 条', async () => {
78
+ const blocks = Array.from({ length: 15 }, (_, i) => makeBlock(makeId(i + 1), 'done', makeDate(i + 1)));
79
+ fs.writeFileSync(queueFile, makeQueueFile(blocks), 'utf8');
80
+ const archiver = new QueueArchiver(tmpDir);
81
+ const result = await archiver.archive();
82
+ expect(result.archived).toBe(5);
83
+ expect(result.kept).toBe(10);
84
+ // 最旧 5 条(LQ-001~LQ-005)在归档文件
85
+ const archiveContent = fs.readFileSync(archiveFile, 'utf8');
86
+ expect(archiveContent).toContain('### LQ-001:');
87
+ expect(archiveContent).toContain('### LQ-005:');
88
+ expect(archiveContent).not.toContain('### LQ-006:');
89
+ // 主文件只有 LQ-006~LQ-015
90
+ const mainContent = fs.readFileSync(queueFile, 'utf8');
91
+ expect(mainContent).toContain('### LQ-006:');
92
+ expect(mainContent).toContain('### LQ-015:');
93
+ expect(mainContent).not.toContain('### LQ-001:');
94
+ });
95
+ // ─── pending/in-progress 不受影响 ─────────────────────────────────────────
96
+ it('pending 和 processing 条目不被归档', async () => {
97
+ const doneBlocks = Array.from({ length: 11 }, (_, i) => makeBlock(makeId(i + 1), 'done', makeDate(i + 1)));
98
+ const pendingBlock = makeBlock('LQ-P01', 'pending', '2026-02-01');
99
+ const processingBlock = makeBlock('LQ-R01', 'processing', '2026-02-02');
100
+ fs.writeFileSync(queueFile, makeQueueFile([...doneBlocks, pendingBlock, processingBlock]), 'utf8');
101
+ const archiver = new QueueArchiver(tmpDir);
102
+ const result = await archiver.archive();
103
+ expect(result.archived).toBe(1);
104
+ const mainContent = fs.readFileSync(queueFile, 'utf8');
105
+ expect(mainContent).toContain('### LQ-P01:');
106
+ expect(mainContent).toContain('### LQ-R01:');
107
+ });
108
+ // ─── 归档文件 ID 无重复 ────────────────────────────────────────────────────
109
+ it('二次调用不重复写入已归档的 ID', async () => {
110
+ const blocks = Array.from({ length: 11 }, (_, i) => makeBlock(makeId(i + 1), 'done', makeDate(i + 1)));
111
+ fs.writeFileSync(queueFile, makeQueueFile(blocks), 'utf8');
112
+ const archiver = new QueueArchiver(tmpDir);
113
+ // 第一次归档(归档 LQ-001)
114
+ await archiver.archive();
115
+ // 重建队列,再次包含同一批条目(模拟 ID 已在归档中)
116
+ fs.writeFileSync(queueFile, makeQueueFile(blocks), 'utf8');
117
+ await archiver.archive();
118
+ // 归档文件中 LQ-001 只出现一次
119
+ const archiveContent = fs.readFileSync(archiveFile, 'utf8');
120
+ const count = (archiveContent.match(/### LQ-001:/g) ?? []).length;
121
+ expect(count).toBe(1);
122
+ });
123
+ // ─── 队列文件不存在 ────────────────────────────────────────────────────────
124
+ it('队列文件不存在时返回 archived=0 且不报错', async () => {
125
+ const archiver = new QueueArchiver(tmpDir);
126
+ const result = await archiver.archive();
127
+ expect(result.archived).toBe(0);
128
+ expect(result.kept).toBe(0);
129
+ });
130
+ // ─── message 格式 ─────────────────────────────────────────────────────────
131
+ it('归档 message 包含正确移动数量', async () => {
132
+ const blocks = Array.from({ length: 12 }, (_, i) => makeBlock(makeId(i + 1), 'done', makeDate(i + 1)));
133
+ fs.writeFileSync(queueFile, makeQueueFile(blocks), 'utf8');
134
+ const archiver = new QueueArchiver(tmpDir);
135
+ const result = await archiver.archive();
136
+ expect(result.message).toMatch(/已移动 2 条 done 条目至 learning_queue_archive\.md/);
137
+ });
138
+ // ─── 归档 > 5000 行 warning ────────────────────────────────────────────────
139
+ it('归档文件超过 5000 行时输出 console.warn', async () => {
140
+ // 预先写入大量内容到归档文件(超过 5000 行)
141
+ fs.writeFileSync(archiveFile, 'x\n'.repeat(5002), 'utf8');
142
+ const blocks = Array.from({ length: 11 }, (_, i) => makeBlock(makeId(i + 1), 'done', makeDate(i + 1)));
143
+ fs.writeFileSync(queueFile, makeQueueFile(blocks), 'utf8');
144
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
145
+ const archiver = new QueueArchiver(tmpDir);
146
+ await archiver.archive();
147
+ expect(warnSpy.mock.calls.some(args => typeof args[0] === 'string' && args[0].includes('5000'))).toBe(true);
148
+ warnSpy.mockRestore();
149
+ });
150
+ // ─── 连续两次归档(锁释放验证)────────────────────────────────────────────
151
+ it('连续两次调用 archive() 均能正常返回(锁被正确释放)', async () => {
152
+ const blocks = Array.from({ length: 11 }, (_, i) => makeBlock(makeId(i + 1), 'done', makeDate(i + 1)));
153
+ fs.writeFileSync(queueFile, makeQueueFile(blocks), 'utf8');
154
+ const archiver = new QueueArchiver(tmpDir);
155
+ const r1 = await archiver.archive();
156
+ expect(r1.archived).toBe(1);
157
+ // 第二次:done 条目已减至 10,不再触发
158
+ const r2 = await archiver.archive();
159
+ expect(r2.archived).toBe(0);
160
+ });
161
+ });
162
+ //# sourceMappingURL=queue-archiver.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue-archiver.test.js","sourceRoot":"","sources":["../../../../src/hooks/learner/__tests__/queue-archiver.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * reflection-archiver.test.ts
3
+ *
4
+ * 覆盖:
5
+ * - 10 条不触发归档(archived=0, kept=10)
6
+ * - 11 条触发归档(archived=1, kept=10)
7
+ * - 归档文件内容正确(被移走的块追加到 archive 文件)
8
+ * - 原子写回主文件(主文件只保留 MAX_WINDOW=10 条)
9
+ * - 主文件不存在时返回 {archived:0, kept:0}
10
+ * - 归档文件超过 5000 行时 warning 字段存在
11
+ * - 锁竞争:并发两次调用同一 baseDir 不损坏数据
12
+ */
13
+ export {};
14
+ //# sourceMappingURL=reflection-archiver.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reflection-archiver.test.d.ts","sourceRoot":"","sources":["../../../../src/hooks/learner/__tests__/reflection-archiver.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}