@dommaker/harness 0.13.3 → 0.16.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 (117) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/bin/harness-knowledge-check.js +38 -23
  3. package/bin/harness-knowledge-track.js +30 -4
  4. package/bin/harness.js +24 -1
  5. package/dist/cli/commands/index.d.ts +1 -1
  6. package/dist/cli/commands/index.d.ts.map +1 -1
  7. package/dist/cli/commands/index.js +4 -1
  8. package/dist/cli/commands/index.js.map +1 -1
  9. package/dist/cli/commands/knowledge.d.ts +21 -0
  10. package/dist/cli/commands/knowledge.d.ts.map +1 -1
  11. package/dist/cli/commands/knowledge.js +160 -9
  12. package/dist/cli/commands/knowledge.js.map +1 -1
  13. package/dist/cli/commands/release.d.ts.map +1 -1
  14. package/dist/cli/commands/release.js +43 -6
  15. package/dist/cli/commands/release.js.map +1 -1
  16. package/dist/core/constraints/checker.js +1 -1
  17. package/dist/core/constraints/checker.js.map +1 -1
  18. package/dist/core/constraints/definitions.d.ts.map +1 -1
  19. package/dist/core/constraints/definitions.js +34 -26
  20. package/dist/core/constraints/definitions.js.map +1 -1
  21. package/dist/index.d.ts +3 -1
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +6 -2
  24. package/dist/index.js.map +1 -1
  25. package/dist/knowledge/audit.d.ts +76 -0
  26. package/dist/knowledge/audit.d.ts.map +1 -0
  27. package/dist/knowledge/audit.js +566 -0
  28. package/dist/knowledge/audit.js.map +1 -0
  29. package/dist/knowledge/doctor.d.ts +1 -1
  30. package/dist/knowledge/doctor.d.ts.map +1 -1
  31. package/dist/knowledge/import.d.ts +1 -1
  32. package/dist/knowledge/import.d.ts.map +1 -1
  33. package/dist/knowledge/import.js +3 -0
  34. package/dist/knowledge/import.js.map +1 -1
  35. package/dist/knowledge/index.d.ts +7 -2
  36. package/dist/knowledge/index.d.ts.map +1 -1
  37. package/dist/knowledge/index.js +7 -2
  38. package/dist/knowledge/index.js.map +1 -1
  39. package/dist/knowledge/ingest.d.ts +28 -1
  40. package/dist/knowledge/ingest.d.ts.map +1 -1
  41. package/dist/knowledge/ingest.js +150 -5
  42. package/dist/knowledge/ingest.js.map +1 -1
  43. package/dist/knowledge/lifecycle-hooks.d.ts +1 -1
  44. package/dist/knowledge/lifecycle-hooks.d.ts.map +1 -1
  45. package/dist/knowledge/lifecycle-hooks.js +3 -0
  46. package/dist/knowledge/lifecycle-hooks.js.map +1 -1
  47. package/dist/knowledge/lifecycle.d.ts +60 -8
  48. package/dist/knowledge/lifecycle.d.ts.map +1 -1
  49. package/dist/knowledge/lifecycle.js +213 -52
  50. package/dist/knowledge/lifecycle.js.map +1 -1
  51. package/dist/knowledge/lint.d.ts +1 -1
  52. package/dist/knowledge/lint.d.ts.map +1 -1
  53. package/dist/knowledge/lint.js +44 -3
  54. package/dist/knowledge/lint.js.map +1 -1
  55. package/dist/knowledge/migration.d.ts +25 -0
  56. package/dist/knowledge/migration.d.ts.map +1 -0
  57. package/dist/knowledge/migration.js +96 -0
  58. package/dist/knowledge/migration.js.map +1 -0
  59. package/dist/knowledge/query.d.ts +30 -2
  60. package/dist/knowledge/query.d.ts.map +1 -1
  61. package/dist/knowledge/query.js +58 -0
  62. package/dist/knowledge/query.js.map +1 -1
  63. package/dist/knowledge/reference-tracker.d.ts +1 -1
  64. package/dist/knowledge/reference-tracker.d.ts.map +1 -1
  65. package/dist/knowledge/store.d.ts +50 -3
  66. package/dist/knowledge/store.d.ts.map +1 -1
  67. package/dist/knowledge/store.js +111 -9
  68. package/dist/knowledge/store.js.map +1 -1
  69. package/dist/knowledge/types.d.ts +43 -1
  70. package/dist/knowledge/types.d.ts.map +1 -1
  71. package/dist/knowledge/types.js +1 -0
  72. package/dist/knowledge/types.js.map +1 -1
  73. package/dist/monitoring/knowledge-evolver.d.ts +1 -1
  74. package/dist/monitoring/knowledge-evolver.d.ts.map +1 -1
  75. package/dist/types/constraint.d.ts +1 -1
  76. package/dist/types/constraint.d.ts.map +1 -1
  77. package/package.json +1 -1
  78. package/src/__tests__/checker.test.ts +4 -4
  79. package/src/cli/commands/__tests__/knowledge.test.ts +167 -0
  80. package/src/cli/commands/index.ts +1 -1
  81. package/src/cli/commands/knowledge.ts +176 -5
  82. package/src/cli/commands/release.ts +44 -6
  83. package/src/context/__tests__/knowledge-injector.test.ts +4 -1
  84. package/src/core/constraints/checker.ts +1 -1
  85. package/src/core/constraints/definitions.ts +35 -27
  86. package/src/dashboard/__tests__/data.test.ts +3 -0
  87. package/src/dashboard/__tests__/stats.test.ts +3 -0
  88. package/src/index.ts +3 -1
  89. package/src/knowledge/CONTEXT.md +29 -7
  90. package/src/knowledge/__tests__/audit.test.ts +598 -0
  91. package/src/knowledge/__tests__/doctor.test.ts +28 -1
  92. package/src/knowledge/__tests__/import.test.ts +1 -1
  93. package/src/knowledge/__tests__/ingest.test.ts +320 -1
  94. package/src/knowledge/__tests__/lifecycle-hooks.test.ts +4 -1
  95. package/src/knowledge/__tests__/lifecycle.test.ts +656 -3
  96. package/src/knowledge/__tests__/lint.test.ts +52 -1
  97. package/src/knowledge/__tests__/migration.test.ts +115 -0
  98. package/src/knowledge/__tests__/query.test.ts +87 -1
  99. package/src/knowledge/__tests__/reference-tracker.test.ts +4 -1
  100. package/src/knowledge/__tests__/store.test.ts +208 -1
  101. package/src/knowledge/audit.ts +641 -0
  102. package/src/knowledge/doctor.ts +1 -1
  103. package/src/knowledge/import.ts +4 -1
  104. package/src/knowledge/index.ts +7 -2
  105. package/src/knowledge/ingest.ts +170 -6
  106. package/src/knowledge/lifecycle-hooks.ts +4 -1
  107. package/src/knowledge/lifecycle.ts +219 -50
  108. package/src/knowledge/lint.ts +45 -4
  109. package/src/knowledge/migration.ts +73 -0
  110. package/src/knowledge/query.ts +72 -1
  111. package/src/knowledge/reference-tracker.ts +1 -1
  112. package/src/knowledge/store.ts +125 -8
  113. package/src/knowledge/types.ts +50 -1
  114. package/src/monitoring/__tests__/knowledge-doctor.test.ts +3 -0
  115. package/src/monitoring/__tests__/knowledge-evolver.test.ts +3 -0
  116. package/src/monitoring/knowledge-evolver.ts +1 -1
  117. package/src/types/constraint.ts +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,41 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
