@productbrain/cli 0.1.0-beta.27 → 0.1.0-beta.29
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/README.md +2 -0
- package/dist/__tests__/relate.test.js +15 -0
- package/dist/__tests__/relate.test.js.map +1 -1
- package/dist/commands/collections.d.ts +22 -0
- package/dist/commands/collections.d.ts.map +1 -0
- package/dist/commands/collections.js +73 -0
- package/dist/commands/collections.js.map +1 -0
- package/dist/commands/handshake.d.ts +2 -0
- package/dist/commands/handshake.d.ts.map +1 -1
- package/dist/commands/handshake.js +37 -1
- package/dist/commands/handshake.js.map +1 -1
- package/dist/commands/relate.d.ts.map +1 -1
- package/dist/commands/relate.js +10 -3
- package/dist/commands/relate.js.map +1 -1
- package/dist/formatters/collections.d.ts +40 -0
- package/dist/formatters/collections.d.ts.map +1 -0
- package/dist/formatters/collections.js +93 -0
- package/dist/formatters/collections.js.map +1 -0
- package/dist/formatters/handshake.d.ts +5 -0
- package/dist/formatters/handshake.d.ts.map +1 -1
- package/dist/formatters/handshake.js +9 -0
- package/dist/formatters/handshake.js.map +1 -1
- package/dist/formatters/relate.d.ts +2 -0
- package/dist/formatters/relate.d.ts.map +1 -1
- package/dist/formatters/relate.js +3 -0
- package/dist/formatters/relate.js.map +1 -1
- package/dist/generators/archetypes.d.ts +52 -0
- package/dist/generators/archetypes.d.ts.map +1 -0
- package/dist/generators/archetypes.js +153 -0
- package/dist/generators/archetypes.js.map +1 -0
- package/dist/generators/archetypes.test.d.ts +2 -0
- package/dist/generators/archetypes.test.d.ts.map +1 -0
- package/dist/generators/archetypes.test.js +237 -0
- package/dist/generators/archetypes.test.js.map +1 -0
- package/dist/generators/chain-classifier.d.ts +49 -0
- package/dist/generators/chain-classifier.d.ts.map +1 -0
- package/dist/generators/chain-classifier.js +180 -0
- package/dist/generators/chain-classifier.js.map +1 -0
- package/dist/generators/chain-classifier.test.d.ts +2 -0
- package/dist/generators/chain-classifier.test.d.ts.map +1 -0
- package/dist/generators/chain-classifier.test.js +257 -0
- package/dist/generators/chain-classifier.test.js.map +1 -0
- package/dist/generators/chain-rules.d.ts +42 -0
- package/dist/generators/chain-rules.d.ts.map +1 -0
- package/dist/generators/chain-rules.js +144 -0
- package/dist/generators/chain-rules.js.map +1 -0
- package/dist/generators/chain-rules.test.d.ts +2 -0
- package/dist/generators/chain-rules.test.d.ts.map +1 -0
- package/dist/generators/chain-rules.test.js +179 -0
- package/dist/generators/chain-rules.test.js.map +1 -0
- package/dist/generators/handshake-diff.d.ts +67 -0
- package/dist/generators/handshake-diff.d.ts.map +1 -0
- package/dist/generators/handshake-diff.js +183 -0
- package/dist/generators/handshake-diff.js.map +1 -0
- package/dist/generators/handshake-diff.test.d.ts +2 -0
- package/dist/generators/handshake-diff.test.d.ts.map +1 -0
- package/dist/generators/handshake-diff.test.js +264 -0
- package/dist/generators/handshake-diff.test.js.map +1 -0
- package/dist/index.js +59 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/templates/archetypes/boundary.md +23 -0
- package/templates/archetypes/constraint.md +23 -0
- package/templates/archetypes/convention.md +23 -0
- package/templates/archetypes/policy.md +23 -0
- package/templates/archetypes/quality-gate.md +23 -0
- package/templates/archetypes/workflow.md +23 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain-rules.js","sourceRoot":"","sources":["../../src/generators/chain-rules.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain-rules.test.d.ts","sourceRoot":"","sources":["../../src/generators/chain-rules.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* chain-rules — unit tests.
|
|
3
|
+
* BET-286 Slice 3: chain rules assembler.
|
|
4
|
+
*/
|
|
5
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
6
|
+
import { generateChainRules } from './chain-rules.js';
|
|
7
|
+
// ── Helpers ────────────────────────────────────────────────────────────
|
|
8
|
+
function makeEntry(overrides) {
|
|
9
|
+
return {
|
|
10
|
+
status: 'active',
|
|
11
|
+
verificationStatus: 'verified',
|
|
12
|
+
data: null,
|
|
13
|
+
relations: [],
|
|
14
|
+
...overrides,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function makeManualRule(name) {
|
|
18
|
+
return {
|
|
19
|
+
name,
|
|
20
|
+
description: 'Manual rule',
|
|
21
|
+
body: 'Manual rule body',
|
|
22
|
+
sourcePath: `.productbrain/rules/${name}.md`,
|
|
23
|
+
autoApply: true,
|
|
24
|
+
level: 'core',
|
|
25
|
+
scope: undefined,
|
|
26
|
+
targets: undefined,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/** Mock mcpCall that returns the given entries wrapped in the Convex response shape. */
|
|
30
|
+
function mockMcpSuccess(entries) {
|
|
31
|
+
return vi.fn().mockResolvedValue({ entries, total: entries.length });
|
|
32
|
+
}
|
|
33
|
+
/** Mock mcpCall that throws. */
|
|
34
|
+
function mockMcpFailure(error = new Error('Network error')) {
|
|
35
|
+
return vi.fn().mockRejectedValue(error);
|
|
36
|
+
}
|
|
37
|
+
// ── Tests ──────────────────────────────────────────────────────────────
|
|
38
|
+
describe('generateChainRules', () => {
|
|
39
|
+
it('happy path: produces rules from classified entries', async () => {
|
|
40
|
+
const entries = [
|
|
41
|
+
makeEntry({ entryId: 'STD-1', name: 'No direct Convex imports', collectionSlug: 'standards' }),
|
|
42
|
+
makeEntry({ entryId: 'STD-2', name: 'Auth check on all routes', collectionSlug: 'business-rules' }),
|
|
43
|
+
makeEntry({ entryId: 'ARCH-1', name: 'Domain boundary rules', collectionSlug: 'architecture' }),
|
|
44
|
+
];
|
|
45
|
+
const mcpFn = mockMcpSuccess(entries);
|
|
46
|
+
const result = await generateChainRules(mcpFn, []);
|
|
47
|
+
expect(mcpFn).toHaveBeenCalledWith('chain.getGovernanceWithRelations', {});
|
|
48
|
+
expect(result.sentinel).toBeNull();
|
|
49
|
+
expect(result.rules.length).toBeGreaterThan(0);
|
|
50
|
+
// All generated rules must have chain:// sourcePath
|
|
51
|
+
for (const rule of result.rules) {
|
|
52
|
+
expect(rule.sourcePath).toMatch(/^chain:\/\//);
|
|
53
|
+
}
|
|
54
|
+
expect(result.stats.totalEntries).toBe(3);
|
|
55
|
+
expect(result.stats.classifiedEntries).toBe(3);
|
|
56
|
+
});
|
|
57
|
+
it('MCP failure: returns sentinel rule and empty rules array', async () => {
|
|
58
|
+
const mcpFn = mockMcpFailure();
|
|
59
|
+
const result = await generateChainRules(mcpFn, []);
|
|
60
|
+
expect(result.rules).toHaveLength(0);
|
|
61
|
+
expect(result.sentinel).not.toBeNull();
|
|
62
|
+
expect(result.sentinel.name).toBe('_chain_degraded');
|
|
63
|
+
expect(result.sentinel.level).toBe('core');
|
|
64
|
+
expect(result.sentinel.sourcePath).toBe('chain://_sentinel');
|
|
65
|
+
expect(result.sentinel.autoApply).toBe(true);
|
|
66
|
+
expect(result.gaps).toHaveLength(0);
|
|
67
|
+
expect(result.stats.totalEntries).toBe(0);
|
|
68
|
+
});
|
|
69
|
+
it('manual suppression: existing manual rule suppresses generated rule', async () => {
|
|
70
|
+
// 'chain-constraints' is the archetype name for 'constraint' function
|
|
71
|
+
const entries = [
|
|
72
|
+
makeEntry({ entryId: 'STD-1', name: 'No direct imports', collectionSlug: 'standards' }),
|
|
73
|
+
];
|
|
74
|
+
const mcpFn = mockMcpSuccess(entries);
|
|
75
|
+
const manualRules = [makeManualRule('chain-constraints')];
|
|
76
|
+
const result = await generateChainRules(mcpFn, manualRules);
|
|
77
|
+
// The constraint archetype should be suppressed since manual rule with same name exists
|
|
78
|
+
const constraintRule = result.rules.find((r) => r.sourcePath === 'chain://constraint');
|
|
79
|
+
expect(constraintRule).toBeUndefined();
|
|
80
|
+
expect(result.stats.suppressedByManual).toBeGreaterThan(0);
|
|
81
|
+
});
|
|
82
|
+
it('zero entries: function with no matching entries appears in gaps', async () => {
|
|
83
|
+
// Only provide boundary entries — all other functions should gap
|
|
84
|
+
const entries = [
|
|
85
|
+
makeEntry({ entryId: 'ARCH-1', name: 'Domain layers', collectionSlug: 'architecture' }),
|
|
86
|
+
];
|
|
87
|
+
const mcpFn = mockMcpSuccess(entries);
|
|
88
|
+
const result = await generateChainRules(mcpFn, []);
|
|
89
|
+
// boundary gets a rule; others go to gaps
|
|
90
|
+
expect(result.gaps.length).toBeGreaterThan(0);
|
|
91
|
+
// 'workflow', 'convention', 'policy', 'quality-gate', 'constraint' should be in gaps
|
|
92
|
+
expect(result.gaps).toContain('workflow');
|
|
93
|
+
expect(result.gaps).toContain('constraint');
|
|
94
|
+
expect(result.stats.suppressedByZeroEntries).toBe(result.gaps.length);
|
|
95
|
+
});
|
|
96
|
+
it('caps at 8 rules: 9+ entries across functions → only top 8', async () => {
|
|
97
|
+
// Provide entries for all 6 functions — but we only have 6 functions so need
|
|
98
|
+
// to test with all 6 populated. The cap of 8 means all 6 pass through here.
|
|
99
|
+
// To test capping we need to produce more than 8. Since we only have 6
|
|
100
|
+
// governance functions, 6 is the max. So we verify the cap does not drop below 6.
|
|
101
|
+
// The cap only fires when a future function count exceeds 8.
|
|
102
|
+
// We still verify that when fewer than 8 rules exist, all are returned.
|
|
103
|
+
const entries = [
|
|
104
|
+
makeEntry({ entryId: 'STD-1', name: 'Import rule', collectionSlug: 'standards' }),
|
|
105
|
+
makeEntry({ entryId: 'ARCH-1', name: 'Domain layers', collectionSlug: 'architecture' }),
|
|
106
|
+
makeEntry({ entryId: 'DEC-1', name: 'Deploy convention', collectionSlug: 'decisions' }),
|
|
107
|
+
makeEntry({ entryId: 'POL-1', name: 'Auth policy', collectionSlug: 'policies' }),
|
|
108
|
+
makeEntry({ entryId: 'FLO-1', name: 'Capture flow', collectionSlug: 'flows' }),
|
|
109
|
+
];
|
|
110
|
+
const mcpFn = mockMcpSuccess(entries);
|
|
111
|
+
const result = await generateChainRules(mcpFn, []);
|
|
112
|
+
// 5 entries across different functions → at most 5 rules, well under the cap of 8
|
|
113
|
+
expect(result.rules.length).toBeLessThanOrEqual(8);
|
|
114
|
+
});
|
|
115
|
+
it('cap at 8 rules enforced when more than 8 rules would be generated', async () => {
|
|
116
|
+
// We cannot generate more than 6 rules (only 6 functions), so we test the
|
|
117
|
+
// ranking/sorting logic and confirm the result is <= 8.
|
|
118
|
+
// Provide entries with dense relations to test ranking path.
|
|
119
|
+
const entries = [
|
|
120
|
+
makeEntry({
|
|
121
|
+
entryId: 'STD-1',
|
|
122
|
+
name: 'Import constraint',
|
|
123
|
+
collectionSlug: 'standards',
|
|
124
|
+
relations: [
|
|
125
|
+
{ type: 'constrains', direction: 'outgoing', otherEntryId: 'BET-1', otherName: 'BET-1', otherCollectionSlug: 'bets' },
|
|
126
|
+
{ type: 'constrains', direction: 'outgoing', otherEntryId: 'BET-2', otherName: 'BET-2', otherCollectionSlug: 'bets' },
|
|
127
|
+
],
|
|
128
|
+
}),
|
|
129
|
+
makeEntry({
|
|
130
|
+
entryId: 'ARCH-1',
|
|
131
|
+
name: 'Layer boundaries',
|
|
132
|
+
collectionSlug: 'architecture',
|
|
133
|
+
relations: [
|
|
134
|
+
{ type: 'informed_by', direction: 'incoming', otherEntryId: 'DEC-1', otherName: 'DEC-1', otherCollectionSlug: 'architecture' },
|
|
135
|
+
],
|
|
136
|
+
}),
|
|
137
|
+
];
|
|
138
|
+
const mcpFn = mockMcpSuccess(entries);
|
|
139
|
+
const result = await generateChainRules(mcpFn, []);
|
|
140
|
+
expect(result.rules.length).toBeLessThanOrEqual(8);
|
|
141
|
+
// Rules are sorted — verify stable output
|
|
142
|
+
for (const rule of result.rules) {
|
|
143
|
+
expect(rule.sourcePath).toMatch(/^chain:\/\//);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
it('empty workspace: no governance entries → empty rules, all functions in gaps', async () => {
|
|
147
|
+
const mcpFn = mockMcpSuccess([]);
|
|
148
|
+
const result = await generateChainRules(mcpFn, []);
|
|
149
|
+
expect(result.rules).toHaveLength(0);
|
|
150
|
+
expect(result.sentinel).toBeNull();
|
|
151
|
+
expect(result.gaps).toHaveLength(6); // all 6 functions gap
|
|
152
|
+
expect(result.gaps).toContain('constraint');
|
|
153
|
+
expect(result.gaps).toContain('boundary');
|
|
154
|
+
expect(result.gaps).toContain('convention');
|
|
155
|
+
expect(result.gaps).toContain('policy');
|
|
156
|
+
expect(result.gaps).toContain('workflow');
|
|
157
|
+
expect(result.gaps).toContain('quality-gate');
|
|
158
|
+
expect(result.stats.totalEntries).toBe(0);
|
|
159
|
+
expect(result.stats.classifiedEntries).toBe(0);
|
|
160
|
+
expect(result.stats.generatedRules).toBe(0);
|
|
161
|
+
expect(result.stats.suppressedByZeroEntries).toBe(6);
|
|
162
|
+
});
|
|
163
|
+
it('stats are accurate: counts match actual outcomes', async () => {
|
|
164
|
+
const entries = [
|
|
165
|
+
makeEntry({ entryId: 'STD-1', name: 'Import rule', collectionSlug: 'standards' }),
|
|
166
|
+
makeEntry({ entryId: 'STD-2', name: 'Null check rule', collectionSlug: 'standards' }),
|
|
167
|
+
];
|
|
168
|
+
const mcpFn = mockMcpSuccess(entries);
|
|
169
|
+
const result = await generateChainRules(mcpFn, []);
|
|
170
|
+
expect(result.stats.totalEntries).toBe(2);
|
|
171
|
+
expect(result.stats.classifiedEntries).toBe(2);
|
|
172
|
+
// generatedRules + suppressedByManual + suppressedByZeroEntries = 6 (total governance functions)
|
|
173
|
+
const total = result.stats.generatedRules + result.stats.suppressedByManual + result.stats.suppressedByZeroEntries;
|
|
174
|
+
expect(total).toBe(6);
|
|
175
|
+
// gaps length equals suppressedByZeroEntries
|
|
176
|
+
expect(result.gaps.length).toBe(result.stats.suppressedByZeroEntries);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
//# sourceMappingURL=chain-rules.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain-rules.test.js","sourceRoot":"","sources":["../../src/generators/chain-rules.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handshake Diff — BET-286 Slice 4
|
|
3
|
+
*
|
|
4
|
+
* Persists handshake --generate state between runs and produces a diff
|
|
5
|
+
* showing what changed (added, removed, changed rules) since the last run.
|
|
6
|
+
*
|
|
7
|
+
* Chain: BET-286 (Chain-Derived Agent Configuration)
|
|
8
|
+
*/
|
|
9
|
+
import type { CanonicalRule } from './portable-knowledge.js';
|
|
10
|
+
import type { ClassifiedGovernance } from './chain-classifier.js';
|
|
11
|
+
/** Persisted record of a single generated rule from a handshake --generate run. */
|
|
12
|
+
export interface HandshakeStateRule {
|
|
13
|
+
name: string;
|
|
14
|
+
/** Governance function key, e.g. 'constraint', 'boundary' */
|
|
15
|
+
functionKey: string;
|
|
16
|
+
/** Source path, always 'chain://<functionKey>' for generated rules */
|
|
17
|
+
sourcePath: string;
|
|
18
|
+
/** Classifier confidence for the winning function (averaged across contributing entries) */
|
|
19
|
+
confidence: number;
|
|
20
|
+
/** Entry IDs that contributed to this rule */
|
|
21
|
+
entryIds: string[];
|
|
22
|
+
}
|
|
23
|
+
/** Persisted state written after each handshake --generate run. */
|
|
24
|
+
export interface HandshakeState {
|
|
25
|
+
timestamp: string;
|
|
26
|
+
rules: HandshakeStateRule[];
|
|
27
|
+
}
|
|
28
|
+
/** A single rule change detected by diffHandshakeState(). */
|
|
29
|
+
export interface RuleDiff {
|
|
30
|
+
name: string;
|
|
31
|
+
change: 'added' | 'removed' | 'changed';
|
|
32
|
+
/** Human-readable change detail, e.g. "confidence: 0.7 → 0.9" or "entries: +STD-22, -STD-7" */
|
|
33
|
+
details?: string;
|
|
34
|
+
}
|
|
35
|
+
/** Full diff result comparing current state to previous state. */
|
|
36
|
+
export interface HandshakeDiff {
|
|
37
|
+
added: RuleDiff[];
|
|
38
|
+
removed: RuleDiff[];
|
|
39
|
+
changed: RuleDiff[];
|
|
40
|
+
isFirstRun: boolean;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Build a HandshakeState in memory from rules and classified entries.
|
|
44
|
+
* Only includes chain:// sourced rules (ignores manual rules).
|
|
45
|
+
* Filters out the sentinel rule (chain://_sentinel) to avoid diff noise.
|
|
46
|
+
*/
|
|
47
|
+
export declare function buildCurrentState(rules: CanonicalRule[], classified: ClassifiedGovernance[]): HandshakeState;
|
|
48
|
+
/**
|
|
49
|
+
* Save current handshake state to .productbrain/.handshake-state.json.
|
|
50
|
+
* Only persists chain:// sourced rules (ignores manual rules and sentinel).
|
|
51
|
+
*/
|
|
52
|
+
export declare function saveHandshakeState(pbDir: string, rules: CanonicalRule[], classified: ClassifiedGovernance[]): void;
|
|
53
|
+
/**
|
|
54
|
+
* Load previous handshake state from .productbrain/.handshake-state.json.
|
|
55
|
+
* Returns null if no previous state exists or the file cannot be parsed.
|
|
56
|
+
*/
|
|
57
|
+
export declare function loadPreviousState(pbDir: string): HandshakeState | null;
|
|
58
|
+
/**
|
|
59
|
+
* Compare current rules against previous state and produce a diff.
|
|
60
|
+
* When previous is null, all current rules are reported as added (first run).
|
|
61
|
+
*/
|
|
62
|
+
export declare function diffHandshakeState(current: HandshakeState, previous: HandshakeState | null): HandshakeDiff;
|
|
63
|
+
/**
|
|
64
|
+
* Format a HandshakeDiff for console output.
|
|
65
|
+
*/
|
|
66
|
+
export declare function formatDiff(diff: HandshakeDiff): string;
|
|
67
|
+
//# sourceMappingURL=handshake-diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handshake-diff.d.ts","sourceRoot":"","sources":["../../src/generators/handshake-diff.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAIlE,mFAAmF;AACnF,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,WAAW,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,UAAU,EAAE,MAAM,CAAC;IACnB,4FAA4F;IAC5F,UAAU,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,mEAAmE;AACnE,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,kBAAkB,EAAE,CAAC;CAC7B;AAED,6DAA6D;AAC7D,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;IACxC,+FAA+F;IAC/F,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,kEAAkE;AAClE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;CACrB;AAyCD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,aAAa,EAAE,EACtB,UAAU,EAAE,oBAAoB,EAAE,GACjC,cAAc,CAShB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,aAAa,EAAE,EACtB,UAAU,EAAE,oBAAoB,EAAE,GACjC,IAAI,CAGN;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAWtE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,cAAc,GAAG,IAAI,GAC9B,aAAa,CAuDf;AA+BD;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CA4BtD"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handshake Diff — BET-286 Slice 4
|
|
3
|
+
*
|
|
4
|
+
* Persists handshake --generate state between runs and produces a diff
|
|
5
|
+
* showing what changed (added, removed, changed rules) since the last run.
|
|
6
|
+
*
|
|
7
|
+
* Chain: BET-286 (Chain-Derived Agent Configuration)
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, readFileSync, writeFileSync } from 'fs';
|
|
10
|
+
import { join } from 'path';
|
|
11
|
+
// ── State file path ────────────────────────────────────────────────────
|
|
12
|
+
const STATE_FILENAME = '.handshake-state.json';
|
|
13
|
+
function stateFilePath(pbDir) {
|
|
14
|
+
return join(pbDir, STATE_FILENAME);
|
|
15
|
+
}
|
|
16
|
+
// ── State builder ─────────────────────────────────────────────────────
|
|
17
|
+
/**
|
|
18
|
+
* Build a HandshakeStateRule from a CanonicalRule and classified governance entries.
|
|
19
|
+
* Only applies to chain:// sourced rules.
|
|
20
|
+
*/
|
|
21
|
+
function buildStateRule(rule, classified) {
|
|
22
|
+
// Extract function key from sourcePath ('chain://<functionKey>')
|
|
23
|
+
const functionKey = rule.sourcePath.replace('chain://', '');
|
|
24
|
+
// Find all entries that classified to this governance function
|
|
25
|
+
const matching = classified.filter((e) => e.governanceFunction === functionKey);
|
|
26
|
+
const entryIds = matching.map((e) => e.entryId);
|
|
27
|
+
// Average confidence across contributing entries (0 if none matched)
|
|
28
|
+
const confidence = matching.length > 0
|
|
29
|
+
? Math.round((matching.reduce((sum, e) => sum + e.confidence, 0) / matching.length) * 100) / 100
|
|
30
|
+
: 0;
|
|
31
|
+
return {
|
|
32
|
+
name: rule.name,
|
|
33
|
+
functionKey,
|
|
34
|
+
sourcePath: rule.sourcePath,
|
|
35
|
+
confidence,
|
|
36
|
+
entryIds,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
// ── Public API ─────────────────────────────────────────────────────────
|
|
40
|
+
/**
|
|
41
|
+
* Build a HandshakeState in memory from rules and classified entries.
|
|
42
|
+
* Only includes chain:// sourced rules (ignores manual rules).
|
|
43
|
+
* Filters out the sentinel rule (chain://_sentinel) to avoid diff noise.
|
|
44
|
+
*/
|
|
45
|
+
export function buildCurrentState(rules, classified) {
|
|
46
|
+
const chainRules = rules.filter((r) => r.sourcePath.startsWith('chain://') && r.sourcePath !== 'chain://_sentinel');
|
|
47
|
+
return {
|
|
48
|
+
timestamp: new Date().toISOString(),
|
|
49
|
+
rules: chainRules.map((r) => buildStateRule(r, classified)),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Save current handshake state to .productbrain/.handshake-state.json.
|
|
54
|
+
* Only persists chain:// sourced rules (ignores manual rules and sentinel).
|
|
55
|
+
*/
|
|
56
|
+
export function saveHandshakeState(pbDir, rules, classified) {
|
|
57
|
+
const state = buildCurrentState(rules, classified);
|
|
58
|
+
writeFileSync(stateFilePath(pbDir), JSON.stringify(state, null, 2) + '\n');
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Load previous handshake state from .productbrain/.handshake-state.json.
|
|
62
|
+
* Returns null if no previous state exists or the file cannot be parsed.
|
|
63
|
+
*/
|
|
64
|
+
export function loadPreviousState(pbDir) {
|
|
65
|
+
const filePath = stateFilePath(pbDir);
|
|
66
|
+
if (!existsSync(filePath))
|
|
67
|
+
return null;
|
|
68
|
+
try {
|
|
69
|
+
const raw = readFileSync(filePath, 'utf8');
|
|
70
|
+
return JSON.parse(raw);
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
process.stderr.write(`Warning: failed to parse ${filePath} — ${err instanceof Error ? err.message : err}\n`);
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Compare current rules against previous state and produce a diff.
|
|
79
|
+
* When previous is null, all current rules are reported as added (first run).
|
|
80
|
+
*/
|
|
81
|
+
export function diffHandshakeState(current, previous) {
|
|
82
|
+
if (previous === null) {
|
|
83
|
+
return {
|
|
84
|
+
added: current.rules.map((r) => ({
|
|
85
|
+
name: r.name,
|
|
86
|
+
change: 'added',
|
|
87
|
+
details: `confidence: ${r.confidence}, ${r.entryIds.length} entries`,
|
|
88
|
+
})),
|
|
89
|
+
removed: [],
|
|
90
|
+
changed: [],
|
|
91
|
+
isFirstRun: true,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
const currentByName = new Map(current.rules.map((r) => [r.name, r]));
|
|
95
|
+
const previousByName = new Map(previous.rules.map((r) => [r.name, r]));
|
|
96
|
+
const added = [];
|
|
97
|
+
const removed = [];
|
|
98
|
+
const changed = [];
|
|
99
|
+
// Added: in current but not previous
|
|
100
|
+
for (const [name, rule] of currentByName) {
|
|
101
|
+
if (!previousByName.has(name)) {
|
|
102
|
+
added.push({
|
|
103
|
+
name,
|
|
104
|
+
change: 'added',
|
|
105
|
+
details: `confidence: ${rule.confidence}, ${rule.entryIds.length} entries`,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Removed: in previous but not current
|
|
110
|
+
for (const [name] of previousByName) {
|
|
111
|
+
if (!currentByName.has(name)) {
|
|
112
|
+
removed.push({
|
|
113
|
+
name,
|
|
114
|
+
change: 'removed',
|
|
115
|
+
details: 'removed — no matching entries',
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Changed: in both but different
|
|
120
|
+
for (const [name, curr] of currentByName) {
|
|
121
|
+
const prev = previousByName.get(name);
|
|
122
|
+
if (!prev)
|
|
123
|
+
continue; // handled as added above
|
|
124
|
+
const details = buildChangedDetails(prev, curr);
|
|
125
|
+
if (details !== null) {
|
|
126
|
+
changed.push({ name, change: 'changed', details });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return { added, removed, changed, isFirstRun: false };
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Build a details string for a changed rule. Returns null if no meaningful change detected.
|
|
133
|
+
*/
|
|
134
|
+
function buildChangedDetails(prev, curr) {
|
|
135
|
+
const parts = [];
|
|
136
|
+
// Confidence delta — only report if it changed
|
|
137
|
+
if (prev.confidence !== curr.confidence) {
|
|
138
|
+
parts.push(`confidence: ${prev.confidence} → ${curr.confidence}`);
|
|
139
|
+
}
|
|
140
|
+
// Entry changes — compute added/removed entry IDs
|
|
141
|
+
const prevSet = new Set(prev.entryIds);
|
|
142
|
+
const currSet = new Set(curr.entryIds);
|
|
143
|
+
const addedEntries = curr.entryIds.filter((id) => !prevSet.has(id));
|
|
144
|
+
const removedEntries = prev.entryIds.filter((id) => !currSet.has(id));
|
|
145
|
+
if (addedEntries.length > 0 || removedEntries.length > 0) {
|
|
146
|
+
const entryParts = [];
|
|
147
|
+
if (addedEntries.length > 0)
|
|
148
|
+
entryParts.push(...addedEntries.map((id) => `+${id}`));
|
|
149
|
+
if (removedEntries.length > 0)
|
|
150
|
+
entryParts.push(...removedEntries.map((id) => `-${id}`));
|
|
151
|
+
parts.push(`entries: ${entryParts.join(', ')}`);
|
|
152
|
+
}
|
|
153
|
+
if (parts.length === 0)
|
|
154
|
+
return null;
|
|
155
|
+
return parts.join(', ');
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Format a HandshakeDiff for console output.
|
|
159
|
+
*/
|
|
160
|
+
export function formatDiff(diff) {
|
|
161
|
+
if (diff.isFirstRun) {
|
|
162
|
+
return 'First run — no previous state to compare.';
|
|
163
|
+
}
|
|
164
|
+
const hasChanges = diff.added.length > 0 || diff.removed.length > 0 || diff.changed.length > 0;
|
|
165
|
+
if (!hasChanges) {
|
|
166
|
+
return 'No changes.';
|
|
167
|
+
}
|
|
168
|
+
const lines = ['Handshake diff (vs previous run):'];
|
|
169
|
+
for (const rule of diff.added) {
|
|
170
|
+
const detail = rule.details ? ` (${rule.details})` : '';
|
|
171
|
+
lines.push(` + ${rule.name}${detail}`);
|
|
172
|
+
}
|
|
173
|
+
for (const rule of diff.removed) {
|
|
174
|
+
const detail = rule.details ? ` (${rule.details})` : '';
|
|
175
|
+
lines.push(` - ${rule.name}${detail}`);
|
|
176
|
+
}
|
|
177
|
+
for (const rule of diff.changed) {
|
|
178
|
+
const detail = rule.details ? ` (${rule.details})` : '';
|
|
179
|
+
lines.push(` ~ ${rule.name}${detail}`);
|
|
180
|
+
}
|
|
181
|
+
return lines.join('\n');
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=handshake-diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handshake-diff.js","sourceRoot":"","sources":["../../src/generators/handshake-diff.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handshake-diff.test.d.ts","sourceRoot":"","sources":["../../src/generators/handshake-diff.test.ts"],"names":[],"mappings":""}
|