@soleri/forge 5.8.0 → 5.10.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/lib.d.ts +1 -0
- package/dist/lib.js +1 -0
- package/dist/lib.js.map +1 -1
- package/dist/scaffolder.js +79 -233
- package/dist/scaffolder.js.map +1 -1
- package/dist/templates/entry-point.d.ts +1 -1
- package/dist/templates/entry-point.js +53 -10
- package/dist/templates/entry-point.js.map +1 -1
- package/dist/templates/extensions.d.ts +10 -0
- package/dist/templates/extensions.js +89 -0
- package/dist/templates/extensions.js.map +1 -0
- package/dist/templates/persona.js +27 -0
- package/dist/templates/persona.js.map +1 -1
- package/dist/templates/skills.d.ts +2 -0
- package/dist/templates/skills.js +10 -0
- package/dist/templates/skills.js.map +1 -1
- package/dist/templates/test-facades.js +228 -298
- package/dist/templates/test-facades.js.map +1 -1
- package/dist/types.d.ts +13 -2
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -1
- package/package.json +5 -1
- package/src/__tests__/extensions-scaffold.test.ts +63 -0
- package/src/__tests__/scaffolder.test.ts +9 -6
- package/src/lib.ts +1 -0
- package/src/scaffolder.ts +79 -234
- package/src/templates/entry-point.ts +53 -10
- package/src/templates/extensions.ts +91 -0
- package/src/templates/persona.ts +27 -0
- package/src/templates/skills.ts +11 -0
- package/src/templates/test-facades.ts +228 -298
- package/src/types.ts +8 -0
package/dist/types.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
/** Communication tone for the agent persona */
|
|
3
|
+
export const TONES = ['precise', 'mentor', 'pragmatic'];
|
|
2
4
|
/** Agent configuration — everything needed to scaffold */
|
|
3
5
|
export const AgentConfigSchema = z.object({
|
|
4
6
|
/** Agent identifier (kebab-case, used for directory and package name) */
|
|
@@ -13,11 +15,15 @@ export const AgentConfigSchema = z.object({
|
|
|
13
15
|
domains: z.array(z.string().min(1)).min(1).max(20),
|
|
14
16
|
/** Core principles the agent follows (3-7 recommended) */
|
|
15
17
|
principles: z.array(z.string()).min(1).max(10),
|
|
18
|
+
/** Communication tone: precise, mentor, or pragmatic */
|
|
19
|
+
tone: z.enum(TONES).optional().default('pragmatic'),
|
|
16
20
|
/** Greeting message when agent introduces itself (auto-generated if omitted) */
|
|
17
21
|
greeting: z.string().min(10).max(300).optional(),
|
|
18
22
|
/** Output directory (parent — agent dir will be created inside, defaults to cwd) */
|
|
19
23
|
outputDir: z.string().min(1).optional().default(process.cwd()),
|
|
20
24
|
/** Hook packs to install after scaffolding (optional) */
|
|
21
25
|
hookPacks: z.array(z.string()).optional(),
|
|
26
|
+
/** Skills to include (if omitted, all skills are included for backward compat) */
|
|
27
|
+
skills: z.array(z.string()).optional(),
|
|
22
28
|
});
|
|
23
29
|
//# sourceMappingURL=types.js.map
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,0DAA0D;AAC1D,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,yEAAyE;IACzE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,mBAAmB,EAAE,gDAAgD,CAAC;IAC3F,kCAAkC;IAClC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;IAC/B,gCAAgC;IAChC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IAChC,iDAAiD;IACjD,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IACxC,0CAA0C;IAC1C,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;IAClD,0DAA0D;IAC1D,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;IAC9C,gFAAgF;IAChF,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAChD,oFAAoF;IACpF,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;IAC9D,yDAAyD;IACzD,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,+CAA+C;AAC/C,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,SAAS,EAAE,QAAQ,EAAE,WAAW,CAAU,CAAC;AAGjE,0DAA0D;AAC1D,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,yEAAyE;IACzE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,mBAAmB,EAAE,gDAAgD,CAAC;IAC3F,kCAAkC;IAClC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;IAC/B,gCAAgC;IAChC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IAChC,iDAAiD;IACjD,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IACxC,0CAA0C;IAC1C,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;IAClD,0DAA0D;IAC1D,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;IAC9C,wDAAwD;IACxD,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC;IACnD,gFAAgF;IAChF,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAChD,oFAAoF;IACpF,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;IAC9D,yDAAyD;IACzD,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IACzC,kFAAkF;IAClF,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;CACvC,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@soleri/forge",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.10.0",
|
|
4
4
|
"description": "Scaffold AI agents that learn, remember, and grow with you.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
@@ -31,6 +31,10 @@
|
|
|
31
31
|
"./lib": {
|
|
32
32
|
"types": "./dist/lib.d.ts",
|
|
33
33
|
"import": "./dist/lib.js"
|
|
34
|
+
},
|
|
35
|
+
"./templates/extensions": {
|
|
36
|
+
"types": "./dist/templates/extensions.d.ts",
|
|
37
|
+
"import": "./dist/templates/extensions.js"
|
|
34
38
|
}
|
|
35
39
|
},
|
|
36
40
|
"publishConfig": {
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { describe, it, expect, afterEach } from 'vitest';
|
|
2
|
+
import { scaffold, previewScaffold } from '../scaffolder.js';
|
|
3
|
+
import { existsSync, readFileSync, rmSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { tmpdir } from 'node:os';
|
|
6
|
+
|
|
7
|
+
describe('scaffold extensions', () => {
|
|
8
|
+
const outputDir = join(tmpdir(), 'soleri-ext-test-' + Date.now());
|
|
9
|
+
const agentId = 'ext-test-agent';
|
|
10
|
+
const agentDir = join(outputDir, agentId);
|
|
11
|
+
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
rmSync(outputDir, { recursive: true, force: true });
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should create extensions directory with index and example op', () => {
|
|
17
|
+
scaffold({
|
|
18
|
+
id: agentId,
|
|
19
|
+
name: 'Extension Test',
|
|
20
|
+
role: 'Test agent',
|
|
21
|
+
description: 'Agent for testing extensions scaffold',
|
|
22
|
+
domains: ['testing'],
|
|
23
|
+
principles: ['Test everything'],
|
|
24
|
+
tone: 'pragmatic',
|
|
25
|
+
outputDir,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Extensions directory exists
|
|
29
|
+
expect(existsSync(join(agentDir, 'src', 'extensions', 'index.ts'))).toBe(true);
|
|
30
|
+
expect(existsSync(join(agentDir, 'src', 'extensions', 'ops', 'example.ts'))).toBe(true);
|
|
31
|
+
expect(existsSync(join(agentDir, 'src', 'extensions', 'facades'))).toBe(true);
|
|
32
|
+
expect(existsSync(join(agentDir, 'src', 'extensions', 'middleware'))).toBe(true);
|
|
33
|
+
|
|
34
|
+
// Extensions index references the agent ID
|
|
35
|
+
const indexContent = readFileSync(join(agentDir, 'src', 'extensions', 'index.ts'), 'utf-8');
|
|
36
|
+
expect(indexContent).toContain('ext-test-agent_core');
|
|
37
|
+
expect(indexContent).toContain('loadExtensions');
|
|
38
|
+
expect(indexContent).toContain('AgentExtensions');
|
|
39
|
+
|
|
40
|
+
// Entry point imports extensions
|
|
41
|
+
const entryPoint = readFileSync(join(agentDir, 'src', 'index.ts'), 'utf-8');
|
|
42
|
+
expect(entryPoint).toContain('wrapWithMiddleware');
|
|
43
|
+
expect(entryPoint).toContain('./extensions/index.js');
|
|
44
|
+
expect(entryPoint).toContain('AgentExtensions');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should include extensions in preview', () => {
|
|
48
|
+
const preview = previewScaffold({
|
|
49
|
+
id: agentId,
|
|
50
|
+
name: 'Extension Test',
|
|
51
|
+
role: 'Test agent',
|
|
52
|
+
description: 'Agent for testing extensions scaffold',
|
|
53
|
+
domains: ['testing'],
|
|
54
|
+
principles: ['Test everything'],
|
|
55
|
+
tone: 'pragmatic',
|
|
56
|
+
outputDir,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const extFile = preview.files.find((f) => f.path === 'src/extensions/');
|
|
60
|
+
expect(extFile).toBeDefined();
|
|
61
|
+
expect(extFile!.description).toContain('extension');
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -56,15 +56,18 @@ describe('Scaffolder', () => {
|
|
|
56
56
|
expect(paths).not.toContain('src/facades/data-pipelines.facade.ts');
|
|
57
57
|
|
|
58
58
|
// Should have domain facades + core facade in preview
|
|
59
|
-
expect(preview.facades).toHaveLength(
|
|
59
|
+
expect(preview.facades).toHaveLength(14); // 3 domains + 10 semantic + 1 agent core
|
|
60
60
|
expect(preview.facades[0].name).toBe('atlas_data_pipelines');
|
|
61
61
|
|
|
62
|
-
//
|
|
62
|
+
// Agent-specific facade has 5 ops
|
|
63
63
|
const coreFacade = preview.facades.find((f) => f.name === 'atlas_core')!;
|
|
64
|
-
expect(coreFacade.ops.length).toBe(
|
|
65
|
-
expect(coreFacade.ops).toContain('curator_status');
|
|
64
|
+
expect(coreFacade.ops.length).toBe(5);
|
|
66
65
|
expect(coreFacade.ops).toContain('health');
|
|
67
66
|
|
|
67
|
+
// Semantic facades cover the rest
|
|
68
|
+
const vaultFacade = preview.facades.find((f) => f.name === 'atlas_vault')!;
|
|
69
|
+
expect(vaultFacade).toBeDefined();
|
|
70
|
+
|
|
68
71
|
// Should NOT create any files
|
|
69
72
|
expect(existsSync(join(tempDir, 'atlas'))).toBe(false);
|
|
70
73
|
});
|
|
@@ -138,7 +141,7 @@ describe('Scaffolder', () => {
|
|
|
138
141
|
|
|
139
142
|
// v5.0 runtime factory pattern
|
|
140
143
|
expect(entry).toContain('createAgentRuntime');
|
|
141
|
-
expect(entry).toContain('
|
|
144
|
+
expect(entry).toContain('createSemanticFacades');
|
|
142
145
|
expect(entry).toContain('createDomainFacades');
|
|
143
146
|
expect(entry).toContain("from '@soleri/core'");
|
|
144
147
|
expect(entry).toContain("agentId: 'atlas'");
|
|
@@ -221,7 +224,7 @@ describe('Scaffolder', () => {
|
|
|
221
224
|
|
|
222
225
|
// Should use runtime factories from @soleri/core
|
|
223
226
|
expect(facadesTest).toContain('createAgentRuntime');
|
|
224
|
-
expect(facadesTest).toContain('
|
|
227
|
+
expect(facadesTest).toContain('createSemanticFacades');
|
|
225
228
|
expect(facadesTest).toContain('createDomainFacade');
|
|
226
229
|
expect(facadesTest).toContain("from '@soleri/core'");
|
|
227
230
|
|
package/src/lib.ts
CHANGED
package/src/scaffolder.ts
CHANGED
|
@@ -23,6 +23,7 @@ import { generateActivate } from './templates/activate.js';
|
|
|
23
23
|
import { generateReadme } from './templates/readme.js';
|
|
24
24
|
import { generateSetupScript } from './templates/setup-script.js';
|
|
25
25
|
import { generateSkills } from './templates/skills.js';
|
|
26
|
+
import { generateExtensionsIndex, generateExampleOp } from './templates/extensions.js';
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
29
|
* Preview what scaffold will create without writing anything.
|
|
@@ -42,7 +43,7 @@ export function previewScaffold(config: AgentConfig): ScaffoldPreview {
|
|
|
42
43
|
{
|
|
43
44
|
path: 'src/index.ts',
|
|
44
45
|
description:
|
|
45
|
-
'Entry point — thin shell using createAgentRuntime() +
|
|
46
|
+
'Entry point — thin shell using createAgentRuntime() + createSemanticFacades() from @soleri/core',
|
|
46
47
|
},
|
|
47
48
|
...config.domains.map((d) => ({
|
|
48
49
|
path: `src/intelligence/data/${d}.json`,
|
|
@@ -68,6 +69,10 @@ export function previewScaffold(config: AgentConfig): ScaffoldPreview {
|
|
|
68
69
|
path: 'src/__tests__/facades.test.ts',
|
|
69
70
|
description: `Facade integration tests — all ${config.domains.length + 1} facades`,
|
|
70
71
|
},
|
|
72
|
+
{
|
|
73
|
+
path: 'src/extensions/',
|
|
74
|
+
description: 'User extension directory — custom ops, facades, middleware, hooks',
|
|
75
|
+
},
|
|
71
76
|
{ path: '.mcp.json', description: 'MCP client config for connecting to this agent' },
|
|
72
77
|
{
|
|
73
78
|
path: 'README.md',
|
|
@@ -79,8 +84,9 @@ export function previewScaffold(config: AgentConfig): ScaffoldPreview {
|
|
|
79
84
|
},
|
|
80
85
|
{
|
|
81
86
|
path: 'skills/',
|
|
82
|
-
description:
|
|
83
|
-
|
|
87
|
+
description: config.skills?.length
|
|
88
|
+
? `${config.skills.length} selected skills`
|
|
89
|
+
: '17 built-in skills — TDD, debugging, planning, vault, brain, code patrol, retrospective, onboarding',
|
|
84
90
|
},
|
|
85
91
|
];
|
|
86
92
|
|
|
@@ -96,257 +102,90 @@ export function previewScaffold(config: AgentConfig): ScaffoldPreview {
|
|
|
96
102
|
name: `${config.id}_${d.replace(/-/g, '_')}`,
|
|
97
103
|
ops: ['get_patterns', 'search', 'get_entry', 'capture', 'remove'],
|
|
98
104
|
})),
|
|
105
|
+
// 10 semantic facades from createSemanticFacades()
|
|
99
106
|
{
|
|
100
|
-
name: `${config.id}
|
|
107
|
+
name: `${config.id}_vault`,
|
|
101
108
|
ops: [
|
|
102
|
-
// From createCoreOps() — 150 generic ops
|
|
103
109
|
'search',
|
|
104
110
|
'vault_stats',
|
|
105
111
|
'list_all',
|
|
106
|
-
'register',
|
|
107
|
-
'memory_search',
|
|
108
|
-
'memory_capture',
|
|
109
|
-
'memory_list',
|
|
110
|
-
'session_capture',
|
|
111
112
|
'export',
|
|
113
|
+
'capture_enriched',
|
|
114
|
+
'...vault-extra',
|
|
115
|
+
'...capture',
|
|
116
|
+
'...intake',
|
|
117
|
+
],
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
name: `${config.id}_plan`,
|
|
121
|
+
ops: [
|
|
112
122
|
'create_plan',
|
|
113
123
|
'get_plan',
|
|
114
124
|
'approve_plan',
|
|
115
125
|
'update_task',
|
|
116
126
|
'complete_plan',
|
|
127
|
+
'...planning-extra',
|
|
128
|
+
'...grading',
|
|
129
|
+
],
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
name: `${config.id}_brain`,
|
|
133
|
+
ops: [
|
|
117
134
|
'record_feedback',
|
|
118
135
|
'brain_feedback',
|
|
119
|
-
'brain_feedback_stats',
|
|
120
|
-
'rebuild_vocabulary',
|
|
121
136
|
'brain_stats',
|
|
122
137
|
'llm_status',
|
|
123
|
-
'brain_session_context',
|
|
124
138
|
'brain_strengths',
|
|
125
|
-
'
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
'
|
|
132
|
-
'
|
|
133
|
-
'
|
|
134
|
-
'
|
|
135
|
-
|
|
136
|
-
'
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
'cognee_config',
|
|
143
|
-
// LLM ops — 2
|
|
139
|
+
'...19 brain ops',
|
|
140
|
+
],
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
name: `${config.id}_memory`,
|
|
144
|
+
ops: [
|
|
145
|
+
'memory_search',
|
|
146
|
+
'memory_capture',
|
|
147
|
+
'memory_list',
|
|
148
|
+
'session_capture',
|
|
149
|
+
'...memory-extra',
|
|
150
|
+
'...cross-project',
|
|
151
|
+
],
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
name: `${config.id}_admin`,
|
|
155
|
+
ops: [
|
|
144
156
|
'llm_rotate',
|
|
145
157
|
'llm_call',
|
|
146
|
-
// Prompt ops — 2
|
|
147
158
|
'render_prompt',
|
|
148
159
|
'list_templates',
|
|
149
|
-
'
|
|
150
|
-
'
|
|
151
|
-
'curator_contradictions',
|
|
152
|
-
'curator_resolve_contradiction',
|
|
153
|
-
'curator_groom',
|
|
154
|
-
'curator_groom_all',
|
|
155
|
-
'curator_consolidate',
|
|
156
|
-
'curator_health_audit',
|
|
157
|
-
'get_identity',
|
|
158
|
-
'update_identity',
|
|
159
|
-
'add_guideline',
|
|
160
|
-
'remove_guideline',
|
|
161
|
-
'rollback_identity',
|
|
162
|
-
'route_intent',
|
|
163
|
-
'morph',
|
|
164
|
-
'get_behavior_rules',
|
|
165
|
-
// Governance ops — 5
|
|
166
|
-
'governance_policy',
|
|
167
|
-
'governance_proposals',
|
|
168
|
-
'governance_stats',
|
|
169
|
-
'governance_expire',
|
|
170
|
-
'governance_dashboard',
|
|
171
|
-
// Planning Extra ops — 22
|
|
172
|
-
'plan_iterate',
|
|
173
|
-
'plan_split',
|
|
174
|
-
'plan_reconcile',
|
|
175
|
-
'plan_complete_lifecycle',
|
|
176
|
-
'plan_dispatch',
|
|
177
|
-
'plan_review',
|
|
178
|
-
'plan_archive',
|
|
179
|
-
'plan_list_tasks',
|
|
180
|
-
'plan_stats',
|
|
181
|
-
// Planning evidence (#148)
|
|
182
|
-
'plan_submit_evidence',
|
|
183
|
-
'plan_verify_task',
|
|
184
|
-
'plan_verify_plan',
|
|
185
|
-
// Subagent dispatch (#149)
|
|
186
|
-
'plan_review_spec',
|
|
187
|
-
'plan_review_quality',
|
|
188
|
-
'plan_review_outcome',
|
|
189
|
-
// Brainstorm (#150)
|
|
190
|
-
'plan_brainstorm',
|
|
191
|
-
// Auto-reconcile (#151)
|
|
192
|
-
'plan_auto_reconcile',
|
|
193
|
-
// Validate plan (#152)
|
|
194
|
-
'plan_validate',
|
|
195
|
-
// Execution metrics + deliverables (#80, #83)
|
|
196
|
-
'plan_execution_metrics',
|
|
197
|
-
'plan_record_task_metrics',
|
|
198
|
-
'plan_submit_deliverable',
|
|
199
|
-
'plan_verify_deliverables',
|
|
200
|
-
// Memory Extra ops — 8
|
|
201
|
-
'memory_delete',
|
|
202
|
-
'memory_stats',
|
|
203
|
-
'memory_export',
|
|
204
|
-
'memory_import',
|
|
205
|
-
'memory_prune',
|
|
206
|
-
'memory_deduplicate',
|
|
207
|
-
'memory_topics',
|
|
208
|
-
'memory_by_project',
|
|
209
|
-
// Vault Extra ops — 12
|
|
210
|
-
'vault_get',
|
|
211
|
-
'vault_update',
|
|
212
|
-
'vault_remove',
|
|
213
|
-
'vault_bulk_add',
|
|
214
|
-
'vault_bulk_remove',
|
|
215
|
-
'vault_tags',
|
|
216
|
-
'vault_domains',
|
|
217
|
-
'vault_recent',
|
|
218
|
-
'vault_import',
|
|
219
|
-
'vault_seed',
|
|
220
|
-
'vault_backup',
|
|
221
|
-
'vault_age_report',
|
|
222
|
-
// Vault extra — seed canonical + knowledge lifecycle (5)
|
|
223
|
-
'vault_seed_canonical',
|
|
224
|
-
'knowledge_audit',
|
|
225
|
-
'knowledge_health',
|
|
226
|
-
'knowledge_merge',
|
|
227
|
-
'knowledge_reorganize',
|
|
228
|
-
// Bi-temporal vault ops (#89) — 3
|
|
229
|
-
'vault_set_temporal',
|
|
230
|
-
'vault_find_expiring',
|
|
231
|
-
'vault_find_expired',
|
|
232
|
-
// Admin ops — 8
|
|
233
|
-
'admin_health',
|
|
234
|
-
'admin_tool_list',
|
|
235
|
-
'admin_config',
|
|
236
|
-
'admin_vault_size',
|
|
237
|
-
'admin_uptime',
|
|
238
|
-
'admin_version',
|
|
239
|
-
'admin_reset_cache',
|
|
240
|
-
'admin_diagnostic',
|
|
241
|
-
// Loop ops — 9
|
|
242
|
-
'loop_start',
|
|
243
|
-
'loop_iterate',
|
|
244
|
-
'loop_iterate_gate',
|
|
245
|
-
'loop_status',
|
|
246
|
-
'loop_cancel',
|
|
247
|
-
'loop_history',
|
|
248
|
-
'loop_is_active',
|
|
249
|
-
'loop_complete',
|
|
250
|
-
'loop_anomaly_check',
|
|
251
|
-
// Orchestrate ops — 5
|
|
252
|
-
'orchestrate_plan',
|
|
253
|
-
'orchestrate_execute',
|
|
254
|
-
'orchestrate_complete',
|
|
255
|
-
'orchestrate_status',
|
|
256
|
-
'orchestrate_quick_capture',
|
|
257
|
-
// Grading ops — 5
|
|
258
|
-
'plan_grade',
|
|
259
|
-
'plan_check_history',
|
|
260
|
-
'plan_latest_check',
|
|
261
|
-
'plan_meets_grade',
|
|
262
|
-
'plan_auto_improve',
|
|
263
|
-
// Capture ops — 4
|
|
264
|
-
'capture_knowledge',
|
|
265
|
-
'capture_quick',
|
|
266
|
-
'search_intelligent',
|
|
267
|
-
'search_feedback',
|
|
268
|
-
// Enriched capture (#154) — 1
|
|
269
|
-
'capture_enriched',
|
|
270
|
-
// Cognee graph (#156) — 3
|
|
271
|
-
'cognee_get_node',
|
|
272
|
-
'cognee_graph_stats',
|
|
273
|
-
'cognee_export_status',
|
|
274
|
-
// Cognee Sync ops — 3
|
|
275
|
-
'cognee_sync_status',
|
|
276
|
-
'cognee_sync_drain',
|
|
277
|
-
'cognee_sync_reconcile',
|
|
278
|
-
// Intake ops — 4
|
|
279
|
-
'intake_ingest_book',
|
|
280
|
-
'intake_process',
|
|
281
|
-
'intake_status',
|
|
282
|
-
'intake_preview',
|
|
283
|
-
// Admin Extra ops — 23
|
|
284
|
-
'admin_telemetry',
|
|
285
|
-
'admin_telemetry_recent',
|
|
286
|
-
'admin_telemetry_reset',
|
|
287
|
-
'admin_permissions',
|
|
288
|
-
'admin_vault_analytics',
|
|
289
|
-
'admin_search_insights',
|
|
290
|
-
'admin_module_status',
|
|
291
|
-
'admin_env',
|
|
292
|
-
'admin_gc',
|
|
293
|
-
'admin_export_config',
|
|
294
|
-
// Admin key pool (#157)
|
|
295
|
-
'admin_key_pool_status',
|
|
296
|
-
'admin_create_token',
|
|
297
|
-
'admin_revoke_token',
|
|
298
|
-
'admin_list_tokens',
|
|
299
|
-
// Admin accounts (#158)
|
|
300
|
-
'admin_add_account',
|
|
301
|
-
'admin_remove_account',
|
|
302
|
-
'admin_rotate_account',
|
|
303
|
-
'admin_list_accounts',
|
|
304
|
-
'admin_account_status',
|
|
305
|
-
// Admin plugins (#159)
|
|
306
|
-
'admin_list_plugins',
|
|
307
|
-
'admin_plugin_status',
|
|
308
|
-
// Admin instruction validation (#160)
|
|
309
|
-
'admin_validate_instructions',
|
|
310
|
-
// Hot reload (#63)
|
|
311
|
-
'admin_hot_reload',
|
|
312
|
-
// Curator Extra ops — 5
|
|
313
|
-
'curator_entry_history',
|
|
314
|
-
'curator_record_snapshot',
|
|
315
|
-
'curator_queue_stats',
|
|
316
|
-
'curator_enrich',
|
|
317
|
-
// Hybrid contradiction detection (#36) — 1
|
|
318
|
-
'curator_hybrid_contradictions',
|
|
319
|
-
// Project ops — 12
|
|
320
|
-
'project_get',
|
|
321
|
-
'project_list',
|
|
322
|
-
'project_unregister',
|
|
323
|
-
'project_get_rules',
|
|
324
|
-
'project_list_rules',
|
|
325
|
-
'project_add_rule',
|
|
326
|
-
'project_remove_rule',
|
|
327
|
-
'project_link',
|
|
328
|
-
'project_unlink',
|
|
329
|
-
'project_get_links',
|
|
330
|
-
'project_linked_projects',
|
|
331
|
-
'project_touch',
|
|
332
|
-
// Cross-project memory ops — 3
|
|
333
|
-
'memory_promote_to_global',
|
|
334
|
-
'memory_configure',
|
|
335
|
-
'memory_cross_project_search',
|
|
336
|
-
// Playbook ops — 5
|
|
337
|
-
'playbook_list',
|
|
338
|
-
'playbook_get',
|
|
339
|
-
'playbook_create',
|
|
340
|
-
'playbook_match',
|
|
341
|
-
'playbook_seed',
|
|
342
|
-
// Agent-specific ops — 5
|
|
343
|
-
'health',
|
|
344
|
-
'identity',
|
|
345
|
-
'activate',
|
|
346
|
-
'inject_claude_md',
|
|
347
|
-
'setup',
|
|
160
|
+
'...admin',
|
|
161
|
+
'...admin-extra',
|
|
348
162
|
],
|
|
349
163
|
},
|
|
164
|
+
{
|
|
165
|
+
name: `${config.id}_curator`,
|
|
166
|
+
ops: ['curator_status', 'curator_health_audit', '...8 curator ops', '...curator-extra'],
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
name: `${config.id}_loop`,
|
|
170
|
+
ops: ['loop_start', 'loop_iterate', 'loop_cancel', '...loop ops'],
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
name: `${config.id}_orchestrate`,
|
|
174
|
+
ops: ['register', '...orchestrate', '...project', '...playbook'],
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
name: `${config.id}_control`,
|
|
178
|
+
ops: ['get_identity', 'route_intent', 'governance_policy', '...control+governance ops'],
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
name: `${config.id}_cognee`,
|
|
182
|
+
ops: ['cognee_status', 'cognee_search', '...cognee ops', '...cognee-sync'],
|
|
183
|
+
},
|
|
184
|
+
// Agent-specific facade
|
|
185
|
+
{
|
|
186
|
+
name: `${config.id}_core`,
|
|
187
|
+
ops: ['health', 'identity', 'activate', 'inject_claude_md', 'setup'],
|
|
188
|
+
},
|
|
350
189
|
];
|
|
351
190
|
|
|
352
191
|
return {
|
|
@@ -393,6 +232,10 @@ export function scaffold(config: AgentConfig): ScaffoldResult {
|
|
|
393
232
|
'src/identity',
|
|
394
233
|
'src/activation',
|
|
395
234
|
'src/__tests__',
|
|
235
|
+
'src/extensions',
|
|
236
|
+
'src/extensions/ops',
|
|
237
|
+
'src/extensions/facades',
|
|
238
|
+
'src/extensions/middleware',
|
|
396
239
|
];
|
|
397
240
|
|
|
398
241
|
if (config.hookPacks?.length) {
|
|
@@ -438,6 +281,8 @@ export function scaffold(config: AgentConfig): ScaffoldResult {
|
|
|
438
281
|
['src/activation/activate.ts', generateActivate(config)],
|
|
439
282
|
['src/index.ts', generateEntryPoint(config)],
|
|
440
283
|
['src/__tests__/facades.test.ts', generateFacadesTest(config)],
|
|
284
|
+
['src/extensions/index.ts', generateExtensionsIndex(config)],
|
|
285
|
+
['src/extensions/ops/example.ts', generateExampleOp(config)],
|
|
441
286
|
];
|
|
442
287
|
|
|
443
288
|
// Empty intelligence data bundles (domain facades come from @soleri/core at runtime)
|
|
@@ -459,7 +304,7 @@ export function scaffold(config: AgentConfig): ScaffoldResult {
|
|
|
459
304
|
filesCreated.push(path);
|
|
460
305
|
}
|
|
461
306
|
|
|
462
|
-
const totalOps = config.domains.length * 5 +
|
|
307
|
+
const totalOps = config.domains.length * 5 + 214; // 5 per domain + 209 semantic + 5 agent-specific
|
|
463
308
|
|
|
464
309
|
// Auto-build: install dependencies and compile before registering MCP
|
|
465
310
|
let buildSuccess = false;
|
|
@@ -494,7 +339,7 @@ export function scaffold(config: AgentConfig): ScaffoldResult {
|
|
|
494
339
|
|
|
495
340
|
const summaryLines = [
|
|
496
341
|
`Created ${config.name} agent at ${agentDir}`,
|
|
497
|
-
`${config.domains.length +
|
|
342
|
+
`${config.domains.length + 11} facades with ${totalOps} operations`,
|
|
498
343
|
`${config.domains.length} empty knowledge domains ready for capture`,
|
|
499
344
|
`Intelligence layer (Brain) — TF-IDF scoring, auto-tagging, duplicate detection`,
|
|
500
345
|
`Activation system included — say "Hello, ${config.name}!" to activate`,
|
|
@@ -3,7 +3,7 @@ import type { AgentConfig } from '../types.js';
|
|
|
3
3
|
/**
|
|
4
4
|
* Generate the main index.ts entry point for the agent.
|
|
5
5
|
*
|
|
6
|
-
* v5.0: Thin shell — delegates to createAgentRuntime(),
|
|
6
|
+
* v5.0: Thin shell — delegates to createAgentRuntime(), createSemanticFacades(),
|
|
7
7
|
* and createDomainFacades() from @soleri/core. Only agent-specific code
|
|
8
8
|
* (persona, activation) lives here.
|
|
9
9
|
*/
|
|
@@ -19,12 +19,13 @@ import { fileURLToPath } from 'node:url';
|
|
|
19
19
|
|
|
20
20
|
import {
|
|
21
21
|
createAgentRuntime,
|
|
22
|
-
|
|
22
|
+
createSemanticFacades,
|
|
23
23
|
createDomainFacades,
|
|
24
24
|
registerAllFacades,
|
|
25
25
|
seedDefaultPlaybooks,
|
|
26
|
+
wrapWithMiddleware,
|
|
26
27
|
} from '@soleri/core';
|
|
27
|
-
import type { OpDefinition } from '@soleri/core';
|
|
28
|
+
import type { OpDefinition, AgentExtensions } from '@soleri/core';
|
|
28
29
|
import { z } from 'zod';
|
|
29
30
|
import { PERSONA, getPersonaPrompt } from './identity/persona.js';
|
|
30
31
|
import { activateAgent, deactivateAgent } from './activation/activate.js';
|
|
@@ -201,15 +202,51 @@ async function main(): Promise<void> {
|
|
|
201
202
|
];
|
|
202
203
|
|
|
203
204
|
// ─── Assemble facades ──────────────────────────────────────────
|
|
204
|
-
const
|
|
205
|
-
const
|
|
205
|
+
const semanticFacades = createSemanticFacades(runtime, '${config.id}');
|
|
206
|
+
const agentFacade = {
|
|
206
207
|
name: '${config.id}_core',
|
|
207
|
-
description: '
|
|
208
|
-
ops:
|
|
208
|
+
description: 'Agent-specific operations — health, identity, activation, CLAUDE.md injection, setup.',
|
|
209
|
+
ops: agentOps,
|
|
209
210
|
};
|
|
210
211
|
|
|
211
212
|
const domainFacades = createDomainFacades(runtime, '${config.id}', ${domainsLiteral});
|
|
212
213
|
|
|
214
|
+
// ─── User extensions (auto-discovered from src/extensions/) ────
|
|
215
|
+
let extensions: AgentExtensions = {};
|
|
216
|
+
try {
|
|
217
|
+
const ext = await import('./extensions/index.js');
|
|
218
|
+
const loader = ext.default ?? (ext as Record<string, unknown>).loadExtensions;
|
|
219
|
+
if (typeof loader === 'function') {
|
|
220
|
+
extensions = loader(runtime);
|
|
221
|
+
} else if (typeof loader === 'object') {
|
|
222
|
+
extensions = loader;
|
|
223
|
+
}
|
|
224
|
+
if (extensions.ops?.length || extensions.facades?.length || extensions.middleware?.length) {
|
|
225
|
+
console.error(\`[\${tag}] Extensions loaded: \${extensions.ops?.length ?? 0} ops, \${extensions.facades?.length ?? 0} facades, \${extensions.middleware?.length ?? 0} middleware\`);
|
|
226
|
+
}
|
|
227
|
+
} catch {
|
|
228
|
+
// No extensions directory or load error — run vanilla
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Merge user ops into agent facade
|
|
232
|
+
if (extensions.ops?.length) {
|
|
233
|
+
agentFacade.ops.push(...extensions.ops);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Collect user facades
|
|
237
|
+
const userFacades = extensions.facades ?? [];
|
|
238
|
+
|
|
239
|
+
// Apply middleware to all facades
|
|
240
|
+
const allFacades = [...semanticFacades, agentFacade, ...domainFacades, ...userFacades];
|
|
241
|
+
if (extensions.middleware?.length) {
|
|
242
|
+
wrapWithMiddleware(allFacades, extensions.middleware);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Lifecycle: onStartup
|
|
246
|
+
if (extensions.hooks?.onStartup) {
|
|
247
|
+
await extensions.hooks.onStartup(runtime);
|
|
248
|
+
}
|
|
249
|
+
|
|
213
250
|
// ─── MCP server ────────────────────────────────────────────────
|
|
214
251
|
const server = new McpServer({
|
|
215
252
|
name: '${config.id}-mcp',
|
|
@@ -220,11 +257,10 @@ async function main(): Promise<void> {
|
|
|
220
257
|
messages: [{ role: 'assistant' as const, content: { type: 'text' as const, text: getPersonaPrompt() } }],
|
|
221
258
|
}));
|
|
222
259
|
|
|
223
|
-
|
|
224
|
-
registerAllFacades(server, facades);
|
|
260
|
+
registerAllFacades(server, allFacades);
|
|
225
261
|
|
|
226
262
|
console.error(\`[\${tag}] \${PERSONA.name} — \${PERSONA.role}\`);
|
|
227
|
-
console.error(\`[\${tag}] Registered \${
|
|
263
|
+
console.error(\`[\${tag}] Registered \${allFacades.length} facades with \${allFacades.reduce((sum, f) => sum + f.ops.length, 0)} operations\`);
|
|
228
264
|
|
|
229
265
|
// ─── Transport + shutdown ──────────────────────────────────────
|
|
230
266
|
const transport = new StdioServerTransport();
|
|
@@ -234,6 +270,13 @@ async function main(): Promise<void> {
|
|
|
234
270
|
|
|
235
271
|
const shutdown = async (): Promise<void> => {
|
|
236
272
|
console.error(\`[\${tag}] Shutting down...\`);
|
|
273
|
+
if (extensions.hooks?.onShutdown) {
|
|
274
|
+
try {
|
|
275
|
+
await extensions.hooks.onShutdown(runtime);
|
|
276
|
+
} catch (err) {
|
|
277
|
+
console.error(\`[\${tag}] Extension shutdown error:\`, err);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
237
280
|
runtime.close();
|
|
238
281
|
process.exit(0);
|
|
239
282
|
};
|