6
6
 
7
+ ## [0.16.0] - 2026-06-10
8
+
9
+ ### Changed
10
+ - **prefer_worktree demoted to guideline**: `prefer_worktree` moved from iron_law to guideline severity — worktree usage is now recommended, not enforced
11
+ - **KnowledgeStore interface extracted**: `FileKnowledgeStore` implements `KnowledgeStore` interface, enabling mock/testing and future alternative implementations
12
+
13
+ ## [0.15.0] - 2026-06-07
14
+
15
+ ### Changed
16
+ - Internal release (constraint tier adjustment prep)
17
+
18
+ ## [0.14.0] - 2026-06-04
19
+
20
+ ### Added
21
+ - **ConsumptionMode + KnowledgeOrigin types** (AS-021 P1): `rule | context | signal | reference` 消费模式,`system | agent | human | external` 知识来源
22
+ - **Per-mode lifecycle** (AS-021 P2): rule/context/signal 三条独立生命周期路径
23
+ - **queryByMode + consume()** (AS-021 P3): 按 consumptionMode 查询 + 消费时 recordReference
24
+ - **External content sanitization** (AS-021 P4): `ingestExternal()` 剥离 prompt injection 模式 + 长度限制
25
+ - **Migration script + CLI** (AS-021 P5): `harness knowledge migrate` 旧条目自动标记 consumptionMode
26
+ - **6-dimension quality audit engine**: `harness knowledge audit [--fix] [--dry-run]`,健康分 + 自动修复
27
+ - **KR4 snapshot mechanism**: 每日 index.json 快照 + 30 天存活率统计
28
+ - **GAP-11 promotion content quality gate**: draft→verified 要求 content ≥ 50 字符
29
+ - **Semantic dedup + test ID interception**: KnowledgeIngest 去重增强
30
+ - **Execution success rate tracking**: Path C 自动晋升依据
31
+ - **Human/auto contributor classification**: 晋升来源区分
32
+ - **D6 flywheel stats**: `harness knowledge stats` 展示飞轮指标
33
+ - **hooks → Agent Event Protocol API** (B9-016): 通用 hook 管线暴露为 API
34
+
35
+ ### Fixed
36
+ - **飞轮质量审计 5 项根因修复**: 噪音治理 + 资源优化
37
+ - **B12 噪音治理**: 低质量条目过滤 + 资源优化
38
+ - **E3 findFile 碰撞修复**: 文件查找哈希碰撞
39
+ - **`no_delete_without_context` 增强**: 零引用 ≠ 无价值
40
+ - **undefined tags/applicablePhases guard**: matchesFilter 空值保护
41
+
7
42
  ## [0.13.0] - 2026-05-26
8
43
 
9
44
  ### Breaking
@@ -14,7 +14,6 @@ const path = require('path');
14
14
  const os = require('os');
15
15
  const STATE_FILE = '/tmp/claude-knowledge-capture-state.json';
16
16
  const LOG_FILE = '/tmp/claude-knowledge-hooks.log';
17
- const EVENTS_FILE = path.join(os.homedir(), 'events', 'studio.jsonl');
18
17
  const UNIQUE_DIR_THRESHOLD = 10;
19
18
 
