@soleri/forge 3.0.0 → 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/dist/index.js +0 -0
- package/dist/knowledge-installer.d.ts +2 -1
- package/dist/scaffolder.js +1 -91
- package/dist/scaffolder.js.map +1 -1
- package/dist/templates/activate.js +1 -2
- package/dist/templates/activate.js.map +1 -1
- package/dist/templates/core-facade.js +1 -6
- package/dist/templates/core-facade.js.map +1 -1
- package/dist/templates/domain-facade.js +1 -3
- package/dist/templates/domain-facade.js.map +1 -1
- package/dist/templates/entry-point.js +2 -7
- package/dist/templates/entry-point.js.map +1 -1
- package/dist/templates/llm-client.js +3 -4
- package/dist/templates/llm-client.js.map +1 -1
- package/dist/templates/package-json.js +1 -2
- package/dist/templates/package-json.js.map +1 -1
- package/dist/templates/test-facades.js +2 -5
- package/dist/templates/test-facades.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/scaffolder.test.ts +35 -47
- package/src/knowledge-installer.ts +1 -1
- package/src/scaffolder.ts +1 -97
- package/src/templates/activate.ts +1 -2
- package/src/templates/core-facade.ts +1 -6
- package/src/templates/domain-facade.ts +1 -3
- package/src/templates/entry-point.ts +2 -7
- package/src/templates/llm-client.ts +3 -4
- package/src/templates/package-json.ts +1 -2
- package/src/templates/test-facades.ts +2 -5
- package/src/templates/brain.ts +0 -478
- package/src/templates/facade-factory.ts +0 -62
- package/src/templates/facade-types.ts +0 -45
- package/src/templates/intelligence-loader.ts +0 -42
- package/src/templates/intelligence-types.ts +0 -23
- package/src/templates/llm-key-pool.ts +0 -212
- package/src/templates/llm-types.ts +0 -160
- package/src/templates/llm-utils.ts +0 -259
- package/src/templates/planner.ts +0 -150
- package/src/templates/test-brain.ts +0 -474
- package/src/templates/test-llm.ts +0 -575
- package/src/templates/test-loader.ts +0 -146
- package/src/templates/test-planner.ts +0 -271
- package/src/templates/test-vault.ts +0 -380
- package/src/templates/vault.ts +0 -263
package/src/scaffolder.ts
CHANGED
|
@@ -13,32 +13,17 @@ import type { AgentConfig, ScaffoldResult, ScaffoldPreview, AgentInfo } from './
|
|
|
13
13
|
import { generatePackageJson } from './templates/package-json.js';
|
|
14
14
|
import { generateTsconfig } from './templates/tsconfig.js';
|
|
15
15
|
import { generateVitestConfig } from './templates/vitest-config.js';
|
|
16
|
-
import { generateFacadeTypes } from './templates/facade-types.js';
|
|
17
|
-
import { generateFacadeFactory } from './templates/facade-factory.js';
|
|
18
|
-
import { generateVault } from './templates/vault.js';
|
|
19
|
-
import { generateIntelligenceTypes } from './templates/intelligence-types.js';
|
|
20
|
-
import { generateIntelligenceLoader } from './templates/intelligence-loader.js';
|
|
21
16
|
import { generatePersona } from './templates/persona.js';
|
|
22
17
|
import { generateDomainFacade } from './templates/domain-facade.js';
|
|
23
18
|
import { generateCoreFacade } from './templates/core-facade.js';
|
|
24
19
|
import { generateEntryPoint } from './templates/entry-point.js';
|
|
25
|
-
import { generateVaultTest } from './templates/test-vault.js';
|
|
26
|
-
import { generateLoaderTest } from './templates/test-loader.js';
|
|
27
20
|
import { generateFacadesTest } from './templates/test-facades.js';
|
|
28
21
|
import { generateClaudeMdTemplate } from './templates/claude-md-template.js';
|
|
29
22
|
import { generateInjectClaudeMd } from './templates/inject-claude-md.js';
|
|
30
23
|
import { generateActivate } from './templates/activate.js';
|
|
31
24
|
import { generateReadme } from './templates/readme.js';
|
|
32
25
|
import { generateSetupScript } from './templates/setup-script.js';
|
|
33
|
-
import { generatePlanner } from './templates/planner.js';
|
|
34
|
-
import { generatePlannerTest } from './templates/test-planner.js';
|
|
35
|
-
import { generateBrain } from './templates/brain.js';
|
|
36
|
-
import { generateBrainTest } from './templates/test-brain.js';
|
|
37
|
-
import { generateLLMTypes } from './templates/llm-types.js';
|
|
38
|
-
import { generateLLMUtils } from './templates/llm-utils.js';
|
|
39
|
-
import { generateLLMKeyPool } from './templates/llm-key-pool.js';
|
|
40
26
|
import { generateLLMClient } from './templates/llm-client.js';
|
|
41
|
-
import { generateLLMTest } from './templates/test-llm.js';
|
|
42
27
|
|
|
43
28
|
/**
|
|
44
29
|
* Preview what scaffold will create without writing anything.
|
|
@@ -60,40 +45,11 @@ export function previewScaffold(config: AgentConfig): ScaffoldPreview {
|
|
|
60
45
|
description:
|
|
61
46
|
'Entry point — initializes vault, planner, brain, registers facades, starts stdio',
|
|
62
47
|
},
|
|
63
|
-
{
|
|
64
|
-
path: 'src/planning/planner.ts',
|
|
65
|
-
description: 'Plan state machine — draft → approved → executing → completed',
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
path: 'src/brain/brain.ts',
|
|
69
|
-
description:
|
|
70
|
-
'Intelligence layer — TF-IDF scoring, auto-tagging, duplicate detection, adaptive weights',
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
path: 'src/llm/types.ts',
|
|
74
|
-
description:
|
|
75
|
-
'LLM types — SecretString, LLMError, call options/result, circuit breaker, key pool, routing',
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
path: 'src/llm/utils.ts',
|
|
79
|
-
description:
|
|
80
|
-
'LLM utilities — CircuitBreaker, retry with backoff+jitter, rate limit header parser',
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
path: 'src/llm/key-pool.ts',
|
|
84
|
-
description:
|
|
85
|
-
'Key pool — multi-key rotation with per-key circuit breakers, preemptive quota rotation',
|
|
86
|
-
},
|
|
87
48
|
{
|
|
88
49
|
path: 'src/llm/llm-client.ts',
|
|
89
50
|
description:
|
|
90
51
|
'LLM client — unified OpenAI/Anthropic caller with model routing (optional, needs API keys)',
|
|
91
52
|
},
|
|
92
|
-
{ path: 'src/facades/types.ts', description: 'Facade type system (OpHandler, FacadeConfig)' },
|
|
93
|
-
{
|
|
94
|
-
path: 'src/facades/facade-factory.ts',
|
|
95
|
-
description: 'Registers facades as MCP tools with op dispatch',
|
|
96
|
-
},
|
|
97
53
|
{
|
|
98
54
|
path: 'src/facades/core.facade.ts',
|
|
99
55
|
description: 'Core facade — search, vault stats, health, identity',
|
|
@@ -102,18 +58,6 @@ export function previewScaffold(config: AgentConfig): ScaffoldPreview {
|
|
|
102
58
|
path: `src/facades/${d}.facade.ts`,
|
|
103
59
|
description: `${d} facade — search, get_patterns, capture, remove`,
|
|
104
60
|
})),
|
|
105
|
-
{
|
|
106
|
-
path: 'src/vault/vault.ts',
|
|
107
|
-
description: 'SQLite vault with FTS5 full-text search (BM25 ranking)',
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
path: 'src/intelligence/types.ts',
|
|
111
|
-
description: 'IntelligenceEntry and IntelligenceBundle types',
|
|
112
|
-
},
|
|
113
|
-
{
|
|
114
|
-
path: 'src/intelligence/loader.ts',
|
|
115
|
-
description: 'Loads and validates JSON intelligence data files',
|
|
116
|
-
},
|
|
117
61
|
...config.domains.map((d) => ({
|
|
118
62
|
path: `src/intelligence/data/${d}.json`,
|
|
119
63
|
description: `Empty ${d} intelligence bundle — ready for knowledge capture`,
|
|
@@ -134,32 +78,10 @@ export function previewScaffold(config: AgentConfig): ScaffoldPreview {
|
|
|
134
78
|
path: 'src/activation/activate.ts',
|
|
135
79
|
description: `${config.name} activation system — persona adoption, setup status, tool recommendations`,
|
|
136
80
|
},
|
|
137
|
-
{
|
|
138
|
-
path: 'src/__tests__/vault.test.ts',
|
|
139
|
-
description: 'Vault tests — CRUD, FTS5 search, stats, project registration (32 tests)',
|
|
140
|
-
},
|
|
141
|
-
{
|
|
142
|
-
path: 'src/__tests__/loader.test.ts',
|
|
143
|
-
description: 'Intelligence loader tests — valid/invalid JSON, edge cases (9 tests)',
|
|
144
|
-
},
|
|
145
81
|
{
|
|
146
82
|
path: 'src/__tests__/facades.test.ts',
|
|
147
83
|
description: `Facade integration tests — all ${config.domains.length + 1} facades`,
|
|
148
84
|
},
|
|
149
|
-
{
|
|
150
|
-
path: 'src/__tests__/planner.test.ts',
|
|
151
|
-
description: 'Planner tests — state machine, task lifecycle, persistence (~20 tests)',
|
|
152
|
-
},
|
|
153
|
-
{
|
|
154
|
-
path: 'src/__tests__/brain.test.ts',
|
|
155
|
-
description:
|
|
156
|
-
'Brain tests — TF-IDF scoring, auto-tagging, duplicate detection, adaptive weights (~38 tests)',
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
path: 'src/__tests__/llm.test.ts',
|
|
160
|
-
description:
|
|
161
|
-
'LLM tests — SecretString, CircuitBreaker, retry, rate limits, KeyPool, ModelRouter (~30 tests)',
|
|
162
|
-
},
|
|
163
85
|
{ path: '.mcp.json', description: 'MCP client config for connecting to this agent' },
|
|
164
86
|
{
|
|
165
87
|
path: 'README.md',
|
|
@@ -238,13 +160,10 @@ export function scaffold(config: AgentConfig): ScaffoldResult {
|
|
|
238
160
|
'scripts',
|
|
239
161
|
'src',
|
|
240
162
|
'src/facades',
|
|
241
|
-
'src/vault',
|
|
242
163
|
'src/intelligence',
|
|
243
164
|
'src/intelligence/data',
|
|
244
165
|
'src/identity',
|
|
245
166
|
'src/activation',
|
|
246
|
-
'src/planning',
|
|
247
|
-
'src/brain',
|
|
248
167
|
'src/llm',
|
|
249
168
|
'src/__tests__',
|
|
250
169
|
];
|
|
@@ -282,29 +201,14 @@ export function scaffold(config: AgentConfig): ScaffoldResult {
|
|
|
282
201
|
|
|
283
202
|
// Write source files
|
|
284
203
|
const sourceFiles: Array<[string, string]> = [
|
|
285
|
-
['src/facades/types.ts', generateFacadeTypes()],
|
|
286
|
-
['src/facades/facade-factory.ts', generateFacadeFactory()],
|
|
287
204
|
['src/facades/core.facade.ts', generateCoreFacade(config)],
|
|
288
|
-
['src/vault/vault.ts', generateVault()],
|
|
289
|
-
['src/intelligence/types.ts', generateIntelligenceTypes()],
|
|
290
|
-
['src/intelligence/loader.ts', generateIntelligenceLoader()],
|
|
291
205
|
['src/identity/persona.ts', generatePersona(config)],
|
|
292
206
|
['src/activation/claude-md-content.ts', generateClaudeMdTemplate(config)],
|
|
293
207
|
['src/activation/inject-claude-md.ts', generateInjectClaudeMd(config)],
|
|
294
208
|
['src/activation/activate.ts', generateActivate(config)],
|
|
295
209
|
['src/index.ts', generateEntryPoint(config)],
|
|
296
|
-
['src/planning/planner.ts', generatePlanner()],
|
|
297
|
-
['src/brain/brain.ts', generateBrain()],
|
|
298
|
-
['src/llm/types.ts', generateLLMTypes()],
|
|
299
|
-
['src/llm/utils.ts', generateLLMUtils()],
|
|
300
|
-
['src/llm/key-pool.ts', generateLLMKeyPool(config)],
|
|
301
210
|
['src/llm/llm-client.ts', generateLLMClient(config)],
|
|
302
|
-
['src/__tests__/vault.test.ts', generateVaultTest()],
|
|
303
|
-
['src/__tests__/loader.test.ts', generateLoaderTest()],
|
|
304
211
|
['src/__tests__/facades.test.ts', generateFacadesTest(config)],
|
|
305
|
-
['src/__tests__/planner.test.ts', generatePlannerTest()],
|
|
306
|
-
['src/__tests__/brain.test.ts', generateBrainTest()],
|
|
307
|
-
['src/__tests__/llm.test.ts', generateLLMTest(config)],
|
|
308
212
|
];
|
|
309
213
|
|
|
310
214
|
// Domain facades and empty data files
|
|
@@ -329,7 +233,7 @@ export function scaffold(config: AgentConfig): ScaffoldResult {
|
|
|
329
233
|
`${config.domains.length} empty knowledge domains ready for capture`,
|
|
330
234
|
`Intelligence layer (Brain) — TF-IDF scoring, auto-tagging, duplicate detection`,
|
|
331
235
|
`Activation system included — say "Hello, ${config.name}!" to activate`,
|
|
332
|
-
`
|
|
236
|
+
`1 test suite — facades (vault, brain, planner, llm tests provided by @soleri/core)`,
|
|
333
237
|
];
|
|
334
238
|
|
|
335
239
|
if (mcpReg.registered) {
|
|
@@ -35,8 +35,7 @@ export function generateActivate(config: AgentConfig): string {
|
|
|
35
35
|
"import { homedir } from 'node:os';",
|
|
36
36
|
"import { PERSONA } from '../identity/persona.js';",
|
|
37
37
|
"import { hasAgentMarker } from './inject-claude-md.js';",
|
|
38
|
-
"import type { Vault } from '
|
|
39
|
-
"import type { Planner, Plan } from '../planning/planner.js';",
|
|
38
|
+
"import type { Vault, Planner, Plan } from '@soleri/core';",
|
|
40
39
|
'',
|
|
41
40
|
'export interface ActivationResult {',
|
|
42
41
|
' activated: boolean;',
|
|
@@ -6,16 +6,11 @@ import type { AgentConfig } from '../types.js';
|
|
|
6
6
|
*/
|
|
7
7
|
export function generateCoreFacade(config: AgentConfig): string {
|
|
8
8
|
return `import { z } from 'zod';
|
|
9
|
-
import type { FacadeConfig } from '
|
|
10
|
-
import type { Vault } from '../vault/vault.js';
|
|
11
|
-
import type { IntelligenceEntry } from '../intelligence/types.js';
|
|
9
|
+
import type { FacadeConfig, Vault, IntelligenceEntry, Planner, Brain, KeyPool } from '@soleri/core';
|
|
12
10
|
import { PERSONA } from '../identity/persona.js';
|
|
13
11
|
import { activateAgent, deactivateAgent } from '../activation/activate.js';
|
|
14
12
|
import { injectClaudeMd, injectClaudeMdGlobal, hasAgentMarker } from '../activation/inject-claude-md.js';
|
|
15
|
-
import type { Planner } from '../planning/planner.js';
|
|
16
|
-
import type { Brain } from '../brain/brain.js';
|
|
17
13
|
import type { LLMClient } from '../llm/llm-client.js';
|
|
18
|
-
import type { KeyPool } from '../llm/key-pool.js';
|
|
19
14
|
|
|
20
15
|
export function createCoreFacade(vault: Vault, planner: Planner, brain: Brain, llmClient?: LLMClient, openaiKeyPool?: KeyPool, anthropicKeyPool?: KeyPool): FacadeConfig {
|
|
21
16
|
return {
|
|
@@ -6,9 +6,7 @@ export function generateDomainFacade(agentId: string, domain: string): string {
|
|
|
6
6
|
const facadeName = `${agentId}_${domain.replace(/-/g, '_')}`;
|
|
7
7
|
|
|
8
8
|
return `import { z } from 'zod';
|
|
9
|
-
import type { FacadeConfig } from '
|
|
10
|
-
import type { Vault } from '../vault/vault.js';
|
|
11
|
-
import type { Brain } from '../brain/brain.js';
|
|
9
|
+
import type { FacadeConfig, Vault, Brain } from '@soleri/core';
|
|
12
10
|
|
|
13
11
|
export function create${pascalCase(domain)}Facade(vault: Vault, brain: Brain): FacadeConfig {
|
|
14
12
|
return {
|
|
@@ -24,15 +24,10 @@ import { dirname, join } from 'node:path';
|
|
|
24
24
|
import { fileURLToPath } from 'node:url';
|
|
25
25
|
import { homedir } from 'node:os';
|
|
26
26
|
|
|
27
|
-
import { registerAllFacades } from '
|
|
27
|
+
import { Vault, Brain, Planner, KeyPool, loadKeyPoolConfig, loadIntelligenceData, registerAllFacades } from '@soleri/core';
|
|
28
28
|
${facadeImports}
|
|
29
29
|
import { createCoreFacade } from './facades/core.facade.js';
|
|
30
|
-
import { loadIntelligenceData } from './intelligence/loader.js';
|
|
31
|
-
import { Vault } from './vault/vault.js';
|
|
32
|
-
import { Planner } from './planning/planner.js';
|
|
33
|
-
import { Brain } from './brain/brain.js';
|
|
34
30
|
import { LLMClient } from './llm/llm-client.js';
|
|
35
|
-
import { KeyPool, loadKeyPoolConfig } from './llm/key-pool.js';
|
|
36
31
|
import { PERSONA, getPersonaPrompt } from './identity/persona.js';
|
|
37
32
|
|
|
38
33
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -63,7 +58,7 @@ async function main(): Promise<void> {
|
|
|
63
58
|
console.error(\`[\${PERSONA.name.toLowerCase()}] Brain: vocabulary \${brain.getVocabularySize()} terms\`);
|
|
64
59
|
|
|
65
60
|
// Initialize LLM client (optional — works without API keys)
|
|
66
|
-
const keyPoolFiles = loadKeyPoolConfig();
|
|
61
|
+
const keyPoolFiles = loadKeyPoolConfig('${config.id}');
|
|
67
62
|
const openaiKeyPool = new KeyPool(keyPoolFiles.openai);
|
|
68
63
|
const anthropicKeyPool = new KeyPool(keyPoolFiles.anthropic);
|
|
69
64
|
const llmClient = new LLMClient(openaiKeyPool, anthropicKeyPool);
|
|
@@ -12,15 +12,14 @@ export function generateLLMClient(config: AgentConfig): string {
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import Anthropic from '@anthropic-ai/sdk';
|
|
15
|
-
import { SecretString, LLMError } from '
|
|
15
|
+
import { SecretString, LLMError, CircuitBreaker, retry, parseRateLimitHeaders } from '@soleri/core';
|
|
16
16
|
import type {
|
|
17
17
|
LLMCallOptions,
|
|
18
18
|
LLMCallResult,
|
|
19
19
|
RouteEntry,
|
|
20
20
|
RoutingConfig,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
import type { KeyPool } from './key-pool.js';
|
|
21
|
+
KeyPool,
|
|
22
|
+
} from '@soleri/core';
|
|
24
23
|
import * as fs from 'node:fs';
|
|
25
24
|
import * as path from 'node:path';
|
|
26
25
|
import { homedir } from 'node:os';
|
|
@@ -23,11 +23,10 @@ export function generatePackageJson(config: AgentConfig): string {
|
|
|
23
23
|
dependencies: {
|
|
24
24
|
'@anthropic-ai/sdk': '^0.39.0',
|
|
25
25
|
'@modelcontextprotocol/sdk': '^1.12.1',
|
|
26
|
-
'
|
|
26
|
+
'@soleri/core': '^1.0.0',
|
|
27
27
|
zod: '^3.24.2',
|
|
28
28
|
},
|
|
29
29
|
devDependencies: {
|
|
30
|
-
'@types/better-sqlite3': '^7.6.12',
|
|
31
30
|
'@types/node': '^22.13.4',
|
|
32
31
|
'@vitest/coverage-v8': '^3.0.5',
|
|
33
32
|
tsx: '^4.19.2',
|
|
@@ -17,17 +17,14 @@ export function generateFacadesTest(config: AgentConfig): string {
|
|
|
17
17
|
.join('\n\n');
|
|
18
18
|
|
|
19
19
|
return `import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
20
|
-
import { Vault } from '
|
|
21
|
-
import {
|
|
22
|
-
import type { IntelligenceEntry } from '../intelligence/types.js';
|
|
20
|
+
import { Vault, Brain, Planner, KeyPool } from '@soleri/core';
|
|
21
|
+
import type { IntelligenceEntry } from '@soleri/core';
|
|
23
22
|
import { mkdirSync, readFileSync, rmSync, writeFileSync, existsSync } from 'node:fs';
|
|
24
23
|
import { join } from 'node:path';
|
|
25
24
|
import { tmpdir } from 'node:os';
|
|
26
25
|
${domainImports}
|
|
27
26
|
import { createCoreFacade } from '../facades/core.facade.js';
|
|
28
|
-
import { Planner } from '../planning/planner.js';
|
|
29
27
|
import { LLMClient } from '../llm/llm-client.js';
|
|
30
|
-
import { KeyPool } from '../llm/key-pool.js';
|
|
31
28
|
|
|
32
29
|
function makeEntry(overrides: Partial<IntelligenceEntry> = {}): IntelligenceEntry {
|
|
33
30
|
return {
|