@soleri/forge 0.0.1 → 4.0.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 +98 -0
- package/README.md +199 -0
- package/dist/facades/forge.facade.d.ts +9 -0
- package/dist/facades/forge.facade.js +134 -0
- package/dist/facades/forge.facade.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +81 -0
- package/dist/index.js.map +1 -0
- package/dist/knowledge-installer.d.ts +31 -0
- package/dist/knowledge-installer.js +437 -0
- package/dist/knowledge-installer.js.map +1 -0
- package/dist/scaffolder.d.ts +13 -0
- package/dist/scaffolder.js +330 -0
- package/dist/scaffolder.js.map +1 -0
- package/dist/templates/activate.d.ts +9 -0
- package/dist/templates/activate.js +139 -0
- package/dist/templates/activate.js.map +1 -0
- package/dist/templates/brain.d.ts +6 -0
- package/dist/templates/brain.js +478 -0
- package/dist/templates/brain.js.map +1 -0
- package/dist/templates/claude-md-template.d.ts +11 -0
- package/dist/templates/claude-md-template.js +73 -0
- package/dist/templates/claude-md-template.js.map +1 -0
- package/dist/templates/core-facade.d.ts +6 -0
- package/dist/templates/core-facade.js +456 -0
- package/dist/templates/core-facade.js.map +1 -0
- package/dist/templates/domain-facade.d.ts +7 -0
- package/dist/templates/domain-facade.js +119 -0
- package/dist/templates/domain-facade.js.map +1 -0
- package/dist/templates/entry-point.d.ts +5 -0
- package/dist/templates/entry-point.js +116 -0
- package/dist/templates/entry-point.js.map +1 -0
- package/dist/templates/facade-factory.d.ts +1 -0
- package/dist/templates/facade-factory.js +63 -0
- package/dist/templates/facade-factory.js.map +1 -0
- package/dist/templates/facade-types.d.ts +1 -0
- package/dist/templates/facade-types.js +46 -0
- package/dist/templates/facade-types.js.map +1 -0
- package/dist/templates/inject-claude-md.d.ts +11 -0
- package/dist/templates/inject-claude-md.js +92 -0
- package/dist/templates/inject-claude-md.js.map +1 -0
- package/dist/templates/intelligence-loader.d.ts +1 -0
- package/dist/templates/intelligence-loader.js +43 -0
- package/dist/templates/intelligence-loader.js.map +1 -0
- package/dist/templates/intelligence-types.d.ts +1 -0
- package/dist/templates/intelligence-types.js +24 -0
- package/dist/templates/intelligence-types.js.map +1 -0
- package/dist/templates/llm-client.d.ts +7 -0
- package/dist/templates/llm-client.js +300 -0
- package/dist/templates/llm-client.js.map +1 -0
- package/dist/templates/llm-key-pool.d.ts +7 -0
- package/dist/templates/llm-key-pool.js +211 -0
- package/dist/templates/llm-key-pool.js.map +1 -0
- package/dist/templates/llm-types.d.ts +5 -0
- package/dist/templates/llm-types.js +161 -0
- package/dist/templates/llm-types.js.map +1 -0
- package/dist/templates/llm-utils.d.ts +5 -0
- package/dist/templates/llm-utils.js +260 -0
- package/dist/templates/llm-utils.js.map +1 -0
- package/dist/templates/package-json.d.ts +2 -0
- package/dist/templates/package-json.js +37 -0
- package/dist/templates/package-json.js.map +1 -0
- package/dist/templates/persona.d.ts +2 -0
- package/dist/templates/persona.js +42 -0
- package/dist/templates/persona.js.map +1 -0
- package/dist/templates/planner.d.ts +5 -0
- package/dist/templates/planner.js +150 -0
- package/dist/templates/planner.js.map +1 -0
- package/dist/templates/readme.d.ts +5 -0
- package/dist/templates/readme.js +316 -0
- package/dist/templates/readme.js.map +1 -0
- package/dist/templates/setup-script.d.ts +6 -0
- package/dist/templates/setup-script.js +112 -0
- package/dist/templates/setup-script.js.map +1 -0
- package/dist/templates/test-brain.d.ts +6 -0
- package/dist/templates/test-brain.js +474 -0
- package/dist/templates/test-brain.js.map +1 -0
- package/dist/templates/test-facades.d.ts +6 -0
- package/dist/templates/test-facades.js +649 -0
- package/dist/templates/test-facades.js.map +1 -0
- package/dist/templates/test-llm.d.ts +7 -0
- package/dist/templates/test-llm.js +574 -0
- package/dist/templates/test-llm.js.map +1 -0
- package/dist/templates/test-loader.d.ts +5 -0
- package/dist/templates/test-loader.js +146 -0
- package/dist/templates/test-loader.js.map +1 -0
- package/dist/templates/test-planner.d.ts +5 -0
- package/dist/templates/test-planner.js +271 -0
- package/dist/templates/test-planner.js.map +1 -0
- package/dist/templates/test-vault.d.ts +5 -0
- package/dist/templates/test-vault.js +380 -0
- package/dist/templates/test-vault.js.map +1 -0
- package/dist/templates/tsconfig.d.ts +1 -0
- package/dist/templates/tsconfig.js +25 -0
- package/dist/templates/tsconfig.js.map +1 -0
- package/dist/templates/vault.d.ts +5 -0
- package/dist/templates/vault.js +263 -0
- package/dist/templates/vault.js.map +1 -0
- package/dist/templates/vitest-config.d.ts +1 -0
- package/dist/templates/vitest-config.js +27 -0
- package/dist/templates/vitest-config.js.map +1 -0
- package/dist/types.d.ts +89 -0
- package/dist/types.js +21 -0
- package/dist/types.js.map +1 -0
- package/package.json +42 -4
- package/src/__tests__/knowledge-installer.test.ts +805 -0
- package/src/__tests__/scaffolder.test.ts +323 -0
- package/src/facades/forge.facade.ts +150 -0
- package/src/index.ts +101 -0
- package/src/knowledge-installer.ts +532 -0
- package/src/scaffolder.ts +386 -0
- package/src/templates/activate.ts +145 -0
- package/src/templates/claude-md-template.ts +137 -0
- package/src/templates/core-facade.ts +457 -0
- package/src/templates/domain-facade.ts +121 -0
- package/src/templates/entry-point.ts +120 -0
- package/src/templates/inject-claude-md.ts +94 -0
- package/src/templates/llm-client.ts +301 -0
- package/src/templates/package-json.ts +39 -0
- package/src/templates/persona.ts +45 -0
- package/src/templates/readme.ts +319 -0
- package/src/templates/setup-script.ts +113 -0
- package/src/templates/test-facades.ts +656 -0
- package/src/templates/tsconfig.ts +25 -0
- package/src/templates/vitest-config.ts +26 -0
- package/src/types.ts +68 -0
- package/tsconfig.json +21 -0
- package/vitest.config.ts +15 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates intelligence loader test file for a new agent.
|
|
3
|
+
* Tests cover: load valid JSON bundles, skip invalid entries, missing dir, malformed JSON.
|
|
4
|
+
*/
|
|
5
|
+
export function generateLoaderTest() {
|
|
6
|
+
return LOADER_TEST_TEMPLATE;
|
|
7
|
+
}
|
|
8
|
+
const LOADER_TEST_TEMPLATE = [
|
|
9
|
+
"import { describe, it, expect, beforeEach, afterEach } from 'vitest';",
|
|
10
|
+
"import { mkdirSync, rmSync, writeFileSync } from 'node:fs';",
|
|
11
|
+
"import { join } from 'node:path';",
|
|
12
|
+
"import { tmpdir } from 'node:os';",
|
|
13
|
+
"import { loadIntelligenceData } from '../intelligence/loader.js';",
|
|
14
|
+
'',
|
|
15
|
+
"describe('Intelligence Loader', () => {",
|
|
16
|
+
' let tempDir: string;',
|
|
17
|
+
'',
|
|
18
|
+
' beforeEach(() => {',
|
|
19
|
+
' tempDir = join(tmpdir(), `loader-test-${Date.now()}`);',
|
|
20
|
+
' mkdirSync(tempDir, { recursive: true });',
|
|
21
|
+
' });',
|
|
22
|
+
'',
|
|
23
|
+
' afterEach(() => {',
|
|
24
|
+
' rmSync(tempDir, { recursive: true, force: true });',
|
|
25
|
+
' });',
|
|
26
|
+
'',
|
|
27
|
+
" it('should load valid entries from JSON files', () => {",
|
|
28
|
+
" writeFileSync(join(tempDir, 'test-domain.json'), JSON.stringify({",
|
|
29
|
+
" domain: 'test-domain',",
|
|
30
|
+
" version: '1.0.0',",
|
|
31
|
+
' entries: [',
|
|
32
|
+
' {',
|
|
33
|
+
" id: 'entry-1',",
|
|
34
|
+
" type: 'pattern',",
|
|
35
|
+
" domain: 'test-domain',",
|
|
36
|
+
" title: 'Test Pattern',",
|
|
37
|
+
" severity: 'warning',",
|
|
38
|
+
" description: 'A test pattern.',",
|
|
39
|
+
" tags: ['test'],",
|
|
40
|
+
' },',
|
|
41
|
+
' ],',
|
|
42
|
+
' }));',
|
|
43
|
+
'',
|
|
44
|
+
' const entries = loadIntelligenceData(tempDir);',
|
|
45
|
+
' expect(entries).toHaveLength(1);',
|
|
46
|
+
" expect(entries[0].id).toBe('entry-1');",
|
|
47
|
+
" expect(entries[0].domain).toBe('test-domain');",
|
|
48
|
+
' });',
|
|
49
|
+
'',
|
|
50
|
+
" it('should load entries from multiple files', () => {",
|
|
51
|
+
" for (const domain of ['api', 'db']) {",
|
|
52
|
+
' writeFileSync(join(tempDir, `${domain}.json`), JSON.stringify({',
|
|
53
|
+
' domain,',
|
|
54
|
+
" version: '1.0.0',",
|
|
55
|
+
' entries: [',
|
|
56
|
+
" { id: `${domain}-1`, type: 'pattern', domain, title: 'P1', severity: 'warning', description: 'Desc', tags: ['t'] },",
|
|
57
|
+
" { id: `${domain}-2`, type: 'rule', domain, title: 'R1', severity: 'critical', description: 'Desc', tags: ['t'] },",
|
|
58
|
+
' ],',
|
|
59
|
+
' }));',
|
|
60
|
+
' }',
|
|
61
|
+
'',
|
|
62
|
+
' const entries = loadIntelligenceData(tempDir);',
|
|
63
|
+
' expect(entries).toHaveLength(4);',
|
|
64
|
+
' });',
|
|
65
|
+
'',
|
|
66
|
+
" it('should skip entries with missing required fields', () => {",
|
|
67
|
+
" writeFileSync(join(tempDir, 'bad.json'), JSON.stringify({",
|
|
68
|
+
" domain: 'bad',",
|
|
69
|
+
" version: '1.0.0',",
|
|
70
|
+
' entries: [',
|
|
71
|
+
" { id: '', type: 'pattern', domain: 'bad', title: 'Missing ID', severity: 'warning', description: 'D', tags: ['t'] },",
|
|
72
|
+
" { id: 'ok-1', type: 'pattern', domain: 'bad', title: 'Valid', severity: 'warning', description: 'D', tags: ['t'] },",
|
|
73
|
+
" { type: 'pattern', domain: 'bad', title: 'No ID', severity: 'warning', description: 'D', tags: ['t'] },",
|
|
74
|
+
' ],',
|
|
75
|
+
' }));',
|
|
76
|
+
'',
|
|
77
|
+
' const entries = loadIntelligenceData(tempDir);',
|
|
78
|
+
' expect(entries).toHaveLength(1);',
|
|
79
|
+
" expect(entries[0].id).toBe('ok-1');",
|
|
80
|
+
' });',
|
|
81
|
+
'',
|
|
82
|
+
" it('should skip entries with invalid type', () => {",
|
|
83
|
+
" writeFileSync(join(tempDir, 'invalid-type.json'), JSON.stringify({",
|
|
84
|
+
" domain: 'x',",
|
|
85
|
+
" version: '1.0.0',",
|
|
86
|
+
' entries: [',
|
|
87
|
+
" { id: 'bad-type', type: 'unknown', domain: 'x', title: 'T', severity: 'warning', description: 'D', tags: ['t'] },",
|
|
88
|
+
' ],',
|
|
89
|
+
' }));',
|
|
90
|
+
'',
|
|
91
|
+
' const entries = loadIntelligenceData(tempDir);',
|
|
92
|
+
' expect(entries).toHaveLength(0);',
|
|
93
|
+
' });',
|
|
94
|
+
'',
|
|
95
|
+
" it('should accept entries with empty tags', () => {",
|
|
96
|
+
" writeFileSync(join(tempDir, 'no-tags.json'), JSON.stringify({",
|
|
97
|
+
" domain: 'x',",
|
|
98
|
+
" version: '1.0.0',",
|
|
99
|
+
' entries: [',
|
|
100
|
+
" { id: 'no-tags', type: 'pattern', domain: 'x', title: 'T', severity: 'warning', description: 'D', tags: [] },",
|
|
101
|
+
' ],',
|
|
102
|
+
' }));',
|
|
103
|
+
'',
|
|
104
|
+
' const entries = loadIntelligenceData(tempDir);',
|
|
105
|
+
' expect(entries).toHaveLength(1);',
|
|
106
|
+
' expect(entries[0].tags).toEqual([]);',
|
|
107
|
+
' });',
|
|
108
|
+
'',
|
|
109
|
+
" it('should return empty for nonexistent directory', () => {",
|
|
110
|
+
" const entries = loadIntelligenceData('/nonexistent/path');",
|
|
111
|
+
' expect(entries).toEqual([]);',
|
|
112
|
+
' });',
|
|
113
|
+
'',
|
|
114
|
+
" it('should skip malformed JSON files gracefully', () => {",
|
|
115
|
+
" writeFileSync(join(tempDir, 'broken.json'), '{ not valid json }}}');",
|
|
116
|
+
" writeFileSync(join(tempDir, 'valid.json'), JSON.stringify({",
|
|
117
|
+
" domain: 'good',",
|
|
118
|
+
" version: '1.0.0',",
|
|
119
|
+
' entries: [',
|
|
120
|
+
" { id: 'v1', type: 'rule', domain: 'good', title: 'Good', severity: 'suggestion', description: 'Works', tags: ['ok'] },",
|
|
121
|
+
' ],',
|
|
122
|
+
' }));',
|
|
123
|
+
'',
|
|
124
|
+
' const entries = loadIntelligenceData(tempDir);',
|
|
125
|
+
' expect(entries).toHaveLength(1);',
|
|
126
|
+
" expect(entries[0].id).toBe('v1');",
|
|
127
|
+
' });',
|
|
128
|
+
'',
|
|
129
|
+
" it('should skip files without entries array', () => {",
|
|
130
|
+
" writeFileSync(join(tempDir, 'no-entries.json'), JSON.stringify({",
|
|
131
|
+
" domain: 'incomplete',",
|
|
132
|
+
" version: '1.0.0',",
|
|
133
|
+
' }));',
|
|
134
|
+
'',
|
|
135
|
+
' const entries = loadIntelligenceData(tempDir);',
|
|
136
|
+
' expect(entries).toEqual([]);',
|
|
137
|
+
' });',
|
|
138
|
+
'',
|
|
139
|
+
" it('should ignore non-JSON files', () => {",
|
|
140
|
+
" writeFileSync(join(tempDir, 'readme.txt'), 'Not a JSON file');",
|
|
141
|
+
' const entries = loadIntelligenceData(tempDir);',
|
|
142
|
+
' expect(entries).toEqual([]);',
|
|
143
|
+
' });',
|
|
144
|
+
'});',
|
|
145
|
+
].join('\n');
|
|
146
|
+
//# sourceMappingURL=test-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-loader.js","sourceRoot":"","sources":["../../src/templates/test-loader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO,oBAAoB,CAAC;AAC9B,CAAC;AAED,MAAM,oBAAoB,GAAG;IAC3B,uEAAuE;IACvE,6DAA6D;IAC7D,mCAAmC;IACnC,mCAAmC;IACnC,mEAAmE;IACnE,EAAE;IACF,yCAAyC;IACzC,wBAAwB;IACxB,EAAE;IACF,sBAAsB;IACtB,4DAA4D;IAC5D,8CAA8C;IAC9C,OAAO;IACP,EAAE;IACF,qBAAqB;IACrB,wDAAwD;IACxD,OAAO;IACP,EAAE;IACF,2DAA2D;IAC3D,uEAAuE;IACvE,8BAA8B;IAC9B,yBAAyB;IACzB,kBAAkB;IAClB,WAAW;IACX,0BAA0B;IAC1B,4BAA4B;IAC5B,kCAAkC;IAClC,kCAAkC;IAClC,gCAAgC;IAChC,2CAA2C;IAC3C,2BAA2B;IAC3B,YAAY;IACZ,UAAU;IACV,UAAU;IACV,EAAE;IACF,oDAAoD;IACpD,sCAAsC;IACtC,4CAA4C;IAC5C,oDAAoD;IACpD,OAAO;IACP,EAAE;IACF,yDAAyD;IACzD,2CAA2C;IAC3C,uEAAuE;IACvE,iBAAiB;IACjB,2BAA2B;IAC3B,oBAAoB;IACpB,+HAA+H;IAC/H,6HAA6H;IAC7H,YAAY;IACZ,YAAY;IACZ,OAAO;IACP,EAAE;IACF,oDAAoD;IACpD,sCAAsC;IACtC,OAAO;IACP,EAAE;IACF,kEAAkE;IAClE,+DAA+D;IAC/D,sBAAsB;IACtB,yBAAyB;IACzB,kBAAkB;IAClB,8HAA8H;IAC9H,6HAA6H;IAC7H,iHAAiH;IACjH,UAAU;IACV,UAAU;IACV,EAAE;IACF,oDAAoD;IACpD,sCAAsC;IACtC,yCAAyC;IACzC,OAAO;IACP,EAAE;IACF,uDAAuD;IACvD,wEAAwE;IACxE,oBAAoB;IACpB,yBAAyB;IACzB,kBAAkB;IAClB,2HAA2H;IAC3H,UAAU;IACV,UAAU;IACV,EAAE;IACF,oDAAoD;IACpD,sCAAsC;IACtC,OAAO;IACP,EAAE;IACF,uDAAuD;IACvD,mEAAmE;IACnE,oBAAoB;IACpB,yBAAyB;IACzB,kBAAkB;IAClB,uHAAuH;IACvH,UAAU;IACV,UAAU;IACV,EAAE;IACF,oDAAoD;IACpD,sCAAsC;IACtC,0CAA0C;IAC1C,OAAO;IACP,EAAE;IACF,+DAA+D;IAC/D,gEAAgE;IAChE,kCAAkC;IAClC,OAAO;IACP,EAAE;IACF,6DAA6D;IAC7D,0EAA0E;IAC1E,iEAAiE;IACjE,uBAAuB;IACvB,yBAAyB;IACzB,kBAAkB;IAClB,gIAAgI;IAChI,UAAU;IACV,UAAU;IACV,EAAE;IACF,oDAAoD;IACpD,sCAAsC;IACtC,uCAAuC;IACvC,OAAO;IACP,EAAE;IACF,yDAAyD;IACzD,sEAAsE;IACtE,6BAA6B;IAC7B,yBAAyB;IACzB,UAAU;IACV,EAAE;IACF,oDAAoD;IACpD,kCAAkC;IAClC,OAAO;IACP,EAAE;IACF,8CAA8C;IAC9C,oEAAoE;IACpE,oDAAoD;IACpD,kCAAkC;IAClC,OAAO;IACP,KAAK;CACN,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC"}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates src/__tests__/planner.test.ts for a new agent.
|
|
3
|
+
* Tests the Planner state machine: create, approve, execute, update tasks, complete.
|
|
4
|
+
*/
|
|
5
|
+
export function generatePlannerTest() {
|
|
6
|
+
return PLANNER_TEST_TEMPLATE;
|
|
7
|
+
}
|
|
8
|
+
const PLANNER_TEST_TEMPLATE = [
|
|
9
|
+
"import { describe, it, expect, beforeEach, afterEach } from 'vitest';",
|
|
10
|
+
"import { Planner } from '../planning/planner.js';",
|
|
11
|
+
"import { mkdirSync, rmSync } from 'node:fs';",
|
|
12
|
+
"import { join } from 'node:path';",
|
|
13
|
+
"import { tmpdir } from 'node:os';",
|
|
14
|
+
'',
|
|
15
|
+
"describe('Planner', () => {",
|
|
16
|
+
' let tempDir: string;',
|
|
17
|
+
' let planner: Planner;',
|
|
18
|
+
'',
|
|
19
|
+
' beforeEach(() => {',
|
|
20
|
+
' tempDir = join(tmpdir(), `planner-test-${Date.now()}`);',
|
|
21
|
+
' mkdirSync(tempDir, { recursive: true });',
|
|
22
|
+
" planner = new Planner(join(tempDir, 'plans.json'));",
|
|
23
|
+
' });',
|
|
24
|
+
'',
|
|
25
|
+
' afterEach(() => {',
|
|
26
|
+
' rmSync(tempDir, { recursive: true, force: true });',
|
|
27
|
+
' });',
|
|
28
|
+
'',
|
|
29
|
+
" describe('create', () => {",
|
|
30
|
+
" it('should create a plan in draft status', () => {",
|
|
31
|
+
" const plan = planner.create({ objective: 'Add auth', scope: 'backend' });",
|
|
32
|
+
' expect(plan.id).toMatch(/^plan-/);',
|
|
33
|
+
" expect(plan.status).toBe('draft');",
|
|
34
|
+
" expect(plan.objective).toBe('Add auth');",
|
|
35
|
+
" expect(plan.scope).toBe('backend');",
|
|
36
|
+
' });',
|
|
37
|
+
'',
|
|
38
|
+
" it('should create a plan with tasks', () => {",
|
|
39
|
+
' const plan = planner.create({',
|
|
40
|
+
" objective: 'Add auth',",
|
|
41
|
+
" scope: 'backend',",
|
|
42
|
+
' tasks: [',
|
|
43
|
+
" { title: 'Add JWT', description: 'Implement JWT signing' },",
|
|
44
|
+
" { title: 'Add middleware', description: 'Auth middleware' },",
|
|
45
|
+
' ],',
|
|
46
|
+
' });',
|
|
47
|
+
' expect(plan.tasks).toHaveLength(2);',
|
|
48
|
+
" expect(plan.tasks[0].id).toBe('task-1');",
|
|
49
|
+
" expect(plan.tasks[0].status).toBe('pending');",
|
|
50
|
+
" expect(plan.tasks[1].id).toBe('task-2');",
|
|
51
|
+
' });',
|
|
52
|
+
'',
|
|
53
|
+
" it('should create a plan with decisions', () => {",
|
|
54
|
+
' const plan = planner.create({',
|
|
55
|
+
" objective: 'Add caching',",
|
|
56
|
+
" scope: 'api',",
|
|
57
|
+
" decisions: ['Use Redis', 'TTL of 5 minutes'],",
|
|
58
|
+
' });',
|
|
59
|
+
" expect(plan.decisions).toEqual(['Use Redis', 'TTL of 5 minutes']);",
|
|
60
|
+
' });',
|
|
61
|
+
'',
|
|
62
|
+
" it('should persist plan to disk', () => {",
|
|
63
|
+
" planner.create({ objective: 'Test persistence', scope: 'test' });",
|
|
64
|
+
" const planner2 = new Planner(join(tempDir, 'plans.json'));",
|
|
65
|
+
' expect(planner2.list()).toHaveLength(1);',
|
|
66
|
+
' });',
|
|
67
|
+
' });',
|
|
68
|
+
'',
|
|
69
|
+
" describe('get', () => {",
|
|
70
|
+
" it('should return a plan by id', () => {",
|
|
71
|
+
" const created = planner.create({ objective: 'Find me', scope: 'test' });",
|
|
72
|
+
' const found = planner.get(created.id);',
|
|
73
|
+
' expect(found).not.toBeNull();',
|
|
74
|
+
" expect(found!.objective).toBe('Find me');",
|
|
75
|
+
' });',
|
|
76
|
+
'',
|
|
77
|
+
" it('should return null for unknown id', () => {",
|
|
78
|
+
" expect(planner.get('plan-nonexistent')).toBeNull();",
|
|
79
|
+
' });',
|
|
80
|
+
' });',
|
|
81
|
+
'',
|
|
82
|
+
" describe('list', () => {",
|
|
83
|
+
" it('should list all plans', () => {",
|
|
84
|
+
" planner.create({ objective: 'Plan A', scope: 'a' });",
|
|
85
|
+
" planner.create({ objective: 'Plan B', scope: 'b' });",
|
|
86
|
+
' expect(planner.list()).toHaveLength(2);',
|
|
87
|
+
' });',
|
|
88
|
+
'',
|
|
89
|
+
" it('should return empty array when no plans', () => {",
|
|
90
|
+
' expect(planner.list()).toEqual([]);',
|
|
91
|
+
' });',
|
|
92
|
+
' });',
|
|
93
|
+
'',
|
|
94
|
+
" describe('approve', () => {",
|
|
95
|
+
" it('should transition draft to approved', () => {",
|
|
96
|
+
" const plan = planner.create({ objective: 'Approve me', scope: 'test' });",
|
|
97
|
+
' const approved = planner.approve(plan.id);',
|
|
98
|
+
" expect(approved.status).toBe('approved');",
|
|
99
|
+
' });',
|
|
100
|
+
'',
|
|
101
|
+
" it('should throw when approving non-draft plan', () => {",
|
|
102
|
+
" const plan = planner.create({ objective: 'Already approved', scope: 'test' });",
|
|
103
|
+
' planner.approve(plan.id);',
|
|
104
|
+
" expect(() => planner.approve(plan.id)).toThrow('must be');",
|
|
105
|
+
' });',
|
|
106
|
+
'',
|
|
107
|
+
" it('should throw for unknown plan', () => {",
|
|
108
|
+
" expect(() => planner.approve('plan-xxx')).toThrow('not found');",
|
|
109
|
+
' });',
|
|
110
|
+
' });',
|
|
111
|
+
'',
|
|
112
|
+
" describe('startExecution', () => {",
|
|
113
|
+
" it('should transition approved to executing', () => {",
|
|
114
|
+
" const plan = planner.create({ objective: 'Execute me', scope: 'test' });",
|
|
115
|
+
' planner.approve(plan.id);',
|
|
116
|
+
' const executing = planner.startExecution(plan.id);',
|
|
117
|
+
" expect(executing.status).toBe('executing');",
|
|
118
|
+
' });',
|
|
119
|
+
'',
|
|
120
|
+
" it('should throw when executing non-approved plan', () => {",
|
|
121
|
+
" const plan = planner.create({ objective: 'Not approved', scope: 'test' });",
|
|
122
|
+
" expect(() => planner.startExecution(plan.id)).toThrow('must be');",
|
|
123
|
+
' });',
|
|
124
|
+
' });',
|
|
125
|
+
'',
|
|
126
|
+
" describe('updateTask', () => {",
|
|
127
|
+
" it('should update task status on executing plan', () => {",
|
|
128
|
+
' const plan = planner.create({',
|
|
129
|
+
" objective: 'Task test',",
|
|
130
|
+
" scope: 'test',",
|
|
131
|
+
" tasks: [{ title: 'Task 1', description: 'Do thing' }],",
|
|
132
|
+
' });',
|
|
133
|
+
' planner.approve(plan.id);',
|
|
134
|
+
' planner.startExecution(plan.id);',
|
|
135
|
+
" const updated = planner.updateTask(plan.id, 'task-1', 'in_progress');",
|
|
136
|
+
" expect(updated.tasks[0].status).toBe('in_progress');",
|
|
137
|
+
' });',
|
|
138
|
+
'',
|
|
139
|
+
" it('should support all task statuses', () => {",
|
|
140
|
+
' const plan = planner.create({',
|
|
141
|
+
" objective: 'Status test',",
|
|
142
|
+
" scope: 'test',",
|
|
143
|
+
' tasks: [',
|
|
144
|
+
" { title: 'T1', description: 'd' },",
|
|
145
|
+
" { title: 'T2', description: 'd' },",
|
|
146
|
+
" { title: 'T3', description: 'd' },",
|
|
147
|
+
" { title: 'T4', description: 'd' },",
|
|
148
|
+
" { title: 'T5', description: 'd' },",
|
|
149
|
+
' ],',
|
|
150
|
+
' });',
|
|
151
|
+
' planner.approve(plan.id);',
|
|
152
|
+
' planner.startExecution(plan.id);',
|
|
153
|
+
" planner.updateTask(plan.id, 'task-1', 'completed');",
|
|
154
|
+
" planner.updateTask(plan.id, 'task-2', 'skipped');",
|
|
155
|
+
" planner.updateTask(plan.id, 'task-3', 'failed');",
|
|
156
|
+
" planner.updateTask(plan.id, 'task-4', 'in_progress');",
|
|
157
|
+
' const result = planner.get(plan.id)!;',
|
|
158
|
+
" expect(result.tasks[0].status).toBe('completed');",
|
|
159
|
+
" expect(result.tasks[1].status).toBe('skipped');",
|
|
160
|
+
" expect(result.tasks[2].status).toBe('failed');",
|
|
161
|
+
" expect(result.tasks[3].status).toBe('in_progress');",
|
|
162
|
+
" expect(result.tasks[4].status).toBe('pending');",
|
|
163
|
+
' });',
|
|
164
|
+
'',
|
|
165
|
+
" it('should throw when updating tasks on non-executing plan', () => {",
|
|
166
|
+
' const plan = planner.create({',
|
|
167
|
+
" objective: 'Not executing',",
|
|
168
|
+
" scope: 'test',",
|
|
169
|
+
" tasks: [{ title: 'T1', description: 'd' }],",
|
|
170
|
+
' });',
|
|
171
|
+
" expect(() => planner.updateTask(plan.id, 'task-1', 'completed')).toThrow('must be');",
|
|
172
|
+
' });',
|
|
173
|
+
'',
|
|
174
|
+
" it('should throw for unknown task', () => {",
|
|
175
|
+
' const plan = planner.create({',
|
|
176
|
+
" objective: 'Unknown task',",
|
|
177
|
+
" scope: 'test',",
|
|
178
|
+
" tasks: [{ title: 'T1', description: 'd' }],",
|
|
179
|
+
' });',
|
|
180
|
+
' planner.approve(plan.id);',
|
|
181
|
+
' planner.startExecution(plan.id);',
|
|
182
|
+
" expect(() => planner.updateTask(plan.id, 'task-99', 'completed')).toThrow('not found');",
|
|
183
|
+
' });',
|
|
184
|
+
' });',
|
|
185
|
+
'',
|
|
186
|
+
" describe('complete', () => {",
|
|
187
|
+
" it('should transition executing to completed', () => {",
|
|
188
|
+
" const plan = planner.create({ objective: 'Complete me', scope: 'test' });",
|
|
189
|
+
' planner.approve(plan.id);',
|
|
190
|
+
' planner.startExecution(plan.id);',
|
|
191
|
+
' const completed = planner.complete(plan.id);',
|
|
192
|
+
" expect(completed.status).toBe('completed');",
|
|
193
|
+
' });',
|
|
194
|
+
'',
|
|
195
|
+
" it('should throw when completing non-executing plan', () => {",
|
|
196
|
+
" const plan = planner.create({ objective: 'Not executing', scope: 'test' });",
|
|
197
|
+
" expect(() => planner.complete(plan.id)).toThrow('must be');",
|
|
198
|
+
' });',
|
|
199
|
+
' });',
|
|
200
|
+
'',
|
|
201
|
+
" describe('getExecuting', () => {",
|
|
202
|
+
" it('should return only executing plans', () => {",
|
|
203
|
+
" const p1 = planner.create({ objective: 'Executing', scope: 'a' });",
|
|
204
|
+
" planner.create({ objective: 'Draft', scope: 'b' });",
|
|
205
|
+
' planner.approve(p1.id);',
|
|
206
|
+
' planner.startExecution(p1.id);',
|
|
207
|
+
' const executing = planner.getExecuting();',
|
|
208
|
+
' expect(executing).toHaveLength(1);',
|
|
209
|
+
" expect(executing[0].objective).toBe('Executing');",
|
|
210
|
+
' });',
|
|
211
|
+
'',
|
|
212
|
+
" it('should return empty when nothing is executing', () => {",
|
|
213
|
+
" planner.create({ objective: 'Draft only', scope: 'test' });",
|
|
214
|
+
' expect(planner.getExecuting()).toEqual([]);',
|
|
215
|
+
' });',
|
|
216
|
+
' });',
|
|
217
|
+
'',
|
|
218
|
+
" describe('getActive', () => {",
|
|
219
|
+
" it('should return draft, approved, and executing plans', () => {",
|
|
220
|
+
" const p1 = planner.create({ objective: 'Draft', scope: 'a' });",
|
|
221
|
+
" const p2 = planner.create({ objective: 'Approved', scope: 'b' });",
|
|
222
|
+
" const p3 = planner.create({ objective: 'Executing', scope: 'c' });",
|
|
223
|
+
" const p4 = planner.create({ objective: 'Completed', scope: 'd' });",
|
|
224
|
+
' planner.approve(p2.id);',
|
|
225
|
+
' planner.approve(p3.id);',
|
|
226
|
+
' planner.startExecution(p3.id);',
|
|
227
|
+
' planner.approve(p4.id);',
|
|
228
|
+
' planner.startExecution(p4.id);',
|
|
229
|
+
' planner.complete(p4.id);',
|
|
230
|
+
' const active = planner.getActive();',
|
|
231
|
+
' expect(active).toHaveLength(3);',
|
|
232
|
+
" expect(active.map((p) => p.status).sort()).toEqual(['approved', 'draft', 'executing']);",
|
|
233
|
+
' });',
|
|
234
|
+
' });',
|
|
235
|
+
'',
|
|
236
|
+
" describe('full lifecycle', () => {",
|
|
237
|
+
" it('should support draft → approved → executing → completed with tasks', () => {",
|
|
238
|
+
' const plan = planner.create({',
|
|
239
|
+
" objective: 'Full lifecycle test',",
|
|
240
|
+
" scope: 'integration',",
|
|
241
|
+
" decisions: ['Use TDD'],",
|
|
242
|
+
' tasks: [',
|
|
243
|
+
" { title: 'Write tests', description: 'Write failing tests first' },",
|
|
244
|
+
" { title: 'Implement', description: 'Make tests pass' },",
|
|
245
|
+
" { title: 'Refactor', description: 'Clean up' },",
|
|
246
|
+
' ],',
|
|
247
|
+
' });',
|
|
248
|
+
" expect(plan.status).toBe('draft');",
|
|
249
|
+
'',
|
|
250
|
+
' planner.approve(plan.id);',
|
|
251
|
+
" expect(planner.get(plan.id)!.status).toBe('approved');",
|
|
252
|
+
'',
|
|
253
|
+
' planner.startExecution(plan.id);',
|
|
254
|
+
" expect(planner.get(plan.id)!.status).toBe('executing');",
|
|
255
|
+
'',
|
|
256
|
+
" planner.updateTask(plan.id, 'task-1', 'in_progress');",
|
|
257
|
+
" planner.updateTask(plan.id, 'task-1', 'completed');",
|
|
258
|
+
" planner.updateTask(plan.id, 'task-2', 'in_progress');",
|
|
259
|
+
" planner.updateTask(plan.id, 'task-2', 'completed');",
|
|
260
|
+
" planner.updateTask(plan.id, 'task-3', 'skipped');",
|
|
261
|
+
'',
|
|
262
|
+
' const final = planner.complete(plan.id);',
|
|
263
|
+
" expect(final.status).toBe('completed');",
|
|
264
|
+
" expect(final.tasks[0].status).toBe('completed');",
|
|
265
|
+
" expect(final.tasks[1].status).toBe('completed');",
|
|
266
|
+
" expect(final.tasks[2].status).toBe('skipped');",
|
|
267
|
+
' });',
|
|
268
|
+
' });',
|
|
269
|
+
'});',
|
|
270
|
+
].join('\n');
|
|
271
|
+
//# sourceMappingURL=test-planner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-planner.js","sourceRoot":"","sources":["../../src/templates/test-planner.ts"],"names":[],"mappings":"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"}
|