20
19
  function log(level, message, data) {
@@ -79,30 +78,46 @@ try {
79
78
 
80
79
  console.log(JSON.stringify({ systemMessage: message }));
81
80
  }
82
- // Emit session summary event → events-daemon knowledge extraction pipeline
81
+ // B9-016: POST agent events to Studio API
83
82
  try {
83
+ const events = state.events || [];
84
+ const sessionId = state.sessionId || ('cc-' + Date.now());
84
85
  const now = Date.now();
85
- const durationMs = state.startTime ? now - state.startTime : 0;
86
- const durationMin = Math.round(durationMs / 60000);
87
- const event = {
88
- type: 'session:summary',
89
- sessionType: 'development',
90
- tool: state.tool || 'unknown', // claude | codex | opencode | etc
91
- timestamp: new Date().toISOString(),
92
- durationMs,
93
- durationMin,
94
- deepAnalysis: state.planned || state.explored || state.readDirs.length >= UNIQUE_DIR_THRESHOLD,
95
- knowledgeCaptured: !!state.captured,
96
- readDirsCount: state.readDirs.length,
97
- planned: state.planned || false,
98
- explored: state.explored || false,
99
- sensitiveOpsCount: (state.sensitiveOps || []).filter(op => !op.verified).length,
100
- turnCount: state.turnCount || 0,
101
- };
102
- const dir = path.dirname(EVENTS_FILE);
103
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
104
- fs.appendFileSync(EVENTS_FILE, JSON.stringify(event) + '\n', 'utf-8');
105
- log('info', 'session-summary-emitted', event);
86
+
87
+ // Append session:end event
88
+ events.push({
89
+ sessionId,
90
+ agentId: 'claude-code',
91
+ timestamp: now,
92
+ type: 'session:end',
93
+ payload: {
94
+ success: true,
95
+ durationMs: state.startTime ? now - state.startTime : 0,
96
+ },
97
+ });
98
+
99
+ // Read Studio API URL from env or default
100
+ const studioUrl = process.env.STUDIO_API_URL || 'http://127.0.0.1:13101';
101
+ const token = process.env.STUDIO_API_TOKEN || '';
102
+
103
+ if (events.length > 0 && token) {
104
+ const { execSync } = require('child_process');
105
+ const body = JSON.stringify(events);
106
+ try {
107
+ execSync(
108
+ `curl -s -X POST "${studioUrl}/api/v1/events/agent-events" ` +
109
+ `-H "Content-Type: application/json" ` +
110
+ `-H "Authorization: Bearer ${token}" ` +
111
+ `-d '${body.replace(/'/g, "'\\''")}'`,
112
+ { timeout: 10000, stdio: 'pipe' }
113
+ );
114
+ log('info', 'agent-events-posted', { count: events.length, sessionId });
115
+ } catch (e) {
116
+ log('warn', 'agent-events-post-failed', { error: (e.message || String(e)).slice(0, 200) });
117
+ }
118
+ } else if (events.length > 0 && !token) {
119
+ log('info', 'agent-events-skipped-no-token', { count: events.length });
120
+ }
106
121
  } catch {}
107
122
 
108
123
  // Auto-ingest: scan memory files with ingest:true → call local-rag API
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * PostToolUse hook — track deep analysis signals
3
+ * PostToolUse hook — track deep analysis signals + collect AgentEvents
4
4
  *
5
5
  * Updates state file with:
6
6
  * - planned: EnterPlanMode was called
@@ -8,8 +8,9 @@
8
8
  * - readDirs: Set of unique directories Read was called on
9
9
  * - captured: Write to .harness/knowledge-docs/ or .harness/knowledge/
10
10
  * - turnCount: session turn counter
11
+ * - events: AgentEvent[] (B9-016) — buffered for batch POST on session:end
11
12
  *
12
- * Usage: PostToolUse hook with matcher "EnterPlanMode|Agent|Read|Write|Write"
13
+ * Usage: PostToolUse hook with matcher "EnterPlanMode|Agent|Read|Write|Edit|Bash"
13
14
  */
14
15
 
15
16
  const fs = require('fs');
@@ -47,7 +48,9 @@ function loadState() {
47
48
  return JSON.parse(fs.readFileSync(STATE_FILE, 'utf-8'));
48
49
  }
49
50
  } catch {}
50
- return { planned: false, explored: false, readDirs: [], captured: false };
51
+ // B9-016: generate sessionId for this Claude Code session
52
+ const sessionId = 'cc-' + Date.now() + '-' + Math.random().toString(36).slice(2, 8);
53
+ return { planned: false, explored: false, readDirs: [], captured: false, sessionId, events: [], startTime: Date.now() };
51
54
  }
52
55
 
53
56
  function updateState(state, event) {
@@ -75,13 +78,36 @@ function updateState(state, event) {
75
78
  }
76
79
  }
77
80
 
78
- if (toolName === 'Write') {
81
+ if (toolName === 'Write' || toolName === 'Edit') {
79
82
  const input = event.tool_input || {};
80
83
  const filePath = input.file_path || '';
81
84
  if (filePath.includes('.harness/knowledge-docs/') || filePath.includes('.harness/knowledge/')) {
82
85
  state.captured = true;
83
86
  log('info', 'captured', { file: filePath });
84
87
  }
88
+ // B9-016: collect file:change event
89
+ if (filePath && !filePath.includes('.harness/')) {
90
+ state.events.push({
91
+ sessionId: state.sessionId,
92
+ agentId: 'claude-code',
93
+ timestamp: Date.now(),
94
+ type: 'file:change',
95
+ payload: { path: filePath, action: toolName === 'Write' ? 'create' : 'modify' },
96
+ });
97
+ }
98
+ }
99
+
100
+ if (toolName === 'Bash') {
101
+ const input = event.tool_input || {};
102
+ const command = input.command || '';
103
+ // B9-016: collect tool:call event
104
+ state.events.push({
105
+ sessionId: state.sessionId,
106
+ agentId: 'claude-code',
107
+ timestamp: Date.now(),
108
+ type: 'tool:call',
109
+ payload: { tool: 'Bash', command: command.slice(0, 200) },
110
+ });
85
111
  }
86
112
  }
87
113
 
