@productbrain/cli 0.1.0-beta.18 → 0.1.0-beta.22
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/dist/__tests__/adapters.test.d.ts +2 -0
- package/dist/__tests__/adapters.test.d.ts.map +1 -0
- package/dist/__tests__/adapters.test.js +382 -0
- package/dist/__tests__/adapters.test.js.map +1 -0
- package/dist/__tests__/batch-transformations.test.d.ts +2 -0
- package/dist/__tests__/batch-transformations.test.d.ts.map +1 -0
- package/dist/__tests__/batch-transformations.test.js +226 -0
- package/dist/__tests__/batch-transformations.test.js.map +1 -0
- package/dist/__tests__/repo-detect.test.js +97 -1
- package/dist/__tests__/repo-detect.test.js.map +1 -1
- package/dist/__tests__/surface-profiles.test.d.ts +2 -0
- package/dist/__tests__/surface-profiles.test.d.ts.map +1 -0
- package/dist/__tests__/surface-profiles.test.js +89 -0
- package/dist/__tests__/surface-profiles.test.js.map +1 -0
- package/dist/__tests__/update.test.js +26 -4
- package/dist/__tests__/update.test.js.map +1 -1
- package/dist/commands/capture.d.ts.map +1 -1
- package/dist/commands/capture.js +16 -2
- package/dist/commands/capture.js.map +1 -1
- package/dist/commands/codex-prep.d.ts +12 -0
- package/dist/commands/codex-prep.d.ts.map +1 -0
- package/dist/commands/codex-prep.js +118 -0
- package/dist/commands/codex-prep.js.map +1 -0
- package/dist/commands/handshake.d.ts.map +1 -1
- package/dist/commands/handshake.js +167 -17
- package/dist/commands/handshake.js.map +1 -1
- package/dist/commands/update.d.ts +1 -0
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +22 -2
- package/dist/commands/update.js.map +1 -1
- package/dist/formatters/capture.d.ts +3 -3
- package/dist/formatters/capture.d.ts.map +1 -1
- package/dist/formatters/capture.js +2 -1
- package/dist/formatters/capture.js.map +1 -1
- package/dist/formatters/entry.d.ts +0 -4
- package/dist/formatters/entry.d.ts.map +1 -1
- package/dist/formatters/entry.js +16 -13
- package/dist/formatters/entry.js.map +1 -1
- package/dist/formatters/handshake.d.ts +2 -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/search.d.ts +0 -4
- package/dist/formatters/search.d.ts.map +1 -1
- package/dist/formatters/search.js +4 -1
- package/dist/formatters/search.js.map +1 -1
- package/dist/formatters/update.d.ts.map +1 -1
- package/dist/formatters/update.js +2 -0
- package/dist/formatters/update.js.map +1 -1
- package/dist/generators/__tests__/surface-profiles.test.d.ts +2 -0
- package/dist/generators/__tests__/surface-profiles.test.d.ts.map +1 -0
- package/dist/generators/__tests__/surface-profiles.test.js +89 -0
- package/dist/generators/__tests__/surface-profiles.test.js.map +1 -0
- package/dist/generators/adapters.d.ts +37 -4
- package/dist/generators/adapters.d.ts.map +1 -1
- package/dist/generators/adapters.js +147 -7
- package/dist/generators/adapters.js.map +1 -1
- package/dist/generators/portable-knowledge.d.ts +70 -9
- package/dist/generators/portable-knowledge.d.ts.map +1 -1
- package/dist/generators/portable-knowledge.js +208 -20
- package/dist/generators/portable-knowledge.js.map +1 -1
- package/dist/generators/portable-knowledge.test.js +457 -1
- package/dist/generators/portable-knowledge.test.js.map +1 -1
- package/dist/generators/surface-profiles.d.ts +27 -0
- package/dist/generators/surface-profiles.d.ts.map +1 -0
- package/dist/generators/surface-profiles.js +47 -0
- package/dist/generators/surface-profiles.js.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/repo-detect.d.ts +19 -0
- package/dist/lib/repo-detect.d.ts.map +1 -1
- package/dist/lib/repo-detect.js +25 -0
- package/dist/lib/repo-detect.js.map +1 -1
- package/dist/lib/strip.d.ts +1 -0
- package/dist/lib/strip.d.ts.map +1 -1
- package/dist/lib/strip.js +15 -0
- package/dist/lib/strip.js.map +1 -1
- package/package.json +2 -1
- package/templates/general/code-integrity.md +11 -0
- package/templates/general/getting-started.md +12 -0
- package/templates/node-ts/code-integrity.md +13 -0
- package/templates/node-ts/testing.md +12 -0
- package/templates/python/code-integrity.md +13 -0
- package/templates/python/testing.md +12 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapters.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/adapters.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* adapters — unit tests for generateAgentsMd and generateCopilotMd.
|
|
3
|
+
* BET-270 Slice 2: governance-enriched AGENTS.md adapter.
|
|
4
|
+
* BET-270 Slice 3: profile-driven single-file Copilot adapter.
|
|
5
|
+
*/
|
|
6
|
+
import { describe, expect, it } from 'vitest';
|
|
7
|
+
import { MARKER, generateAgentsMd, generateCopilotMd } from '../generators/adapters.js';
|
|
8
|
+
import { SURFACE_PROFILES } from '../generators/surface-profiles.js';
|
|
9
|
+
const TIMESTAMP = '2026-04-05T12:00:00.000Z';
|
|
10
|
+
// ── Auto-generated marker ─────────────────────────────────────────────
|
|
11
|
+
describe('generateAgentsMd — marker', () => {
|
|
12
|
+
it('always includes the auto-generated marker', () => {
|
|
13
|
+
expect(generateAgentsMd(TIMESTAMP)).toContain(MARKER);
|
|
14
|
+
});
|
|
15
|
+
it('always includes the marker when options are provided', () => {
|
|
16
|
+
expect(generateAgentsMd(TIMESTAMP, {
|
|
17
|
+
workspaceContext: { stage: 'grounded' },
|
|
18
|
+
skills: [{ name: 'my-skill', description: 'does things' }],
|
|
19
|
+
})).toContain(MARKER);
|
|
20
|
+
});
|
|
21
|
+
it('embeds the timestamp in the marker line', () => {
|
|
22
|
+
const result = generateAgentsMd(TIMESTAMP);
|
|
23
|
+
expect(result).toContain(`<!-- ${MARKER} — ${TIMESTAMP} -->`);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
// ── Backward compatibility (no options) ──────────────────────────────
|
|
27
|
+
describe('generateAgentsMd — no options (backward compat)', () => {
|
|
28
|
+
it('produces the command reference table', () => {
|
|
29
|
+
const result = generateAgentsMd(TIMESTAMP);
|
|
30
|
+
expect(result).toContain('pb orient -b');
|
|
31
|
+
expect(result).toContain('pb get <ID>');
|
|
32
|
+
expect(result).toContain('pb search <query>');
|
|
33
|
+
expect(result).toContain('pb handshake');
|
|
34
|
+
});
|
|
35
|
+
it('produces the session lifecycle section', () => {
|
|
36
|
+
const result = generateAgentsMd(TIMESTAMP);
|
|
37
|
+
expect(result).toContain('pb session start');
|
|
38
|
+
expect(result).toContain('pb capture');
|
|
39
|
+
expect(result).toContain('pb session close');
|
|
40
|
+
});
|
|
41
|
+
it('does not include workspace context section when no options given', () => {
|
|
42
|
+
const result = generateAgentsMd(TIMESTAMP);
|
|
43
|
+
expect(result).not.toContain('## Workspace Context');
|
|
44
|
+
});
|
|
45
|
+
it('does not include skill directory when no options given', () => {
|
|
46
|
+
const result = generateAgentsMd(TIMESTAMP);
|
|
47
|
+
expect(result).not.toContain('## Skill Directory');
|
|
48
|
+
});
|
|
49
|
+
it('includes governance summary', () => {
|
|
50
|
+
const result = generateAgentsMd(TIMESTAMP);
|
|
51
|
+
expect(result).toContain('## Governance Summary');
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
// ── Workspace Context section ─────────────────────────────────────────
|
|
55
|
+
describe('generateAgentsMd — workspaceContext', () => {
|
|
56
|
+
it('includes workspace context section when workspaceContext is provided', () => {
|
|
57
|
+
const result = generateAgentsMd(TIMESTAMP, {
|
|
58
|
+
workspaceContext: { stage: 'grounded', governanceMode: 'active', totalEntries: 42 },
|
|
59
|
+
});
|
|
60
|
+
expect(result).toContain('## Workspace Context');
|
|
61
|
+
});
|
|
62
|
+
it('renders stage in workspace context table', () => {
|
|
63
|
+
const result = generateAgentsMd(TIMESTAMP, {
|
|
64
|
+
workspaceContext: { stage: 'grounded' },
|
|
65
|
+
});
|
|
66
|
+
expect(result).toContain('grounded');
|
|
67
|
+
expect(result).toContain('Stage');
|
|
68
|
+
});
|
|
69
|
+
it('renders focus in workspace context table', () => {
|
|
70
|
+
const result = generateAgentsMd(TIMESTAMP, {
|
|
71
|
+
workspaceContext: { focus: 'Ship BET-270' },
|
|
72
|
+
});
|
|
73
|
+
expect(result).toContain('Ship BET-270');
|
|
74
|
+
expect(result).toContain('Current focus');
|
|
75
|
+
});
|
|
76
|
+
it('renders governanceMode in workspace context table', () => {
|
|
77
|
+
const result = generateAgentsMd(TIMESTAMP, {
|
|
78
|
+
workspaceContext: { governanceMode: 'structured' },
|
|
79
|
+
});
|
|
80
|
+
expect(result).toContain('structured');
|
|
81
|
+
expect(result).toContain('Governance mode');
|
|
82
|
+
});
|
|
83
|
+
it('renders totalEntries in workspace context table', () => {
|
|
84
|
+
const result = generateAgentsMd(TIMESTAMP, {
|
|
85
|
+
workspaceContext: { totalEntries: 99 },
|
|
86
|
+
});
|
|
87
|
+
expect(result).toContain('99');
|
|
88
|
+
expect(result).toContain('Chain entries');
|
|
89
|
+
});
|
|
90
|
+
it('omits workspace context section when workspaceContext is undefined', () => {
|
|
91
|
+
const result = generateAgentsMd(TIMESTAMP, { skills: [] });
|
|
92
|
+
expect(result).not.toContain('## Workspace Context');
|
|
93
|
+
});
|
|
94
|
+
it('omits workspace context section when workspaceContext is empty object', () => {
|
|
95
|
+
const result = generateAgentsMd(TIMESTAMP, { workspaceContext: {} });
|
|
96
|
+
expect(result).not.toContain('## Workspace Context');
|
|
97
|
+
});
|
|
98
|
+
it('omits skill directory when only workspaceContext provided (no skills)', () => {
|
|
99
|
+
const result = generateAgentsMd(TIMESTAMP, {
|
|
100
|
+
workspaceContext: { stage: 'grounded' },
|
|
101
|
+
});
|
|
102
|
+
expect(result).not.toContain('## Skill Directory');
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
// ── Skill Directory section ───────────────────────────────────────────
|
|
106
|
+
describe('generateAgentsMd — skills', () => {
|
|
107
|
+
it('includes skill directory when skills array provided', () => {
|
|
108
|
+
const result = generateAgentsMd(TIMESTAMP, {
|
|
109
|
+
skills: [{ name: 'my-skill', description: 'does things' }],
|
|
110
|
+
});
|
|
111
|
+
expect(result).toContain('## Skill Directory');
|
|
112
|
+
});
|
|
113
|
+
it('renders skill name in the table', () => {
|
|
114
|
+
const result = generateAgentsMd(TIMESTAMP, {
|
|
115
|
+
skills: [{ name: 'commit', description: 'commit changes to main' }],
|
|
116
|
+
});
|
|
117
|
+
expect(result).toContain('commit');
|
|
118
|
+
expect(result).toContain('commit changes to main');
|
|
119
|
+
});
|
|
120
|
+
it('renders skill triggers (up to 3) in the table', () => {
|
|
121
|
+
const result = generateAgentsMd(TIMESTAMP, {
|
|
122
|
+
skills: [
|
|
123
|
+
{
|
|
124
|
+
name: 'review',
|
|
125
|
+
description: 'review changes',
|
|
126
|
+
triggers: ['review', 'implementation review', 'review this'],
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
});
|
|
130
|
+
expect(result).toContain('review');
|
|
131
|
+
expect(result).toContain('implementation review');
|
|
132
|
+
expect(result).toContain('review this');
|
|
133
|
+
});
|
|
134
|
+
it('caps triggers at 3 items', () => {
|
|
135
|
+
const result = generateAgentsMd(TIMESTAMP, {
|
|
136
|
+
skills: [
|
|
137
|
+
{
|
|
138
|
+
name: 'shape',
|
|
139
|
+
description: 'shape a bet',
|
|
140
|
+
triggers: ['shape', 'shape this', 'shape a bet', 'shape up', 'let\'s shape'],
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
});
|
|
144
|
+
// Should have at most 3 triggers shown — 4th and 5th should not appear if they are unique
|
|
145
|
+
// The row should contain up to 3 triggers joined by ', '
|
|
146
|
+
const lines = result.split('\n');
|
|
147
|
+
const skillRow = lines.find((l) => l.includes('shape') && l.includes('shape a bet'));
|
|
148
|
+
expect(skillRow).toBeDefined();
|
|
149
|
+
const parts = skillRow.split('|');
|
|
150
|
+
// triggers cell is the 4th column (index 3)
|
|
151
|
+
const triggersCell = parts[3]?.trim() ?? '';
|
|
152
|
+
const triggerCount = triggersCell.split(',').length;
|
|
153
|
+
expect(triggerCount).toBeLessThanOrEqual(3);
|
|
154
|
+
});
|
|
155
|
+
it('renders "—" when no triggers provided for a skill', () => {
|
|
156
|
+
const result = generateAgentsMd(TIMESTAMP, {
|
|
157
|
+
skills: [{ name: 'my-skill', description: 'does things' }],
|
|
158
|
+
});
|
|
159
|
+
expect(result).toContain('—');
|
|
160
|
+
});
|
|
161
|
+
it('renders multiple skills as separate rows', () => {
|
|
162
|
+
const result = generateAgentsMd(TIMESTAMP, {
|
|
163
|
+
skills: [
|
|
164
|
+
{ name: 'skill-a', description: 'skill A description' },
|
|
165
|
+
{ name: 'skill-b', description: 'skill B description' },
|
|
166
|
+
],
|
|
167
|
+
});
|
|
168
|
+
expect(result).toContain('skill-a');
|
|
169
|
+
expect(result).toContain('skill-b');
|
|
170
|
+
expect(result).toContain('skill A description');
|
|
171
|
+
expect(result).toContain('skill B description');
|
|
172
|
+
});
|
|
173
|
+
it('omits skill directory when skills array is empty', () => {
|
|
174
|
+
const result = generateAgentsMd(TIMESTAMP, { skills: [] });
|
|
175
|
+
expect(result).not.toContain('## Skill Directory');
|
|
176
|
+
});
|
|
177
|
+
it('omits skill directory when skills option is undefined', () => {
|
|
178
|
+
const result = generateAgentsMd(TIMESTAMP, { workspaceContext: { stage: 'grounded' } });
|
|
179
|
+
expect(result).not.toContain('## Skill Directory');
|
|
180
|
+
});
|
|
181
|
+
it('includes workspace context AND skill directory together', () => {
|
|
182
|
+
const result = generateAgentsMd(TIMESTAMP, {
|
|
183
|
+
workspaceContext: { stage: 'grounded', totalEntries: 10 },
|
|
184
|
+
skills: [{ name: 'orient', description: 'orient the workspace' }],
|
|
185
|
+
});
|
|
186
|
+
expect(result).toContain('## Workspace Context');
|
|
187
|
+
expect(result).toContain('## Skill Directory');
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
// ── Governance summary (always present) ─────────────────────────────
|
|
191
|
+
describe('generateAgentsMd — governance summary', () => {
|
|
192
|
+
it('is present with no options', () => {
|
|
193
|
+
expect(generateAgentsMd(TIMESTAMP)).toContain('## Governance Summary');
|
|
194
|
+
});
|
|
195
|
+
it('is present with full context', () => {
|
|
196
|
+
const result = generateAgentsMd(TIMESTAMP, {
|
|
197
|
+
workspaceContext: { stage: 'grounded' },
|
|
198
|
+
skills: [{ name: 'commit', description: 'commit to main' }],
|
|
199
|
+
});
|
|
200
|
+
expect(result).toContain('## Governance Summary');
|
|
201
|
+
});
|
|
202
|
+
it('mentions Product Brain governance', () => {
|
|
203
|
+
const result = generateAgentsMd(TIMESTAMP);
|
|
204
|
+
expect(result).toContain('Product Brain governance');
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
// ────────────────────────────────────────────────────────────────────
|
|
208
|
+
// generateCopilotMd
|
|
209
|
+
// ────────────────────────────────────────────────────────────────────
|
|
210
|
+
// ── Marker always present ────────────────────────────────────────────
|
|
211
|
+
describe('generateCopilotMd — marker', () => {
|
|
212
|
+
it('always includes the auto-generated marker with no options', () => {
|
|
213
|
+
expect(generateCopilotMd(TIMESTAMP)).toContain(MARKER);
|
|
214
|
+
});
|
|
215
|
+
it('always includes the marker when options are provided', () => {
|
|
216
|
+
expect(generateCopilotMd(TIMESTAMP, {
|
|
217
|
+
skills: [{ name: 'my-skill', description: 'does things' }],
|
|
218
|
+
})).toContain(MARKER);
|
|
219
|
+
});
|
|
220
|
+
it('embeds the timestamp in the marker line', () => {
|
|
221
|
+
const result = generateCopilotMd(TIMESTAMP);
|
|
222
|
+
expect(result).toContain(`<!-- ${MARKER} — ${TIMESTAMP} -->`);
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
// ── Backward compatibility (no options) ─────────────────────────────
|
|
226
|
+
describe('generateCopilotMd — no options (backward compat)', () => {
|
|
227
|
+
it('produces the command reference section', () => {
|
|
228
|
+
const result = generateCopilotMd(TIMESTAMP);
|
|
229
|
+
expect(result).toContain('pb orient -b');
|
|
230
|
+
expect(result).toContain('pb get <ID>');
|
|
231
|
+
expect(result).toContain('pb search <query>');
|
|
232
|
+
expect(result).toContain('pb handshake');
|
|
233
|
+
});
|
|
234
|
+
it('produces the session lifecycle section', () => {
|
|
235
|
+
const result = generateCopilotMd(TIMESTAMP);
|
|
236
|
+
expect(result).toContain('pb session start');
|
|
237
|
+
expect(result).toContain('pb capture');
|
|
238
|
+
expect(result).toContain('pb session close');
|
|
239
|
+
});
|
|
240
|
+
it('does not include Skills section when no options given', () => {
|
|
241
|
+
const result = generateCopilotMd(TIMESTAMP);
|
|
242
|
+
expect(result).not.toContain('## Skills');
|
|
243
|
+
});
|
|
244
|
+
it('does not include Rules section when no options given', () => {
|
|
245
|
+
const result = generateCopilotMd(TIMESTAMP);
|
|
246
|
+
expect(result).not.toContain('## Rules');
|
|
247
|
+
});
|
|
248
|
+
it('does not include workspace context section when no options given', () => {
|
|
249
|
+
const result = generateCopilotMd(TIMESTAMP);
|
|
250
|
+
expect(result).not.toContain('## Workspace Context');
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
// ── Full context ─────────────────────────────────────────────────────
|
|
254
|
+
describe('generateCopilotMd — full context', () => {
|
|
255
|
+
it('produces all sections when all options provided', () => {
|
|
256
|
+
const result = generateCopilotMd(TIMESTAMP, {
|
|
257
|
+
profile: SURFACE_PROFILES.copilot,
|
|
258
|
+
workspaceContext: { stage: 'grounded', focus: 'Ship BET-270', governanceMode: 'active', totalEntries: 55 },
|
|
259
|
+
skills: [{ name: 'commit', description: 'commit changes', triggers: ['commit'] }],
|
|
260
|
+
rules: [{ name: 'git-workflow', description: 'two-track git workflow' }],
|
|
261
|
+
});
|
|
262
|
+
expect(result).toContain('## Workspace Context');
|
|
263
|
+
expect(result).toContain('## Skills');
|
|
264
|
+
expect(result).toContain('## Rules');
|
|
265
|
+
expect(result).toContain('commit');
|
|
266
|
+
expect(result).toContain('git-workflow');
|
|
267
|
+
});
|
|
268
|
+
it('renders workspace context fields', () => {
|
|
269
|
+
const result = generateCopilotMd(TIMESTAMP, {
|
|
270
|
+
workspaceContext: { stage: 'grounded', governanceMode: 'active', totalEntries: 42, focus: 'BET-270' },
|
|
271
|
+
});
|
|
272
|
+
expect(result).toContain('grounded');
|
|
273
|
+
expect(result).toContain('active');
|
|
274
|
+
expect(result).toContain('42');
|
|
275
|
+
expect(result).toContain('BET-270');
|
|
276
|
+
});
|
|
277
|
+
it('renders skill name and description', () => {
|
|
278
|
+
const result = generateCopilotMd(TIMESTAMP, {
|
|
279
|
+
skills: [{ name: 'review', description: 'review implementation changes' }],
|
|
280
|
+
});
|
|
281
|
+
expect(result).toContain('### review');
|
|
282
|
+
expect(result).toContain('review implementation changes');
|
|
283
|
+
});
|
|
284
|
+
it('renders skill triggers (up to 3)', () => {
|
|
285
|
+
const result = generateCopilotMd(TIMESTAMP, {
|
|
286
|
+
skills: [
|
|
287
|
+
{ name: 'shape', description: 'shape a bet', triggers: ['shape', 'shape this', 'shape a bet', 'let\'s shape'] },
|
|
288
|
+
],
|
|
289
|
+
});
|
|
290
|
+
expect(result).toContain('shape');
|
|
291
|
+
expect(result).toContain('shape this');
|
|
292
|
+
expect(result).toContain('shape a bet');
|
|
293
|
+
// 4th trigger should not appear as it was sliced
|
|
294
|
+
expect(result).not.toContain('let\'s shape');
|
|
295
|
+
});
|
|
296
|
+
it('renders rule name and description', () => {
|
|
297
|
+
const result = generateCopilotMd(TIMESTAMP, {
|
|
298
|
+
rules: [{ name: 'feature-flags', description: 'three-tier feature flag resolution' }],
|
|
299
|
+
});
|
|
300
|
+
expect(result).toContain('### feature-flags');
|
|
301
|
+
expect(result).toContain('three-tier feature flag resolution');
|
|
302
|
+
});
|
|
303
|
+
it('renders multiple skills as separate headings', () => {
|
|
304
|
+
const result = generateCopilotMd(TIMESTAMP, {
|
|
305
|
+
skills: [
|
|
306
|
+
{ name: 'skill-a', description: 'alpha skill' },
|
|
307
|
+
{ name: 'skill-b', description: 'beta skill' },
|
|
308
|
+
],
|
|
309
|
+
});
|
|
310
|
+
expect(result).toContain('### skill-a');
|
|
311
|
+
expect(result).toContain('### skill-b');
|
|
312
|
+
expect(result).toContain('alpha skill');
|
|
313
|
+
expect(result).toContain('beta skill');
|
|
314
|
+
});
|
|
315
|
+
it('renders multiple rules as separate headings', () => {
|
|
316
|
+
const result = generateCopilotMd(TIMESTAMP, {
|
|
317
|
+
rules: [
|
|
318
|
+
{ name: 'rule-one', description: 'first rule' },
|
|
319
|
+
{ name: 'rule-two', description: 'second rule' },
|
|
320
|
+
],
|
|
321
|
+
});
|
|
322
|
+
expect(result).toContain('### rule-one');
|
|
323
|
+
expect(result).toContain('### rule-two');
|
|
324
|
+
});
|
|
325
|
+
it('does not include skill bodies — only summaries', () => {
|
|
326
|
+
// Summaries contain just name + description + optional triggers, no full markdown content
|
|
327
|
+
const result = generateCopilotMd(TIMESTAMP, {
|
|
328
|
+
skills: [{ name: 'orchestrate', description: 'run bounded implementation slices' }],
|
|
329
|
+
});
|
|
330
|
+
// Should have a heading and description but NOT multi-paragraph content from the skill body
|
|
331
|
+
expect(result).toContain('### orchestrate');
|
|
332
|
+
expect(result).toContain('run bounded implementation slices');
|
|
333
|
+
// Confirm no "Run Contract" section from skill body is present
|
|
334
|
+
expect(result).not.toContain('## Run Contract');
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
// ── Token budget enforcement ─────────────────────────────────────────
|
|
338
|
+
describe('generateCopilotMd — token budget enforcement', () => {
|
|
339
|
+
it('output length does not exceed profile token budget', () => {
|
|
340
|
+
const profile = SURFACE_PROFILES.copilot; // 30000 chars
|
|
341
|
+
// Generate a large payload
|
|
342
|
+
const manySkills = Array.from({ length: 100 }, (_, i) => ({
|
|
343
|
+
name: `skill-${i}`,
|
|
344
|
+
description: `Description for skill ${i} — a moderately long description to consume budget`,
|
|
345
|
+
triggers: [`trigger-${i}-a`, `trigger-${i}-b`, `trigger-${i}-c`],
|
|
346
|
+
}));
|
|
347
|
+
const manyRules = Array.from({ length: 50 }, (_, i) => ({
|
|
348
|
+
name: `rule-${i}`,
|
|
349
|
+
description: `Description for rule ${i} — another moderately long description`,
|
|
350
|
+
}));
|
|
351
|
+
const result = generateCopilotMd(TIMESTAMP, { profile, skills: manySkills, rules: manyRules });
|
|
352
|
+
expect(result.length).toBeLessThanOrEqual(profile.tokenBudget);
|
|
353
|
+
});
|
|
354
|
+
it('includes a truncation note when content is truncated', () => {
|
|
355
|
+
const profile = { ...SURFACE_PROFILES.copilot, tokenBudget: 2000 };
|
|
356
|
+
const manySkills = Array.from({ length: 50 }, (_, i) => ({
|
|
357
|
+
name: `skill-${i}`,
|
|
358
|
+
description: `Description for skill ${i}`,
|
|
359
|
+
}));
|
|
360
|
+
const result = generateCopilotMd(TIMESTAMP, { profile, skills: manySkills });
|
|
361
|
+
expect(result).toContain('Truncated');
|
|
362
|
+
expect(result).toContain('token budget');
|
|
363
|
+
});
|
|
364
|
+
it('does not include a truncation note when everything fits', () => {
|
|
365
|
+
const result = generateCopilotMd(TIMESTAMP, {
|
|
366
|
+
profile: SURFACE_PROFILES.copilot,
|
|
367
|
+
skills: [{ name: 'one-skill', description: 'a single skill that easily fits' }],
|
|
368
|
+
rules: [{ name: 'one-rule', description: 'a single rule that easily fits' }],
|
|
369
|
+
});
|
|
370
|
+
expect(result).not.toContain('Truncated');
|
|
371
|
+
});
|
|
372
|
+
it('truncated output still contains the marker', () => {
|
|
373
|
+
const profile = { ...SURFACE_PROFILES.copilot, tokenBudget: 2000 };
|
|
374
|
+
const manySkills = Array.from({ length: 50 }, (_, i) => ({
|
|
375
|
+
name: `skill-${i}`,
|
|
376
|
+
description: `Description for skill ${i}`,
|
|
377
|
+
}));
|
|
378
|
+
const result = generateCopilotMd(TIMESTAMP, { profile, skills: manySkills });
|
|
379
|
+
expect(result).toContain(MARKER);
|
|
380
|
+
});
|
|
381
|
+
});
|
|
382
|
+
//# sourceMappingURL=adapters.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapters.test.js","sourceRoot":"","sources":["../../src/__tests__/adapters.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batch-transformations.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/batch-transformations.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BET-270 S1: Batch transformation tests for surface-optimized skill projection.
|
|
3
|
+
* Tests applyBatchTransformations + generateCodexSkill batch mode + Claude/Cursor unchanged.
|
|
4
|
+
*/
|
|
5
|
+
import { describe, expect, it } from 'vitest';
|
|
6
|
+
import { applyBatchTransformations, generateCodexSkill, generateCursorSkill, generateClaudeRule, generateClaudeSkillRouter, } from '../generators/portable-knowledge.js';
|
|
7
|
+
import { SURFACE_PROFILES } from '../generators/surface-profiles.js';
|
|
8
|
+
describe('applyBatchTransformations', () => {
|
|
9
|
+
it('strips sub-agent spawn patterns and replaces with inline step instruction', () => {
|
|
10
|
+
const body = `# My Skill
|
|
11
|
+
|
|
12
|
+
Do some work.
|
|
13
|
+
Spawn a sub-agent to handle the review.
|
|
14
|
+
Continue with the result.`;
|
|
15
|
+
const result = applyBatchTransformations(body);
|
|
16
|
+
expect(result).not.toContain('Spawn a sub-agent');
|
|
17
|
+
expect(result).toContain('Execute as inline steps within this session.');
|
|
18
|
+
expect(result).toContain('Do some work.');
|
|
19
|
+
expect(result).toContain('Continue with the result.');
|
|
20
|
+
});
|
|
21
|
+
it('strips SPAWN build sub-agent pattern (uppercase SPAWN)', () => {
|
|
22
|
+
const body = `# Heading
|
|
23
|
+
|
|
24
|
+
SPAWN build sub-agent with primer.
|
|
25
|
+
Other content.`;
|
|
26
|
+
const result = applyBatchTransformations(body);
|
|
27
|
+
expect(result).not.toContain('SPAWN build sub-agent');
|
|
28
|
+
expect(result).toContain('Execute as inline steps within this session.');
|
|
29
|
+
});
|
|
30
|
+
it('strips SPAWN review sub-agent pattern', () => {
|
|
31
|
+
const body = `# Heading
|
|
32
|
+
|
|
33
|
+
SPAWN review sub-agent for verification.
|
|
34
|
+
Done.`;
|
|
35
|
+
const result = applyBatchTransformations(body);
|
|
36
|
+
expect(result).not.toContain('SPAWN review sub-agent');
|
|
37
|
+
expect(result).toContain('Execute as inline steps within this session.');
|
|
38
|
+
});
|
|
39
|
+
it('strips "fresh conversation handoff" pattern', () => {
|
|
40
|
+
const body = `# Heading
|
|
41
|
+
|
|
42
|
+
Use fresh conversation handoff for next slice.
|
|
43
|
+
Continue.`;
|
|
44
|
+
const result = applyBatchTransformations(body);
|
|
45
|
+
expect(result).not.toContain('fresh conversation handoff');
|
|
46
|
+
expect(result).toContain('Execute as inline steps within this session.');
|
|
47
|
+
});
|
|
48
|
+
it('strips user confirmation gates — "Ask the user"', () => {
|
|
49
|
+
const body = `# Skill
|
|
50
|
+
|
|
51
|
+
Do work.
|
|
52
|
+
Ask the user before proceeding.
|
|
53
|
+
Continue.`;
|
|
54
|
+
const result = applyBatchTransformations(body);
|
|
55
|
+
expect(result).not.toContain('Ask the user');
|
|
56
|
+
expect(result).toContain('Proceed autonomously. Log decision rationale.');
|
|
57
|
+
expect(result).toContain('Do work.');
|
|
58
|
+
expect(result).toContain('Continue.');
|
|
59
|
+
});
|
|
60
|
+
it('strips user confirmation gates — "Wait for user input"', () => {
|
|
61
|
+
const body = `# Skill
|
|
62
|
+
|
|
63
|
+
Step one done.
|
|
64
|
+
Wait for user input before continuing.
|
|
65
|
+
Step two.`;
|
|
66
|
+
const result = applyBatchTransformations(body);
|
|
67
|
+
expect(result).not.toContain('Wait for user input');
|
|
68
|
+
expect(result).toContain('Proceed autonomously. Log decision rationale.');
|
|
69
|
+
});
|
|
70
|
+
it('strips user confirmation gates — "Present gate to user"', () => {
|
|
71
|
+
const body = `# Skill
|
|
72
|
+
|
|
73
|
+
Build the feature.
|
|
74
|
+
Present gate to user before merging.
|
|
75
|
+
Merge.`;
|
|
76
|
+
const result = applyBatchTransformations(body);
|
|
77
|
+
expect(result).not.toContain('Present gate to user');
|
|
78
|
+
expect(result).toContain('Proceed autonomously. Log decision rationale.');
|
|
79
|
+
});
|
|
80
|
+
it('strips user confirmation gates — "STOP and ask"', () => {
|
|
81
|
+
const body = `# Skill
|
|
82
|
+
|
|
83
|
+
Analyze problem.
|
|
84
|
+
STOP and ask the user whether to continue.
|
|
85
|
+
Then proceed.`;
|
|
86
|
+
const result = applyBatchTransformations(body);
|
|
87
|
+
expect(result).not.toContain('STOP and ask');
|
|
88
|
+
expect(result).toContain('Proceed autonomously. Log decision rationale.');
|
|
89
|
+
});
|
|
90
|
+
it('adds batch governance header after the first # heading', () => {
|
|
91
|
+
const body = `# My Skill
|
|
92
|
+
|
|
93
|
+
Some content here.`;
|
|
94
|
+
const result = applyBatchTransformations(body);
|
|
95
|
+
expect(result).toContain('> Batch execution mode: This skill runs autonomously without interactive gates. Decisions are logged, not prompted.');
|
|
96
|
+
// Header must appear right after the heading
|
|
97
|
+
const lines = result.split('\n');
|
|
98
|
+
const headingIdx = lines.findIndex((l) => l.startsWith('# My Skill'));
|
|
99
|
+
const batchHeaderIdx = lines.findIndex((l) => l.includes('Batch execution mode:'));
|
|
100
|
+
expect(headingIdx).toBeGreaterThanOrEqual(0);
|
|
101
|
+
expect(batchHeaderIdx).toBeGreaterThan(headingIdx);
|
|
102
|
+
expect(batchHeaderIdx - headingIdx).toBeLessThanOrEqual(3);
|
|
103
|
+
});
|
|
104
|
+
it('preserves non-interactive content unchanged', () => {
|
|
105
|
+
const body = `# Clean Skill
|
|
106
|
+
|
|
107
|
+
This skill has no interactive patterns.
|
|
108
|
+
It describes steps the agent should follow.
|
|
109
|
+
Use grep to find the file.
|
|
110
|
+
Run npm run build.`;
|
|
111
|
+
const result = applyBatchTransformations(body);
|
|
112
|
+
expect(result).toContain('This skill has no interactive patterns.');
|
|
113
|
+
expect(result).toContain('It describes steps the agent should follow.');
|
|
114
|
+
expect(result).toContain('Use grep to find the file.');
|
|
115
|
+
expect(result).toContain('Run npm run build.');
|
|
116
|
+
expect(result).toContain('Batch execution mode:');
|
|
117
|
+
});
|
|
118
|
+
it('does not transform every mention of "user" — only clear interactive gate patterns', () => {
|
|
119
|
+
const body = `# Skill
|
|
120
|
+
|
|
121
|
+
The user should be aware of this tradeoff.
|
|
122
|
+
User data must be validated before insert.`;
|
|
123
|
+
const result = applyBatchTransformations(body);
|
|
124
|
+
expect(result).toContain('The user should be aware of this tradeoff.');
|
|
125
|
+
expect(result).toContain('User data must be validated before insert.');
|
|
126
|
+
expect(result).not.toContain('Proceed autonomously. Log decision rationale.');
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
describe('generateCodexSkill — batch mode (BET-270 S1)', () => {
|
|
130
|
+
const baseSkill = {
|
|
131
|
+
name: 'orchestrate',
|
|
132
|
+
description: 'Orchestrate a bet slice.',
|
|
133
|
+
triggers: ['orchestrate'],
|
|
134
|
+
body: `# Orchestrate
|
|
135
|
+
|
|
136
|
+
Do planning.
|
|
137
|
+
Spawn a sub-agent to execute.
|
|
138
|
+
Ask the user to confirm the plan.
|
|
139
|
+
Finalize.`,
|
|
140
|
+
sourcePath: '/tmp/.productbrain/skills/orchestrate.md',
|
|
141
|
+
};
|
|
142
|
+
it('applies batch transformations when profile.executionModel is batch', () => {
|
|
143
|
+
const output = generateCodexSkill(baseSkill, SURFACE_PROFILES.codex);
|
|
144
|
+
expect(output).not.toContain('Spawn a sub-agent');
|
|
145
|
+
expect(output).not.toContain('Ask the user');
|
|
146
|
+
expect(output).toContain('Execute as inline steps within this session.');
|
|
147
|
+
expect(output).toContain('Proceed autonomously. Log decision rationale.');
|
|
148
|
+
expect(output).toContain('Batch execution mode:');
|
|
149
|
+
});
|
|
150
|
+
it('produces CURRENT output (no batch transforms) when profile is undefined — backward compat', () => {
|
|
151
|
+
const output = generateCodexSkill(baseSkill, undefined);
|
|
152
|
+
expect(output).toContain('Spawn a sub-agent to execute.');
|
|
153
|
+
expect(output).toContain('Ask the user to confirm the plan.');
|
|
154
|
+
expect(output).not.toContain('Batch execution mode:');
|
|
155
|
+
});
|
|
156
|
+
it('includes skill name, description, triggers in both modes', () => {
|
|
157
|
+
const withProfile = generateCodexSkill(baseSkill, SURFACE_PROFILES.codex);
|
|
158
|
+
const withoutProfile = generateCodexSkill(baseSkill, undefined);
|
|
159
|
+
for (const output of [withProfile, withoutProfile]) {
|
|
160
|
+
expect(output).toContain('# orchestrate');
|
|
161
|
+
expect(output).toContain('Orchestrate a bet slice.');
|
|
162
|
+
expect(output).toContain('`orchestrate`');
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
it('still performs path replacement before batch transforms', () => {
|
|
166
|
+
const skillWithPath = {
|
|
167
|
+
...baseSkill,
|
|
168
|
+
body: `# Path Skill
|
|
169
|
+
|
|
170
|
+
Read \`.productbrain/skills/preflight.md\` before starting.
|
|
171
|
+
Ask the user for approval.`,
|
|
172
|
+
};
|
|
173
|
+
const output = generateCodexSkill(skillWithPath, SURFACE_PROFILES.codex);
|
|
174
|
+
expect(output).toContain('.codex/skills/preflight.md');
|
|
175
|
+
expect(output).not.toContain('.productbrain/skills/preflight.md');
|
|
176
|
+
expect(output).not.toContain('Ask the user');
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
describe('generateCursorSkill / generateClaudeRule / generateClaudeSkillRouter — profile ignored (BET-270 S1)', () => {
|
|
180
|
+
const skill = {
|
|
181
|
+
name: 'test-skill',
|
|
182
|
+
description: 'Test skill',
|
|
183
|
+
triggers: ['test'],
|
|
184
|
+
body: `# Test Skill
|
|
185
|
+
|
|
186
|
+
Ask the user to confirm.
|
|
187
|
+
Spawn a sub-agent.
|
|
188
|
+
Normal content.`,
|
|
189
|
+
sourcePath: '/tmp/.productbrain/skills/test-skill.md',
|
|
190
|
+
};
|
|
191
|
+
const rule = {
|
|
192
|
+
name: 'test-rule',
|
|
193
|
+
description: 'A test rule',
|
|
194
|
+
autoApply: true,
|
|
195
|
+
body: '# Rule body\n\nAsk the user to confirm.\nNormal content.',
|
|
196
|
+
sourcePath: '/tmp/.productbrain/rules/test-rule.md',
|
|
197
|
+
};
|
|
198
|
+
it('generateCursorSkill preserves interactive content regardless of profile', () => {
|
|
199
|
+
const withProfile = generateCursorSkill(skill, SURFACE_PROFILES.cursor);
|
|
200
|
+
const withCodexProfile = generateCursorSkill(skill, SURFACE_PROFILES.codex);
|
|
201
|
+
for (const output of [withProfile, withCodexProfile]) {
|
|
202
|
+
expect(output).toContain('Ask the user to confirm.');
|
|
203
|
+
expect(output).toContain('Spawn a sub-agent.');
|
|
204
|
+
expect(output).not.toContain('Batch execution mode:');
|
|
205
|
+
expect(output).not.toContain('Proceed autonomously');
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
it('generateClaudeRule preserves interactive content regardless of profile', () => {
|
|
209
|
+
const withProfile = generateClaudeRule(rule, SURFACE_PROFILES.claude);
|
|
210
|
+
const withCodexProfile = generateClaudeRule(rule, SURFACE_PROFILES.codex);
|
|
211
|
+
for (const output of [withProfile, withCodexProfile]) {
|
|
212
|
+
expect(output).toContain('Ask the user to confirm.');
|
|
213
|
+
expect(output).not.toContain('Batch execution mode:');
|
|
214
|
+
expect(output).not.toContain('Proceed autonomously');
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
it('generateClaudeSkillRouter preserves interactive content regardless of profile', () => {
|
|
218
|
+
const withProfile = generateClaudeSkillRouter([skill], SURFACE_PROFILES.claude);
|
|
219
|
+
const withCodexProfile = generateClaudeSkillRouter([skill], SURFACE_PROFILES.codex);
|
|
220
|
+
for (const output of [withProfile, withCodexProfile]) {
|
|
221
|
+
expect(output).toContain('test-skill');
|
|
222
|
+
expect(output).toContain('Skill Router');
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
//# sourceMappingURL=batch-transformations.test.js.map
|