@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.
- package/CHANGELOG.md +35 -0
- package/bin/harness-knowledge-check.js +38 -23
- package/bin/harness-knowledge-track.js +30 -4
- package/bin/harness.js +24 -1
- package/dist/cli/commands/index.d.ts +1 -1
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +4 -1
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/knowledge.d.ts +21 -0
- package/dist/cli/commands/knowledge.d.ts.map +1 -1
- package/dist/cli/commands/knowledge.js +160 -9
- package/dist/cli/commands/knowledge.js.map +1 -1
- package/dist/cli/commands/release.d.ts.map +1 -1
- package/dist/cli/commands/release.js +43 -6
- package/dist/cli/commands/release.js.map +1 -1
- package/dist/core/constraints/checker.js +1 -1
- package/dist/core/constraints/checker.js.map +1 -1
- package/dist/core/constraints/definitions.d.ts.map +1 -1
- package/dist/core/constraints/definitions.js +34 -26
- package/dist/core/constraints/definitions.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/knowledge/audit.d.ts +76 -0
- package/dist/knowledge/audit.d.ts.map +1 -0
- package/dist/knowledge/audit.js +566 -0
- package/dist/knowledge/audit.js.map +1 -0
- package/dist/knowledge/doctor.d.ts +1 -1
- package/dist/knowledge/doctor.d.ts.map +1 -1
- package/dist/knowledge/import.d.ts +1 -1
- package/dist/knowledge/import.d.ts.map +1 -1
- package/dist/knowledge/import.js +3 -0
- package/dist/knowledge/import.js.map +1 -1
- package/dist/knowledge/index.d.ts +7 -2
- package/dist/knowledge/index.d.ts.map +1 -1
- package/dist/knowledge/index.js +7 -2
- package/dist/knowledge/index.js.map +1 -1
- package/dist/knowledge/ingest.d.ts +28 -1
- package/dist/knowledge/ingest.d.ts.map +1 -1
- package/dist/knowledge/ingest.js +150 -5
- package/dist/knowledge/ingest.js.map +1 -1
- package/dist/knowledge/lifecycle-hooks.d.ts +1 -1
- package/dist/knowledge/lifecycle-hooks.d.ts.map +1 -1
- package/dist/knowledge/lifecycle-hooks.js +3 -0
- package/dist/knowledge/lifecycle-hooks.js.map +1 -1
- package/dist/knowledge/lifecycle.d.ts +60 -8
- package/dist/knowledge/lifecycle.d.ts.map +1 -1
- package/dist/knowledge/lifecycle.js +213 -52
- package/dist/knowledge/lifecycle.js.map +1 -1
- package/dist/knowledge/lint.d.ts +1 -1
- package/dist/knowledge/lint.d.ts.map +1 -1
- package/dist/knowledge/lint.js +44 -3
- package/dist/knowledge/lint.js.map +1 -1
- package/dist/knowledge/migration.d.ts +25 -0
- package/dist/knowledge/migration.d.ts.map +1 -0
- package/dist/knowledge/migration.js +96 -0
- package/dist/knowledge/migration.js.map +1 -0
- package/dist/knowledge/query.d.ts +30 -2
- package/dist/knowledge/query.d.ts.map +1 -1
- package/dist/knowledge/query.js +58 -0
- package/dist/knowledge/query.js.map +1 -1
- package/dist/knowledge/reference-tracker.d.ts +1 -1
- package/dist/knowledge/reference-tracker.d.ts.map +1 -1
- package/dist/knowledge/store.d.ts +50 -3
- package/dist/knowledge/store.d.ts.map +1 -1
- package/dist/knowledge/store.js +111 -9
- package/dist/knowledge/store.js.map +1 -1
- package/dist/knowledge/types.d.ts +43 -1
- package/dist/knowledge/types.d.ts.map +1 -1
- package/dist/knowledge/types.js +1 -0
- package/dist/knowledge/types.js.map +1 -1
- package/dist/monitoring/knowledge-evolver.d.ts +1 -1
- package/dist/monitoring/knowledge-evolver.d.ts.map +1 -1
- package/dist/types/constraint.d.ts +1 -1
- package/dist/types/constraint.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/checker.test.ts +4 -4
- package/src/cli/commands/__tests__/knowledge.test.ts +167 -0
- package/src/cli/commands/index.ts +1 -1
- package/src/cli/commands/knowledge.ts +176 -5
- package/src/cli/commands/release.ts +44 -6
- package/src/context/__tests__/knowledge-injector.test.ts +4 -1
- package/src/core/constraints/checker.ts +1 -1
- package/src/core/constraints/definitions.ts +35 -27
- package/src/dashboard/__tests__/data.test.ts +3 -0
- package/src/dashboard/__tests__/stats.test.ts +3 -0
- package/src/index.ts +3 -1
- package/src/knowledge/CONTEXT.md +29 -7
- package/src/knowledge/__tests__/audit.test.ts +598 -0
- package/src/knowledge/__tests__/doctor.test.ts +28 -1
- package/src/knowledge/__tests__/import.test.ts +1 -1
- package/src/knowledge/__tests__/ingest.test.ts +320 -1
- package/src/knowledge/__tests__/lifecycle-hooks.test.ts +4 -1
- package/src/knowledge/__tests__/lifecycle.test.ts +656 -3
- package/src/knowledge/__tests__/lint.test.ts +52 -1
- package/src/knowledge/__tests__/migration.test.ts +115 -0
- package/src/knowledge/__tests__/query.test.ts +87 -1
- package/src/knowledge/__tests__/reference-tracker.test.ts +4 -1
- package/src/knowledge/__tests__/store.test.ts +208 -1
- package/src/knowledge/audit.ts +641 -0
- package/src/knowledge/doctor.ts +1 -1
- package/src/knowledge/import.ts +4 -1
- package/src/knowledge/index.ts +7 -2
- package/src/knowledge/ingest.ts +170 -6
- package/src/knowledge/lifecycle-hooks.ts +4 -1
- package/src/knowledge/lifecycle.ts +219 -50
- package/src/knowledge/lint.ts +45 -4
- package/src/knowledge/migration.ts +73 -0
- package/src/knowledge/query.ts +72 -1
- package/src/knowledge/reference-tracker.ts +1 -1
- package/src/knowledge/store.ts +125 -8
- package/src/knowledge/types.ts +50 -1
- package/src/monitoring/__tests__/knowledge-doctor.test.ts +3 -0
- package/src/monitoring/__tests__/knowledge-evolver.test.ts +3 -0
- package/src/monitoring/knowledge-evolver.ts +1 -1
- package/src/types/constraint.ts +1 -1
|
@@ -7,8 +7,12 @@
|
|
|
7
7
|
* - MaturityLevel: how trusted (lifecycle)
|
|
8
8
|
*/
|
|
9
9
|
export type KnowledgeType = 'model' | 'decision' | 'guideline' | 'pitfall' | 'process' | 'architecture';
|
|
10
|
-
export type MaturityLevel = 'draft' | 'verified' | 'proven' | 'archived';
|
|
10
|
+
export type MaturityLevel = 'draft' | 'verified' | 'proven' | 'archived' | 'active' | 'deprecated';
|
|
11
11
|
export type StorageLayer = 'personal' | 'team' | 'tech' | 'domain' | 'project' | 'system';
|
|
12
|
+
/** How agent consumes this knowledge — drives injection strategy and lifecycle */
|
|
13
|
+
export type ConsumptionMode = 'rule' | 'reference' | 'context' | 'signal';
|
|
14
|
+
/** Where this knowledge came from — affects initial trust and maturity */
|
|
15
|
+
export type KnowledgeOrigin = 'human' | 'agent' | 'external' | 'system';
|
|
12
16
|
export interface KnowledgeEntry {
|
|
13
17
|
id: string;
|
|
14
18
|
type: KnowledgeType;
|
|
@@ -24,7 +28,16 @@ export interface KnowledgeEntry {
|
|
|
24
28
|
applicablePhases: string[];
|
|
25
29
|
sourceReferences: SourceRef[];
|
|
26
30
|
referencedBy: string[];
|
|
31
|
+
executionResults: ExecutionResult[];
|
|
27
32
|
decayAt?: string;
|
|
33
|
+
/** How agent consumes this knowledge (default: 'reference') */
|
|
34
|
+
consumptionMode: ConsumptionMode;
|
|
35
|
+
/** Where this knowledge came from (default: 'agent') */
|
|
36
|
+
origin: KnowledgeOrigin;
|
|
37
|
+
/** Path/URL to full content for on-demand retrieval */
|
|
38
|
+
fullContentPath?: string;
|
|
39
|
+
/** Skill ID if this knowledge was refined into a Skill */
|
|
40
|
+
skillId?: string;
|
|
28
41
|
}
|
|
29
42
|
export interface SourceRef {
|
|
30
43
|
workflow?: string;
|
|
@@ -32,6 +45,12 @@ export interface SourceRef {
|
|
|
32
45
|
commit?: string;
|
|
33
46
|
timestamp: string;
|
|
34
47
|
}
|
|
48
|
+
export interface ExecutionResult {
|
|
49
|
+
contributor: string;
|
|
50
|
+
success: boolean;
|
|
51
|
+
timestamp: string;
|
|
52
|
+
source?: 'human' | 'auto';
|
|
53
|
+
}
|
|
35
54
|
export interface KnowledgeReference {
|
|
36
55
|
id: string;
|
|
37
56
|
title: string;
|
|
@@ -56,6 +75,8 @@ export interface QueryFilter {
|
|
|
56
75
|
tags?: string[];
|
|
57
76
|
applicablePhases?: string[];
|
|
58
77
|
excludeArchived?: boolean;
|
|
78
|
+
consumptionModes?: ConsumptionMode[];
|
|
79
|
+
origins?: KnowledgeOrigin[];
|
|
59
80
|
}
|
|
60
81
|
export type LintIssueType = 'orphan' | 'contradiction' | 'outdated' | 'duplicate' | 'index_inconsistent';
|
|
61
82
|
export interface LintIssue {
|
|
@@ -71,6 +92,9 @@ export interface IngestOptions {
|
|
|
71
92
|
maturity?: MaturityLevel;
|
|
72
93
|
tags?: string[];
|
|
73
94
|
projects?: string[];
|
|
95
|
+
consumptionMode?: ConsumptionMode;
|
|
96
|
+
origin?: KnowledgeOrigin;
|
|
97
|
+
fullContentPath?: string;
|
|
74
98
|
}
|
|
75
99
|
export interface MaturityChange {
|
|
76
100
|
entryId: string;
|
|
@@ -82,8 +106,24 @@ export interface DecayConfig {
|
|
|
82
106
|
provenDecayMonths: number;
|
|
83
107
|
verifiedDecayMonths: number;
|
|
84
108
|
draftDecayMonths: number;
|
|
109
|
+
/** Sources whose entries skip draft→verified promotion (start at verified) */
|
|
110
|
+
autoPromoteSources: string[];
|
|
85
111
|
}
|
|
86
112
|
export declare const DEFAULT_DECAY_CONFIG: DecayConfig;
|
|
113
|
+
export interface DecisionRecord {
|
|
114
|
+
topic: string;
|
|
115
|
+
category: 'architecture' | 'tooling' | 'process' | 'design';
|
|
116
|
+
context: string;
|
|
117
|
+
decision: string;
|
|
118
|
+
alternatives: string[];
|
|
119
|
+
rationale: string;
|
|
120
|
+
consequences: string;
|
|
121
|
+
participants: string[];
|
|
122
|
+
sourceType: string;
|
|
123
|
+
sourceId?: string;
|
|
124
|
+
revisable: boolean;
|
|
125
|
+
revisitCondition?: string;
|
|
126
|
+
}
|
|
87
127
|
export interface ReferenceRecord {
|
|
88
128
|
decisionId: string;
|
|
89
129
|
entryIds: string[];
|
|
@@ -99,5 +139,7 @@ export interface IndexEntry {
|
|
|
99
139
|
applicablePhases: string[];
|
|
100
140
|
lastReferenced: string;
|
|
101
141
|
created: string;
|
|
142
|
+
consumptionMode: ConsumptionMode;
|
|
143
|
+
origin: KnowledgeOrigin;
|
|
102
144
|
}
|
|
103
145
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/knowledge/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,UAAU,GAAG,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,cAAc,CAAC;AAExG,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,UAAU,GAAG,QAAQ,GAAG,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/knowledge/types.ts"],"names":[],"mappings":"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"}
|
package/dist/knowledge/types.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/knowledge/types.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/knowledge/types.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAsIU,QAAA,oBAAoB,GAAgB;IAC/C,iBAAiB,EAAE,EAAE;IACrB,mBAAmB,EAAE,CAAC;IACtB,gBAAgB,EAAE,CAAC;IACnB,kBAAkB,EAAE,EAAE;CACvB,CAAC"}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import type { KnowledgeEntry, MaturityLevel } from '../knowledge/types';
|
|
10
10
|
import type { KnowledgeDiagnosis } from './knowledge-doctor';
|
|
11
|
-
import { KnowledgeStore } from '../knowledge/store';
|
|
11
|
+
import type { KnowledgeStore } from '../knowledge/store';
|
|
12
12
|
export type ProposalAction = 'promote' | 'demote' | 'archive' | 'merge' | 'freeze';
|
|
13
13
|
export interface EvolutionProposal {
|
|
14
14
|
id: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"knowledge-evolver.d.ts","sourceRoot":"","sources":["../../src/monitoring/knowledge-evolver.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"knowledge-evolver.d.ts","sourceRoot":"","sources":["../../src/monitoring/knowledge-evolver.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAIzD,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEnF,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,cAAc,CAAC;IACvB,eAAe,EAAE,aAAa,CAAC;IAC/B,cAAc,EAAE,aAAa,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAChC,cAAc,EAAE,OAAO,CAAC;IACxB,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,UAAU,GAAG,aAAa,CAAC;IAC5D,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,iBAAiB,EAAE,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;CACzC;AAID,MAAM,WAAW,sBAAsB;IACrC,iBAAiB;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,kBAAkB;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB;IAClB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAwBD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAmC;IACjD,OAAO,CAAC,KAAK,CAAC,CAAiB;gBAEnB,MAAM,CAAC,EAAE,sBAAsB,EAAE,KAAK,CAAC,EAAE,cAAc;IAKnE;;OAEG;IACH,iBAAiB,CACf,OAAO,EAAE,cAAc,EAAE,EACzB,SAAS,GAAE,kBAAkB,EAAO,GACnC,iBAAiB,EAAE;IAwCtB;;OAEG;IACH,OAAO,CAAC,YAAY;IA4BpB;;OAEG;IACH,OAAO,CAAC,WAAW;IAsBnB,OAAO,CAAC,cAAc;IAuBtB;;OAEG;IACH,MAAM,CAAC,QAAQ,EAAE,iBAAiB,GAAG;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE;IAmB1E;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO;IA0B/C;;OAEG;IACH,gBAAgB,CAAC,SAAS,EAAE,iBAAiB,EAAE,GAAG,eAAe;CA8BlE"}
|
|
@@ -163,7 +163,7 @@ export interface ConstraintContext {
|
|
|
163
163
|
hasRequirementReview?: boolean;
|
|
164
164
|
/** 是否有需求文档(用于 no_implementation_without_requirement) */
|
|
165
165
|
hasRequirement?: boolean;
|
|
166
|
-
/** 是否在 worktree 中执行(用于
|
|
166
|
+
/** 是否在 worktree 中执行(用于 prefer_worktree) */
|
|
167
167
|
hasWorktree?: boolean;
|
|
168
168
|
/** worktree 路径(用于 worktree 相关检查) */
|
|
169
169
|
worktreePath?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constraint.d.ts","sourceRoot":"","sources":["../../src/types/constraint.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"constraint.d.ts","sourceRoot":"","sources":["../../src/types/constraint.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1113,19 +1113,19 @@ describe('ConstraintChecker', () => {
|
|
|
1113
1113
|
expect(result.satisfied).toBe(false);
|
|
1114
1114
|
});
|
|
1115
1115
|
|
|
1116
|
-
it('
|
|
1116
|
+
it('prefer_worktree should pass with worktree', async () => {
|
|
1117
1117
|
const context: ConstraintContext = { operation: 'code_implementation', hasWorktree: true };
|
|
1118
1118
|
const result = await checker.check(
|
|
1119
|
-
{ id: '
|
|
1119
|
+
{ id: 'prefer_worktree', level: 'guideline', rule: 'WORKTREE', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
1120
1120
|
context
|
|
1121
1121
|
);
|
|
1122
1122
|
expect(result.satisfied).toBe(true);
|
|
1123
1123
|
});
|
|
1124
1124
|
|
|
1125
|
-
it('
|
|
1125
|
+
it('prefer_worktree should fail without worktree', async () => {
|
|
1126
1126
|
const context: ConstraintContext = { operation: 'code_implementation', hasWorktree: false };
|
|
1127
1127
|
const result = await checker.check(
|
|
1128
|
-
{ id: '
|
|
1128
|
+
{ id: 'prefer_worktree', level: 'guideline', rule: 'WORKTREE', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
1129
1129
|
context
|
|
1130
1130
|
);
|
|
1131
1131
|
expect(result.satisfied).toBe(false);
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* knowledge 命令测试 — knowledgeAudit
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { knowledgeAudit, knowledgeStats } from '../knowledge';
|
|
6
|
+
|
|
7
|
+
// Mock chalk
|
|
8
|
+
jest.mock('chalk', () => ({
|
|
9
|
+
blue: jest.fn((str: string) => str),
|
|
10
|
+
bold: jest.fn((str: string) => str),
|
|
11
|
+
green: jest.fn((str: string) => str),
|
|
12
|
+
yellow: jest.fn((str: string) => str),
|
|
13
|
+
red: jest.fn((str: string) => str),
|
|
14
|
+
gray: jest.fn((str: string) => str),
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
// Mock KnowledgeAudit
|
|
18
|
+
const mockRun = jest.fn();
|
|
19
|
+
jest.mock('../../../knowledge/audit', () => ({
|
|
20
|
+
KnowledgeAudit: jest.fn().mockImplementation(() => ({
|
|
21
|
+
run: mockRun,
|
|
22
|
+
})),
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
const MOCK_REPORT = {
|
|
26
|
+
timestamp: '2026-06-02T00:00:00.000Z',
|
|
27
|
+
totalEntries: 100,
|
|
28
|
+
issues: [
|
|
29
|
+
{
|
|
30
|
+
rule: 'short-content',
|
|
31
|
+
entryId: 'GUI-001',
|
|
32
|
+
title: 'Short Entry',
|
|
33
|
+
severity: 'medium',
|
|
34
|
+
action: 'flag',
|
|
35
|
+
detail: 'content 30 chars',
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
summary: {
|
|
39
|
+
'frontmatter-missing': 0,
|
|
40
|
+
'test-data-pollution': 0,
|
|
41
|
+
'daily-audit-noise': 0,
|
|
42
|
+
'zero-content-proven': 0,
|
|
43
|
+
'short-content': 1,
|
|
44
|
+
'maturity-inflation': 0,
|
|
45
|
+
'title-duplicate': 0,
|
|
46
|
+
'source-refs-bloat': 0,
|
|
47
|
+
'promotion-blocked': 0,
|
|
48
|
+
'orphan-draft': 0,
|
|
49
|
+
'stale-entry': 0,
|
|
50
|
+
},
|
|
51
|
+
dimensions: {
|
|
52
|
+
structure: { score: 100, issues: 0, details: {} },
|
|
53
|
+
content: { score: 95, issues: 1, details: {} },
|
|
54
|
+
dedup: { score: 100, issues: 0, details: {} },
|
|
55
|
+
maturity: { score: 100, issues: 0, details: {} },
|
|
56
|
+
freshness: { score: 100, issues: 0, details: {} },
|
|
57
|
+
flywheel: { score: 50, issues: 0, details: {} },
|
|
58
|
+
},
|
|
59
|
+
autoFixed: 0,
|
|
60
|
+
healthScore: { before: 95, after: 95 },
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
describe('getKnowledgeDir', () => {
|
|
64
|
+
const os = require('os');
|
|
65
|
+
const path = require('path');
|
|
66
|
+
const storeModule = require('../../../knowledge/store');
|
|
67
|
+
let storeCtorSpy: jest.SpyInstance;
|
|
68
|
+
|
|
69
|
+
beforeEach(() => {
|
|
70
|
+
delete process.env.KNOWLEDGE_BASE_DIR;
|
|
71
|
+
storeCtorSpy = jest.spyOn(storeModule, 'FileKnowledgeStore').mockImplementation(() => ({
|
|
72
|
+
list: jest.fn().mockReturnValue([]),
|
|
73
|
+
}));
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
afterEach(() => {
|
|
77
|
+
storeCtorSpy.mockRestore();
|
|
78
|
+
delete process.env.KNOWLEDGE_BASE_DIR;
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should use KNOWLEDGE_BASE_DIR env var when set', async () => {
|
|
82
|
+
process.env.KNOWLEDGE_BASE_DIR = '/custom/knowledge';
|
|
83
|
+
await knowledgeStats({ json: true });
|
|
84
|
+
expect(storeCtorSpy).toHaveBeenCalledWith(expect.objectContaining({
|
|
85
|
+
baseDir: '/custom/knowledge',
|
|
86
|
+
}));
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should default to ~/.studio/knowledge when no env var', async () => {
|
|
90
|
+
const expected = path.join(os.homedir(), '.studio', 'knowledge');
|
|
91
|
+
await knowledgeStats({ json: true });
|
|
92
|
+
expect(storeCtorSpy).toHaveBeenCalledWith(expect.objectContaining({
|
|
93
|
+
baseDir: expected,
|
|
94
|
+
}));
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should use projectPath when provided', async () => {
|
|
98
|
+
await knowledgeStats({ projectPath: '/my/project', json: true });
|
|
99
|
+
expect(storeCtorSpy).toHaveBeenCalledWith(expect.objectContaining({
|
|
100
|
+
baseDir: '/my/project/.harness/knowledge',
|
|
101
|
+
}));
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe('knowledgeAudit CLI', () => {
|
|
106
|
+
let consoleSpy: jest.SpyInstance;
|
|
107
|
+
|
|
108
|
+
beforeEach(() => {
|
|
109
|
+
jest.clearAllMocks();
|
|
110
|
+
consoleSpy = jest.spyOn(console, 'log').mockImplementation();
|
|
111
|
+
mockRun.mockReturnValue(MOCK_REPORT);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
afterEach(() => {
|
|
115
|
+
consoleSpy.mockRestore();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('should output JSON when --json is set', async () => {
|
|
119
|
+
await knowledgeAudit({ json: true });
|
|
120
|
+
expect(consoleSpy).toHaveBeenCalledWith(JSON.stringify(MOCK_REPORT, null, 2));
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('should call audit.run with autoFix=true when --fix is set', async () => {
|
|
124
|
+
await knowledgeAudit({ fix: true });
|
|
125
|
+
expect(mockRun).toHaveBeenCalledWith({ autoFix: true });
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('should call audit.run with autoFix falsy when --dry-run is set', async () => {
|
|
129
|
+
await knowledgeAudit({ dryRun: true });
|
|
130
|
+
expect(mockRun).toHaveBeenCalledWith({ autoFix: undefined });
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should call audit.run with autoFix falsy by default', async () => {
|
|
134
|
+
await knowledgeAudit({});
|
|
135
|
+
expect(mockRun).toHaveBeenCalledWith({ autoFix: undefined });
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should display total entries and health score', async () => {
|
|
139
|
+
await knowledgeAudit({});
|
|
140
|
+
const output = consoleSpy.mock.calls.map((c: any[]) => c[0]).join('\n');
|
|
141
|
+
expect(output).toContain('总条目: 100');
|
|
142
|
+
expect(output).toContain('95/100');
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('should display dimension scores', async () => {
|
|
146
|
+
await knowledgeAudit({});
|
|
147
|
+
const output = consoleSpy.mock.calls.map((c: any[]) => c[0]).join('\n');
|
|
148
|
+
expect(output).toContain('D1 结构完整性');
|
|
149
|
+
expect(output).toContain('D6 飞轮验证');
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('should display autoFixed count when > 0', async () => {
|
|
153
|
+
mockRun.mockReturnValue({ ...MOCK_REPORT, autoFixed: 5, healthScore: { before: 90, after: 95 } });
|
|
154
|
+
await knowledgeAudit({ fix: true });
|
|
155
|
+
const output = consoleSpy.mock.calls.map((c: any[]) => c[0]).join('\n');
|
|
156
|
+
expect(output).toContain('自动修复: 5');
|
|
157
|
+
expect(output).toContain('修复后: 95/100');
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('should pass custom dir to KnowledgeAudit', async () => {
|
|
161
|
+
const { KnowledgeAudit } = require('../../../knowledge/audit');
|
|
162
|
+
await knowledgeAudit({ dir: '/custom/path' });
|
|
163
|
+
expect(KnowledgeAudit).toHaveBeenCalledWith(expect.objectContaining({
|
|
164
|
+
baseDir: '/custom/path',
|
|
165
|
+
}));
|
|
166
|
+
});
|
|
167
|
+
});
|
|
@@ -17,7 +17,7 @@ export { contract, validateSchema, type ContractOptions } from './contract';
|
|
|
17
17
|
export { review, reviewStatus, type ReviewOptions } from './review';
|
|
18
18
|
export { executeCommand, type CommandCheckOptions } from './command';
|
|
19
19
|
export { syncDocs, type SyncDocsOptions } from './sync-docs';
|
|
20
|
-
export { knowledgeList, knowledgeSearch, knowledgeImport, knowledgeDecay, knowledgeStats, knowledgeUpsert, knowledgeSyncStatus, knowledgeSyncRag, type KnowledgeOptions, type KnowledgeUpsertOptions } from './knowledge';
|
|
20
|
+
export { knowledgeList, knowledgeSearch, knowledgeImport, knowledgeDecay, knowledgeStats, knowledgeUpsert, knowledgeSyncStatus, knowledgeSyncRag, knowledgeAudit, knowledgeSnapshot, knowledgeMigrate, type KnowledgeOptions, type KnowledgeUpsertOptions } from './knowledge';
|
|
21
21
|
export { failureList, failureStats, failureClear, type FailureOptions } from './failure';
|
|
22
22
|
export { postevalPlan, type PostEvalPlanOptions } from './posteval-plan';
|
|
23
23
|
export { release, type ReleaseOptions } from './release';
|
|
@@ -6,10 +6,14 @@
|
|
|
6
6
|
|
|
7
7
|
import chalk from 'chalk';
|
|
8
8
|
import * as fs from 'fs';
|
|
9
|
-
import
|
|
9
|
+
import * as os from 'os';
|
|
10
|
+
import * as path from 'path';
|
|
11
|
+
import { FileKnowledgeStore as KnowledgeStore } from '../../knowledge/store';
|
|
10
12
|
import { KnowledgeQuery } from '../../knowledge/query';
|
|
11
13
|
import { KnowledgeLifecycle } from '../../knowledge/lifecycle';
|
|
12
14
|
import { ColdStartImporter } from '../../knowledge/import';
|
|
15
|
+
import { KnowledgeAudit } from '../../knowledge/audit';
|
|
16
|
+
import { migrateKnowledgeEntries } from '../../knowledge/migration';
|
|
13
17
|
import type { KnowledgeType, MaturityLevel, QueryFilter } from '../../knowledge/types';
|
|
14
18
|
|
|
15
19
|
export interface KnowledgeOptions {
|
|
@@ -201,6 +205,7 @@ export async function knowledgeDecay(options: KnowledgeOptions): Promise<void> {
|
|
|
201
205
|
export async function knowledgeStats(options: KnowledgeOptions): Promise<void> {
|
|
202
206
|
const store = new KnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath) });
|
|
203
207
|
const entries = store.list({ excludeArchived: false });
|
|
208
|
+
const active = entries.filter(e => e.maturity !== 'archived');
|
|
204
209
|
|
|
205
210
|
const byType: Record<string, number> = {};
|
|
206
211
|
const byMaturity: Record<string, number> = {};
|
|
@@ -212,13 +217,31 @@ export async function knowledgeStats(options: KnowledgeOptions): Promise<void> {
|
|
|
212
217
|
byLayer[entry.layer] = (byLayer[entry.layer] || 0) + 1;
|
|
213
218
|
}
|
|
214
219
|
|
|
220
|
+
// D6 flywheel metrics
|
|
221
|
+
const withRefs = active.filter(e => e.referencedBy.length > 0).length;
|
|
222
|
+
const refCoverage = active.length > 0 ? Math.round(withRefs / active.length * 100) : 0;
|
|
223
|
+
const avgRefs = active.length > 0
|
|
224
|
+
? Math.round(active.reduce((sum, e) => sum + e.referencedBy.length, 0) / active.length * 10) / 10
|
|
225
|
+
: 0;
|
|
226
|
+
let consumptionHitRate = 0;
|
|
227
|
+
try {
|
|
228
|
+
const statsPath = path.join(store.getBaseDir(), '.consumption-stats.json');
|
|
229
|
+
if (fs.existsSync(statsPath)) {
|
|
230
|
+
const stats = JSON.parse(fs.readFileSync(statsPath, 'utf-8'));
|
|
231
|
+
const dailyEvents = stats.dailyEvents || 0;
|
|
232
|
+
consumptionHitRate = active.length > 0 ? Math.min(Math.round(dailyEvents / active.length * 100), 100) : 0;
|
|
233
|
+
}
|
|
234
|
+
} catch { /* best-effort */ }
|
|
235
|
+
|
|
236
|
+
const flywheel = { refCoverage, avgRefs, consumptionHitRate };
|
|
237
|
+
|
|
215
238
|
if (options.json) {
|
|
216
|
-
console.log(JSON.stringify({ total: entries.length, byType, byMaturity, byLayer }, null, 2));
|
|
239
|
+
console.log(JSON.stringify({ total: entries.length, byType, byMaturity, byLayer, flywheel }, null, 2));
|
|
217
240
|
return;
|
|
218
241
|
}
|
|
219
242
|
|
|
220
243
|
console.log(chalk.blue(`📊 知识库统计\n`));
|
|
221
|
-
console.log(chalk.bold(` 总计: ${entries.length}
|
|
244
|
+
console.log(chalk.bold(` 总计: ${entries.length} 条 (活跃: ${active.length})\n`));
|
|
222
245
|
|
|
223
246
|
console.log(chalk.bold(' 按类型:'));
|
|
224
247
|
for (const [type, count] of Object.entries(byType)) {
|
|
@@ -235,6 +258,11 @@ export async function knowledgeStats(options: KnowledgeOptions): Promise<void> {
|
|
|
235
258
|
for (const [layer, count] of Object.entries(byLayer)) {
|
|
236
259
|
console.log(` ${layer}: ${count}`);
|
|
237
260
|
}
|
|
261
|
+
|
|
262
|
+
console.log(chalk.bold('\n 飞轮指标:'));
|
|
263
|
+
console.log(` 引用覆盖: ${refCoverage}%`);
|
|
264
|
+
console.log(` 平均引用: ${avgRefs}`);
|
|
265
|
+
console.log(` 消费命中率: ${consumptionHitRate}%`);
|
|
238
266
|
}
|
|
239
267
|
|
|
240
268
|
export interface KnowledgeUpsertOptions {
|
|
@@ -386,6 +414,149 @@ export async function knowledgeSyncStatus(options: KnowledgeOptions): Promise<vo
|
|
|
386
414
|
}
|
|
387
415
|
|
|
388
416
|
function getKnowledgeDir(projectPath?: string): string {
|
|
389
|
-
|
|
390
|
-
return
|
|
417
|
+
if (projectPath) return `${projectPath}/.harness/knowledge`;
|
|
418
|
+
if (process.env.KNOWLEDGE_BASE_DIR) return process.env.KNOWLEDGE_BASE_DIR;
|
|
419
|
+
return path.join(os.homedir(), '.studio', 'knowledge');
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* 知识库质量审计
|
|
424
|
+
*/
|
|
425
|
+
export async function knowledgeAudit(options: KnowledgeOptions & {
|
|
426
|
+
fix?: boolean;
|
|
427
|
+
dryRun?: boolean;
|
|
428
|
+
threshold?: number;
|
|
429
|
+
dir?: string;
|
|
430
|
+
}): Promise<void> {
|
|
431
|
+
const audit = new KnowledgeAudit({
|
|
432
|
+
baseDir: options.dir || getKnowledgeDir(options.projectPath),
|
|
433
|
+
shortContentThreshold: options.threshold ? parseInt(options.threshold as any, 10) : undefined,
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
const isDryRun = options.dryRun && !options.fix;
|
|
437
|
+
|
|
438
|
+
if (!options.json && !isDryRun) {
|
|
439
|
+
console.log(chalk.blue('🔍 知识库质量审计...\n'));
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const report = audit.run({ autoFix: options.fix && !isDryRun });
|
|
443
|
+
|
|
444
|
+
if (options.json) {
|
|
445
|
+
console.log(JSON.stringify(report, null, 2));
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// Summary
|
|
450
|
+
console.log(chalk.bold(` 总条目: ${report.totalEntries}`));
|
|
451
|
+
console.log(chalk.bold(` 健康分: ${report.healthScore.before}/100`));
|
|
452
|
+
if (report.autoFixed > 0) {
|
|
453
|
+
console.log(chalk.green(` 自动修复: ${report.autoFixed} 条`));
|
|
454
|
+
console.log(chalk.bold(` 修复后: ${report.healthScore.after}/100`));
|
|
455
|
+
}
|
|
456
|
+
console.log();
|
|
457
|
+
|
|
458
|
+
// Dimension scores
|
|
459
|
+
const dimLabels: Record<string, string> = {
|
|
460
|
+
structure: 'D1 结构完整性',
|
|
461
|
+
content: 'D2 内容质量',
|
|
462
|
+
dedup: 'D3 去重有效性',
|
|
463
|
+
maturity: 'D4 成熟度健康',
|
|
464
|
+
freshness: 'D5 新鲜度',
|
|
465
|
+
flywheel: 'D6 飞轮验证',
|
|
466
|
+
};
|
|
467
|
+
console.log(chalk.bold(' 维度评分:'));
|
|
468
|
+
for (const [key, dim] of Object.entries(report.dimensions)) {
|
|
469
|
+
const label = dimLabels[key] || key;
|
|
470
|
+
const scoreColor = dim.score >= 80 ? chalk.green : dim.score >= 60 ? chalk.yellow : chalk.red;
|
|
471
|
+
console.log(` ${label}: ${scoreColor(`${dim.score}/100`)} (${dim.issues} 问题)`);
|
|
472
|
+
}
|
|
473
|
+
console.log();
|
|
474
|
+
|
|
475
|
+
// Issues by rule
|
|
476
|
+
const ruleLabels: Record<string, string> = {
|
|
477
|
+
'frontmatter-missing': 'frontmatter 缺失',
|
|
478
|
+
'test-data-pollution': '测试数据污染',
|
|
479
|
+
'daily-audit-noise': '每日审计噪音',
|
|
480
|
+
'zero-content-proven': '零内容 proven',
|
|
481
|
+
'short-content': '短内容',
|
|
482
|
+
'maturity-inflation': '成熟度虚高',
|
|
483
|
+
'title-duplicate': '标题重复',
|
|
484
|
+
'source-refs-bloat': 'sourceReferences 膨胀',
|
|
485
|
+
'promotion-blocked': 'promotion 受阻',
|
|
486
|
+
'orphan-draft': '孤儿 draft',
|
|
487
|
+
'stale-entry': '过期条目',
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
for (const [rule, count] of Object.entries(report.summary)) {
|
|
491
|
+
if (count === 0) continue;
|
|
492
|
+
const label = ruleLabels[rule] || rule;
|
|
493
|
+
console.log(` ${chalk.red(`${label}: ${count}`)}`);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// Detail (first 20)
|
|
497
|
+
if (report.issues.length > 0) {
|
|
498
|
+
console.log(chalk.bold(`\n 问题详情 (前 20 条):\n`));
|
|
499
|
+
for (const issue of report.issues.slice(0, 20)) {
|
|
500
|
+
const severityColor = issue.severity === 'critical' ? chalk.red
|
|
501
|
+
: issue.severity === 'high' ? chalk.yellow
|
|
502
|
+
: chalk.gray;
|
|
503
|
+
console.log(` ${severityColor(`[${issue.severity}]`)} ${issue.entryId}: ${issue.title}`);
|
|
504
|
+
console.log(` ${chalk.gray(issue.detail)} → ${issue.action}`);
|
|
505
|
+
}
|
|
506
|
+
if (report.issues.length > 20) {
|
|
507
|
+
console.log(chalk.gray(`\n ... 还有 ${report.issues.length - 20} 条`));
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
if (!options.fix && report.issues.length > 0) {
|
|
512
|
+
console.log(chalk.yellow(`\n 使用 --fix 自动修复`));
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* 知识库快照(KR4 存活率追踪)
|
|
518
|
+
*/
|
|
519
|
+
export function knowledgeSnapshot(options: KnowledgeOptions & { dir?: string }): void {
|
|
520
|
+
const store = new KnowledgeStore({ baseDir: options.dir || getKnowledgeDir(options.projectPath) });
|
|
521
|
+
const snapPath = store.snapshot();
|
|
522
|
+
|
|
523
|
+
if (options.json) {
|
|
524
|
+
console.log(JSON.stringify({ snapshotPath: snapPath }));
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
console.log(chalk.green(`✅ 快照已保存: ${snapPath}`));
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* 知识库迁移 — 为现有条目添加 AS-021 新字段
|
|
533
|
+
*/
|
|
534
|
+
export function knowledgeMigrate(options: KnowledgeOptions & { dir?: string }): void {
|
|
535
|
+
const baseDir = options.dir || getKnowledgeDir(options.projectPath);
|
|
536
|
+
|
|
537
|
+
if (options.json) {
|
|
538
|
+
const result = migrateKnowledgeEntries(baseDir);
|
|
539
|
+
console.log(JSON.stringify(result, null, 2));
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
console.log(chalk.blue('🔄 迁移知识条目(添加 consumptionMode/origin 字段)\n'));
|
|
544
|
+
const result = migrateKnowledgeEntries(baseDir);
|
|
545
|
+
|
|
546
|
+
console.log(chalk.green(` 总计: ${result.total} 条`));
|
|
547
|
+
console.log(chalk.green(` 已迁移: ${result.migrated} 条`));
|
|
548
|
+
console.log(chalk.gray(` 已跳过: ${result.skipped} 条`));
|
|
549
|
+
|
|
550
|
+
if (result.errors.length > 0) {
|
|
551
|
+
console.log(chalk.red(`\n 错误: ${result.errors.length} 条`));
|
|
552
|
+
for (const err of result.errors.slice(0, 5)) {
|
|
553
|
+
console.log(chalk.red(` ${err}`));
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
if (result.migrated === 0 && result.errors.length === 0) {
|
|
558
|
+
console.log(chalk.green('\n✅ 所有条目已是最新,无需迁移'));
|
|
559
|
+
} else if (result.migrated > 0) {
|
|
560
|
+
console.log(chalk.green(`\n✅ 迁移完成`));
|
|
561
|
+
}
|
|
391
562
|
}
|