package/bin/harness.js CHANGED
@@ -39,6 +39,9 @@ const {
39
39
  knowledgeUpsert,
40
40
  knowledgeSyncStatus,
41
41
  knowledgeSyncRag,
42
+ knowledgeAudit,
43
+ knowledgeSnapshot,
44
+ knowledgeMigrate,
42
45
  failureList,
43
46
  failureStats,
44
47
  failureClear,
@@ -351,7 +354,7 @@ program
351
354
  // ========================================
352
355
  program
353
356
  .command('knowledge [subcommand] [arg]')
354
- .description('知识库管理(list/search/import/decay/stats)')
357
+ .description('知识库管理(list/search/import/decay/stats/audit)')
355
358
  .alias('kb')
356
359
  .option('-p, --project-path <path>', '项目路径')
357
360
  .option('--type <types>', '按类型过滤(逗号分隔)')
@@ -365,6 +368,10 @@ program
365
368
  .option('--content <content>', '知识内容 Markdown(用于 upsert)')
366
369
  .option('--file <path>', '从文件读取内容(用于 upsert)')
367
370
  .option('--source <source>', '知识来源 (analyst/cli/design)', 'cli')
371
+ .option('--fix', '自动修复(用于 audit)', false)
372
+ .option('--dry-run', '只输出报告不修改(用于 audit)', false)
373
+ .option('--threshold <n>', '短内容阈值(字符数,用于 audit)', '50')
374
+ .option('--dir <path>', '知识库目录(覆盖默认路径)')
368
375
  .option('--json', 'JSON 格式输出', false)
369
376
  .action(async (subcommand, arg, options) => {
370
377
  const opts = { projectPath: options.projectPath, json: options.json };
@@ -408,6 +415,22 @@ program
408
415
  source: options.source || 'cli',
409
416
  });
410
417
  break;
418
+ case 'audit':
419
+ case 'a':
420
+ await knowledgeAudit({
421
+ ...opts,
422
+ fix: options.fix,
423
+ dryRun: options.dryRun,
424
+ threshold: options.threshold,
425
+ dir: options.dir,
426
+ });
427
+ break;
428
+ case 'snapshot':
429
+ knowledgeSnapshot({ ...opts, dir: options.dir });
430
+ break;
431
+ case 'migrate':
432
+ knowledgeMigrate({ ...opts, dir: options.dir });
433
+ break;
411
434
  default:
412
435
  // 无子命令时显示帮助
413
436
  if (!subcommand) {
@@ -16,7 +16,7 @@ export { contract, validateSchema, type ContractOptions } from './contract';
16
16
  export { review, reviewStatus, type ReviewOptions } from './review';
17
17
  export { executeCommand, type CommandCheckOptions } from './command';
18
18
  export { syncDocs, type SyncDocsOptions } from './sync-docs';
19
- export { knowledgeList, knowledgeSearch, knowledgeImport, knowledgeDecay, knowledgeStats, knowledgeUpsert, knowledgeSyncStatus, knowledgeSyncRag, type KnowledgeOptions, type KnowledgeUpsertOptions } from './knowledge';
19
+ export { knowledgeList, knowledgeSearch, knowledgeImport, knowledgeDecay, knowledgeStats, knowledgeUpsert, knowledgeSyncStatus, knowledgeSyncRag, knowledgeAudit, knowledgeSnapshot, knowledgeMigrate, type KnowledgeOptions, type KnowledgeUpsertOptions } from './knowledge';
20
20
  export { failureList, failureStats, failureClear, type FailureOptions } from './failure';
21
21
  export { postevalPlan, type PostEvalPlanOptions } from './posteval-plan';
22
22
  export { release, type ReleaseOptions } from './release';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAC1G,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,KAAK,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACrF,OAAO,EAAE,IAAI,EAAE,KAAK,WAAW,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,EAAE,IAAI,EAAE,KAAK,WAAW,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,KAAK,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAC/E,OAAO,EAAE,UAAU,EAAE,sBAAsB,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC1F,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAC1E,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,WAAW,CAAC;AACrE,OAAO,EAAE,QAAQ,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,eAAe,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,KAAK,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAC1N,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AACzF,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAClF,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AACnF,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAC1G,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,KAAK,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACrF,OAAO,EAAE,IAAI,EAAE,KAAK,WAAW,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,EAAE,IAAI,EAAE,KAAK,WAAW,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,KAAK,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAC/E,OAAO,EAAE,UAAU,EAAE,sBAAsB,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC1F,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAC1E,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,WAAW,CAAC;AACrE,OAAO,EAAE,QAAQ,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,eAAe,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,cAAc,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,KAAK,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAC/Q,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AACzF,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAClF,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AACnF,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC"}
@@ -3,7 +3,7 @@
3
3
  * CLI 命令导出
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.getConstraintsMeta = exports.constraints = exports.updateUserModel = exports.analyzeSessions = exports.release = exports.postevalPlan = exports.failureClear = exports.failureStats = exports.failureList = exports.knowledgeSyncRag = exports.knowledgeSyncStatus = exports.knowledgeUpsert = exports.knowledgeStats = exports.knowledgeDecay = exports.knowledgeImport = exports.knowledgeSearch = exports.knowledgeList = exports.syncDocs = exports.executeCommand = exports.reviewStatus = exports.review = exports.validateSchema = exports.contract = exports.auditDetails = exports.security = exports.performance = exports.listAcceptanceCriteria = exports.acceptance = exports.listSpecTypes = exports.specValidate = exports.flow = exports.status = exports.report = exports.init = exports.checkCoverage = exports.runPassesGate = exports.DEFAULT_CHECKPOINTS = exports.createExampleCheckpoint = exports.validate = exports.listLaws = exports.check = void 0;
6
+ exports.getConstraintsMeta = exports.constraints = exports.updateUserModel = exports.analyzeSessions = exports.release = exports.postevalPlan = exports.failureClear = exports.failureStats = exports.failureList = exports.knowledgeMigrate = exports.knowledgeSnapshot = exports.knowledgeAudit = exports.knowledgeSyncRag = exports.knowledgeSyncStatus = exports.knowledgeUpsert = exports.knowledgeStats = exports.knowledgeDecay = exports.knowledgeImport = exports.knowledgeSearch = exports.knowledgeList = exports.syncDocs = exports.executeCommand = exports.reviewStatus = exports.review = exports.validateSchema = exports.contract = exports.auditDetails = exports.security = exports.performance = exports.listAcceptanceCriteria = exports.acceptance = exports.listSpecTypes = exports.specValidate = exports.flow = exports.status = exports.report = exports.init = exports.checkCoverage = exports.runPassesGate = exports.DEFAULT_CHECKPOINTS = exports.createExampleCheckpoint = exports.validate = exports.listLaws = exports.check = void 0;
7
7
  var check_1 = require("./check");
8
8
  Object.defineProperty(exports, "check", { enumerable: true, get: function () { return check_1.check; } });
9
9
  Object.defineProperty(exports, "listLaws", { enumerable: true, get: function () { return check_1.listLaws; } });
@@ -52,6 +52,9 @@ Object.defineProperty(exports, "knowledgeStats", { enumerable: true, get: functi
52
52
  Object.defineProperty(exports, "knowledgeUpsert", { enumerable: true, get: function () { return knowledge_1.knowledgeUpsert; } });
53
53
  Object.defineProperty(exports, "knowledgeSyncStatus", { enumerable: true, get: function () { return knowledge_1.knowledgeSyncStatus; } });
54
54
  Object.defineProperty(exports, "knowledgeSyncRag", { enumerable: true, get: function () { return knowledge_1.knowledgeSyncRag; } });
55
+ Object.defineProperty(exports, "knowledgeAudit", { enumerable: true, get: function () { return knowledge_1.knowledgeAudit; } });
56
+ Object.defineProperty(exports, "knowledgeSnapshot", { enumerable: true, get: function () { return knowledge_1.knowledgeSnapshot; } });
57
+ Object.defineProperty(exports, "knowledgeMigrate", { enumerable: true, get: function () { return knowledge_1.knowledgeMigrate; } });
55
58
  var failure_1 = require("./failure");
56
59
  Object.defineProperty(exports, "failureList", { enumerable: true, get: function () { return failure_1.failureList; } });
57
60
  Object.defineProperty(exports, "failureStats", { enumerable: true, get: function () { return failure_1.failureStats; } });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/commands/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,iCAA6D;AAApD,8FAAA,KAAK,OAAA;AAAE,iGAAA,QAAQ,OAAA;AACxB,uCAA0G;AAAjG,oGAAA,QAAQ,OAAA;AAAE,mHAAA,uBAAuB,OAAA;AAAE,+GAAA,mBAAmB,OAAA;AAC/D,6CAAqF;AAA5E,4GAAA,aAAa,OAAA;AAAE,4GAAA,aAAa,OAAA;AACrC,+BAAgD;AAAvC,4FAAA,IAAI,OAAA;AACb,mCAAsD;AAA7C,gGAAA,MAAM,OAAA;AACf,mCAAsD;AAA7C,gGAAA,MAAM,OAAA;AACf,+BAAgD;AAAvC,4FAAA,IAAI,OAAA;AACb,+BAA+E;AAAtE,oGAAA,YAAY,OAAA;AAAE,qGAAA,aAAa,OAAA;AACpC,2CAA0F;AAAjF,wGAAA,UAAU,OAAA;AAAE,oHAAA,sBAAsB,OAAA;AAC3C,6CAAqE;AAA5D,0GAAA,WAAW,OAAA;AACpB,uCAA0E;AAAjE,oGAAA,QAAQ,OAAA;AAAE,wGAAA,YAAY,OAAA;AAC/B,uCAA4E;AAAnE,oGAAA,QAAQ,OAAA;AAAE,0GAAA,cAAc,OAAA;AACjC,mCAAoE;AAA3D,gGAAA,MAAM,OAAA;AAAE,sGAAA,YAAY,OAAA;AAC7B,qCAAqE;AAA5D,yGAAA,cAAc,OAAA;AACvB,yCAA6D;AAApD,qGAAA,QAAQ,OAAA;AACjB,yCAA0N;AAAjN,0GAAA,aAAa,OAAA;AAAE,4GAAA,eAAe,OAAA;AAAE,4GAAA,eAAe,OAAA;AAAE,2GAAA,cAAc,OAAA;AAAE,2GAAA,cAAc,OAAA;AAAE,4GAAA,eAAe,OAAA;AAAE,gHAAA,mBAAmB,OAAA;AAAE,6GAAA,gBAAgB,OAAA;AAChJ,qCAAyF;AAAhF,sGAAA,WAAW,OAAA;AAAE,uGAAA,YAAY,OAAA;AAAE,uGAAA,YAAY,OAAA;AAChD,iDAAyE;AAAhE,6GAAA,YAAY,OAAA;AACrB,qCAAyD;AAAhD,kGAAA,OAAO,OAAA;AAChB,uDAAkF;AAAzE,mHAAA,eAAe,OAAA;AACxB,yDAAmF;AAA1E,oHAAA,eAAe,OAAA;AACxB,6CAAsF;AAA7E,0GAAA,WAAW,OAAA;AAAE,iHAAA,kBAAkB,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/commands/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,iCAA6D;AAApD,8FAAA,KAAK,OAAA;AAAE,iGAAA,QAAQ,OAAA;AACxB,uCAA0G;AAAjG,oGAAA,QAAQ,OAAA;AAAE,mHAAA,uBAAuB,OAAA;AAAE,+GAAA,mBAAmB,OAAA;AAC/D,6CAAqF;AAA5E,4GAAA,aAAa,OAAA;AAAE,4GAAA,aAAa,OAAA;AACrC,+BAAgD;AAAvC,4FAAA,IAAI,OAAA;AACb,mCAAsD;AAA7C,gGAAA,MAAM,OAAA;AACf,mCAAsD;AAA7C,gGAAA,MAAM,OAAA;AACf,+BAAgD;AAAvC,4FAAA,IAAI,OAAA;AACb,+BAA+E;AAAtE,oGAAA,YAAY,OAAA;AAAE,qGAAA,aAAa,OAAA;AACpC,2CAA0F;AAAjF,wGAAA,UAAU,OAAA;AAAE,oHAAA,sBAAsB,OAAA;AAC3C,6CAAqE;AAA5D,0GAAA,WAAW,OAAA;AACpB,uCAA0E;AAAjE,oGAAA,QAAQ,OAAA;AAAE,wGAAA,YAAY,OAAA;AAC/B,uCAA4E;AAAnE,oGAAA,QAAQ,OAAA;AAAE,0GAAA,cAAc,OAAA;AACjC,mCAAoE;AAA3D,gGAAA,MAAM,OAAA;AAAE,sGAAA,YAAY,OAAA;AAC7B,qCAAqE;AAA5D,yGAAA,cAAc,OAAA;AACvB,yCAA6D;AAApD,qGAAA,QAAQ,OAAA;AACjB,yCAA+Q;AAAtQ,0GAAA,aAAa,OAAA;AAAE,4GAAA,eAAe,OAAA;AAAE,4GAAA,eAAe,OAAA;AAAE,2GAAA,cAAc,OAAA;AAAE,2GAAA,cAAc,OAAA;AAAE,4GAAA,eAAe,OAAA;AAAE,gHAAA,mBAAmB,OAAA;AAAE,6GAAA,gBAAgB,OAAA;AAAE,2GAAA,cAAc,OAAA;AAAE,8GAAA,iBAAiB,OAAA;AAAE,6GAAA,gBAAgB,OAAA;AACrM,qCAAyF;AAAhF,sGAAA,WAAW,OAAA;AAAE,uGAAA,YAAY,OAAA;AAAE,uGAAA,YAAY,OAAA;AAChD,iDAAyE;AAAhE,6GAAA,YAAY,OAAA;AACrB,qCAAyD;AAAhD,kGAAA,OAAO,OAAA;AAChB,uDAAkF;AAAzE,mHAAA,eAAe,OAAA;AACxB,yDAAmF;AAA1E,oHAAA,eAAe,OAAA;AACxB,6CAAsF;AAA7E,0GAAA,WAAW,OAAA;AAAE,iHAAA,kBAAkB,OAAA"}
@@ -61,4 +61,25 @@ export declare function knowledgeSyncRag(options: KnowledgeOptions): Promise<voi
61
61
  * 知识同步状态:检测所有 tracked scope 的新鲜度
62
62
  */
63
63
  export declare function knowledgeSyncStatus(options: KnowledgeOptions): Promise<void>;
64
+ /**
65
+ * 知识库质量审计
66
+ */
67
+ export declare function knowledgeAudit(options: KnowledgeOptions & {
68
+ fix?: boolean;
69
+ dryRun?: boolean;
70
+ threshold?: number;
71
+ dir?: string;
72
+ }): Promise<void>;
73
+ /**
74
+ * 知识库快照(KR4 存活率追踪)
75
+ */
76
+ export declare function knowledgeSnapshot(options: KnowledgeOptions & {
77
+ dir?: string;
78
+ }): void;
79
+ /**
80
+ * 知识库迁移 — 为现有条目添加 AS-021 新字段
81
+ */
82
+ export declare function knowledgeMigrate(options: KnowledgeOptions & {
83
+ dir?: string;
84
+ }): void;
64
85
  //# sourceMappingURL=knowledge.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"knowledge.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/knowledge.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH,MAAM,WAAW,gBAAgB;IAC/B,WAAW;IACX,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,gBAAgB,GAAG;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,IAAI,CAAC,CAsChB;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,gBAAgB,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7C,OAAO,CAAC,IAAI,CAAC,CAqCf;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,gBAAgB,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAChE,OAAO,CAAC,IAAI,CAAC,CA+Cf;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyB7E;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqC7E;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoDpF;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0B/E;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2ClF"}
1
+ {"version":3,"file":"knowledge.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/knowledge.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAcH,MAAM,WAAW,gBAAgB;IAC/B,WAAW;IACX,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,gBAAgB,GAAG;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,IAAI,CAAC,CAsChB;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,gBAAgB,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7C,OAAO,CAAC,IAAI,CAAC,CAqCf;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,gBAAgB,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAChE,OAAO,CAAC,IAAI,CAAC,CA+Cf;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyB7E;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6D7E;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoDpF;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0B/E;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2ClF;AAQD;;GAEG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,gBAAgB,GAAG;IAC/D,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,IAAI,CAAC,CAoFhB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,gBAAgB,GAAG;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAUpF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,gBAAgB,GAAG;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA4BnF"}
@@ -49,17 +49,24 @@ exports.knowledgeStats = knowledgeStats;
49
49
  exports.knowledgeUpsert = knowledgeUpsert;
50
50
  exports.knowledgeSyncRag = knowledgeSyncRag;
51
51
  exports.knowledgeSyncStatus = knowledgeSyncStatus;
52
+ exports.knowledgeAudit = knowledgeAudit;
53
+ exports.knowledgeSnapshot = knowledgeSnapshot;
54
+ exports.knowledgeMigrate = knowledgeMigrate;
52
55
  const chalk_1 = __importDefault(require("chalk"));
53
56
  const fs = __importStar(require("fs"));
57
+ const os = __importStar(require("os"));
58
+ const path = __importStar(require("path"));
54
59
  const store_1 = require("../../knowledge/store");
55
60
  const query_1 = require("../../knowledge/query");
56
61
  const lifecycle_1 = require("../../knowledge/lifecycle");
57
62
  const import_1 = require("../../knowledge/import");
63
+ const audit_1 = require("../../knowledge/audit");
64
+ const migration_1 = require("../../knowledge/migration");
58
65
  /**
59
66
  * 知识库列表
60
67
  */
61
68
  async function knowledgeList(options) {
62
- const store = new store_1.KnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath) });
69
+ const store = new store_1.FileKnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath) });
63
70
  const filter = { excludeArchived: false };
64
71
  if (options.type) {
65
72
  filter.types = options.type.split(',');
@@ -96,7 +103,7 @@ async function knowledgeList(options) {
96
103
  * 知识库搜索
97
104
  */
98
105
  async function knowledgeSearch(query, options) {
99
- const store = new store_1.KnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath) });
106
+ const store = new store_1.FileKnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath) });
100
107
  const queryEngine = new query_1.KnowledgeQuery(store);
101
108
  const budget = {
102
109
  phase: 'cli',
@@ -130,7 +137,7 @@ async function knowledgeSearch(query, options) {
130
137
  */
131
138
  async function knowledgeImport(options) {
132
139
  const projectPath = options.projectPath || process.cwd();
133
- const store = new store_1.KnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath) });
140
+ const store = new store_1.FileKnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath) });
134
141
  const sources = options.sources
135
142
  ? options.sources.split(',')
136
143
  : ['code', 'git', 'docs'];
@@ -171,7 +178,7 @@ async function knowledgeImport(options) {
171
178
  * 知识库衰减周期
172
179
  */
173
180
  async function knowledgeDecay(options) {
174
- const store = new store_1.KnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath) });
181
+ const store = new store_1.FileKnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath) });
175
182
  const lifecycle = new lifecycle_1.KnowledgeLifecycle(store);
176
183
  if (!options.json) {
177
184
  console.log(chalk_1.default.blue('🔄 运行衰减周期...'));
@@ -195,8 +202,9 @@ async function knowledgeDecay(options) {
195
202
  * 知识库统计
196
203
  */
197
204
  async function knowledgeStats(options) {
198
- const store = new store_1.KnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath) });
205
+ const store = new store_1.FileKnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath) });
199
206
  const entries = store.list({ excludeArchived: false });
207
+ const active = entries.filter(e => e.maturity !== 'archived');
200
208
  const byType = {};
201
209
  const byMaturity = {};
202
210
  const byLayer = {};
@@ -205,12 +213,29 @@ async function knowledgeStats(options) {
205
213
  byMaturity[entry.maturity] = (byMaturity[entry.maturity] || 0) + 1;
206
214
  byLayer[entry.layer] = (byLayer[entry.layer] || 0) + 1;
207
215
  }
216
+ // D6 flywheel metrics
217
+ const withRefs = active.filter(e => e.referencedBy.length > 0).length;
218
+ const refCoverage = active.length > 0 ? Math.round(withRefs / active.length * 100) : 0;
219
+ const avgRefs = active.length > 0
220
+ ? Math.round(active.reduce((sum, e) => sum + e.referencedBy.length, 0) / active.length * 10) / 10
221
+ : 0;
222
+ let consumptionHitRate = 0;
223
+ try {
224
+ const statsPath = path.join(store.getBaseDir(), '.consumption-stats.json');
225
+ if (fs.existsSync(statsPath)) {
226
+ const stats = JSON.parse(fs.readFileSync(statsPath, 'utf-8'));
227
+ const dailyEvents = stats.dailyEvents || 0;
228
+ consumptionHitRate = active.length > 0 ? Math.min(Math.round(dailyEvents / active.length * 100), 100) : 0;
229
+ }
230
+ }
231
+ catch { /* best-effort */ }
232
+ const flywheel = { refCoverage, avgRefs, consumptionHitRate };
208
233
  if (options.json) {
209
- console.log(JSON.stringify({ total: entries.length, byType, byMaturity, byLayer }, null, 2));
234
+ console.log(JSON.stringify({ total: entries.length, byType, byMaturity, byLayer, flywheel }, null, 2));
210
235
  return;
211
236
  }
212
237
  console.log(chalk_1.default.blue(`📊 知识库统计\n`));
213
- console.log(chalk_1.default.bold(` 总计: ${entries.length} 条\n`));
238
+ console.log(chalk_1.default.bold(` 总计: ${entries.length} 条 (活跃: ${active.length})\n`));
214
239
  console.log(chalk_1.default.bold(' 按类型:'));
215
240
  for (const [type, count] of Object.entries(byType)) {
216
241
  console.log(` ${type}: ${count}`);
@@ -224,6 +249,10 @@ async function knowledgeStats(options) {
224
249
  for (const [layer, count] of Object.entries(byLayer)) {
225
250
  console.log(` ${layer}: ${count}`);
226
251
  }
252
+ console.log(chalk_1.default.bold('\n 飞轮指标:'));
253
+ console.log(` 引用覆盖: ${refCoverage}%`);
254
+ console.log(` 平均引用: ${avgRefs}`);
255
+ console.log(` 消费命中率: ${consumptionHitRate}%`);
227
256
  }
228
257
  /**
229
258
  * 设计时知识沉淀:写入 KnowledgeStore + 同步 Prisma Document(Studio UI 可见)
@@ -353,7 +382,129 @@ async function knowledgeSyncStatus(options) {
353
382
  }
354
383
  }
355
384
  function getKnowledgeDir(projectPath) {
356
- const base = projectPath || process.cwd();
357
- return `${base}/.harness/knowledge`;
385
+ if (projectPath)
386
+ return `${projectPath}/.harness/knowledge`;
387
+ if (process.env.KNOWLEDGE_BASE_DIR)
388
+ return process.env.KNOWLEDGE_BASE_DIR;
389
+ return path.join(os.homedir(), '.studio', 'knowledge');
390
+ }
391
+ /**
392
+ * 知识库质量审计
393
+ */
394
+ async function knowledgeAudit(options) {
395
+ const audit = new audit_1.KnowledgeAudit({
396
+ baseDir: options.dir || getKnowledgeDir(options.projectPath),
397
+ shortContentThreshold: options.threshold ? parseInt(options.threshold, 10) : undefined,
398
+ });
399
+ const isDryRun = options.dryRun && !options.fix;
400
+ if (!options.json && !isDryRun) {
401
+ console.log(chalk_1.default.blue('🔍 知识库质量审计...\n'));
402
+ }
403
+ const report = audit.run({ autoFix: options.fix && !isDryRun });
404
+ if (options.json) {
405
+ console.log(JSON.stringify(report, null, 2));
406
+ return;
407
+ }
408
+ // Summary
409
+ console.log(chalk_1.default.bold(` 总条目: ${report.totalEntries}`));
410
+ console.log(chalk_1.default.bold(` 健康分: ${report.healthScore.before}/100`));
411
+ if (report.autoFixed > 0) {
412
+ console.log(chalk_1.default.green(` 自动修复: ${report.autoFixed} 条`));
413
+ console.log(chalk_1.default.bold(` 修复后: ${report.healthScore.after}/100`));
414
+ }
415
+ console.log();
416
+ // Dimension scores
417
+ const dimLabels = {
418
+ structure: 'D1 结构完整性',
419
+ content: 'D2 内容质量',
420
+ dedup: 'D3 去重有效性',
421
+ maturity: 'D4 成熟度健康',
422
+ freshness: 'D5 新鲜度',
423
+ flywheel: 'D6 飞轮验证',
424
+ };
425
+ console.log(chalk_1.default.bold(' 维度评分:'));
426
+ for (const [key, dim] of Object.entries(report.dimensions)) {
427
+ const label = dimLabels[key] || key;
428
+ const scoreColor = dim.score >= 80 ? chalk_1.default.green : dim.score >= 60 ? chalk_1.default.yellow : chalk_1.default.red;
429
+ console.log(` ${label}: ${scoreColor(`${dim.score}/100`)} (${dim.issues} 问题)`);
430
+ }
431
+ console.log();
432
+ // Issues by rule
433
+ const ruleLabels = {
434
+ 'frontmatter-missing': 'frontmatter 缺失',
435
+ 'test-data-pollution': '测试数据污染',
436
+ 'daily-audit-noise': '每日审计噪音',
437
+ 'zero-content-proven': '零内容 proven',
438
+ 'short-content': '短内容',
439
+ 'maturity-inflation': '成熟度虚高',
440
+ 'title-duplicate': '标题重复',
441
+ 'source-refs-bloat': 'sourceReferences 膨胀',
442
+ 'promotion-blocked': 'promotion 受阻',
443
+ 'orphan-draft': '孤儿 draft',
444
+ 'stale-entry': '过期条目',
445
+ };
446
+ for (const [rule, count] of Object.entries(report.summary)) {
447
+ if (count === 0)
448
+ continue;
449
+ const label = ruleLabels[rule] || rule;
450
+ console.log(` ${chalk_1.default.red(`${label}: ${count}`)}`);
451
+ }
452
+ // Detail (first 20)
453
+ if (report.issues.length > 0) {
454
+ console.log(chalk_1.default.bold(`\n 问题详情 (前 20 条):\n`));
455
+ for (const issue of report.issues.slice(0, 20)) {
456
+ const severityColor = issue.severity === 'critical' ? chalk_1.default.red
457
+ : issue.severity === 'high' ? chalk_1.default.yellow
458
+ : chalk_1.default.gray;
459
+ console.log(` ${severityColor(`[${issue.severity}]`)} ${issue.entryId}: ${issue.title}`);
460
+ console.log(` ${chalk_1.default.gray(issue.detail)} → ${issue.action}`);
461
+ }
462
+ if (report.issues.length > 20) {
463
+ console.log(chalk_1.default.gray(`\n ... 还有 ${report.issues.length - 20} 条`));
464
+ }
465
+ }
466
+ if (!options.fix && report.issues.length > 0) {
467
+ console.log(chalk_1.default.yellow(`\n 使用 --fix 自动修复`));
468
+ }
469
+ }
470
+ /**
471
+ * 知识库快照(KR4 存活率追踪)
472
+ */
473
+ function knowledgeSnapshot(options) {
474
+ const store = new store_1.FileKnowledgeStore({ baseDir: options.dir || getKnowledgeDir(options.projectPath) });
475
+ const snapPath = store.snapshot();
476
+ if (options.json) {
477
+ console.log(JSON.stringify({ snapshotPath: snapPath }));
478
+ return;
479
+ }
480
+ console.log(chalk_1.default.green(`✅ 快照已保存: ${snapPath}`));
481
+ }
482
+ /**
483
+ * 知识库迁移 — 为现有条目添加 AS-021 新字段
484
+ */
485
+ function knowledgeMigrate(options) {
486
+ const baseDir = options.dir || getKnowledgeDir(options.projectPath);
487
+ if (options.json) {
488
+ const result = (0, migration_1.migrateKnowledgeEntries)(baseDir);
489
+ console.log(JSON.stringify(result, null, 2));
490
+ return;
491
+ }
492
+ console.log(chalk_1.default.blue('🔄 迁移知识条目(添加 consumptionMode/origin 字段)\n'));
493
+ const result = (0, migration_1.migrateKnowledgeEntries)(baseDir);
494
+ console.log(chalk_1.default.green(` 总计: ${result.total} 条`));
495
+ console.log(chalk_1.default.green(` 已迁移: ${result.migrated} 条`));
496
+ console.log(chalk_1.default.gray(` 已跳过: ${result.skipped} 条`));
497
+ if (result.errors.length > 0) {
498
+ console.log(chalk_1.default.red(`\n 错误: ${result.errors.length} 条`));
499
+ for (const err of result.errors.slice(0, 5)) {
500
+ console.log(chalk_1.default.red(` ${err}`));
501
+ }
502
+ }
503
+ if (result.migrated === 0 && result.errors.length === 0) {
504
+ console.log(chalk_1.default.green('\n✅ 所有条目已是最新,无需迁移'));
505
+ }
506
+ else if (result.migrated > 0) {
507
+ console.log(chalk_1.default.green(`\n✅ 迁移完成`));
508
+ }
358
509
  }
359
510
  //# sourceMappingURL=knowledge.js.map