@soleri/forge 5.14.10 → 7.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.
Files changed (65) hide show
  1. package/dist/agent-schema.d.ts +323 -0
  2. package/dist/agent-schema.js +151 -0
  3. package/dist/agent-schema.js.map +1 -0
  4. package/dist/compose-claude-md.d.ts +24 -0
  5. package/dist/compose-claude-md.js +197 -0
  6. package/dist/compose-claude-md.js.map +1 -0
  7. package/dist/index.js +0 -0
  8. package/dist/lib.d.ts +12 -1
  9. package/dist/lib.js +10 -1
  10. package/dist/lib.js.map +1 -1
  11. package/dist/scaffold-filetree.d.ts +22 -0
  12. package/dist/scaffold-filetree.js +349 -0
  13. package/dist/scaffold-filetree.js.map +1 -0
  14. package/dist/scaffolder.js +261 -11
  15. package/dist/scaffolder.js.map +1 -1
  16. package/dist/templates/activate.js +39 -1
  17. package/dist/templates/activate.js.map +1 -1
  18. package/dist/templates/agents-md.d.ts +10 -1
  19. package/dist/templates/agents-md.js +76 -16
  20. package/dist/templates/agents-md.js.map +1 -1
  21. package/dist/templates/claude-md-template.js +9 -1
  22. package/dist/templates/claude-md-template.js.map +1 -1
  23. package/dist/templates/entry-point.js +83 -6
  24. package/dist/templates/entry-point.js.map +1 -1
  25. package/dist/templates/inject-claude-md.js +53 -0
  26. package/dist/templates/inject-claude-md.js.map +1 -1
  27. package/dist/templates/package-json.js +4 -1
  28. package/dist/templates/package-json.js.map +1 -1
  29. package/dist/templates/readme.js +4 -3
  30. package/dist/templates/readme.js.map +1 -1
  31. package/dist/templates/setup-script.js +109 -3
  32. package/dist/templates/setup-script.js.map +1 -1
  33. package/dist/templates/shared-rules.js +54 -17
  34. package/dist/templates/shared-rules.js.map +1 -1
  35. package/dist/templates/test-facades.js +151 -6
  36. package/dist/templates/test-facades.js.map +1 -1
  37. package/dist/types.d.ts +75 -10
  38. package/dist/types.js +40 -2
  39. package/dist/types.js.map +1 -1
  40. package/dist/utils/detect-domain-packs.d.ts +25 -0
  41. package/dist/utils/detect-domain-packs.js +104 -0
  42. package/dist/utils/detect-domain-packs.js.map +1 -0
  43. package/package.json +2 -1
  44. package/src/__tests__/detect-domain-packs.test.ts +178 -0
  45. package/src/__tests__/scaffold-filetree.test.ts +243 -0
  46. package/src/__tests__/scaffolder.test.ts +5 -3
  47. package/src/agent-schema.ts +184 -0
  48. package/src/compose-claude-md.ts +252 -0
  49. package/src/lib.ts +14 -1
  50. package/src/scaffold-filetree.ts +409 -0
  51. package/src/scaffolder.ts +299 -15
  52. package/src/templates/activate.ts +39 -0
  53. package/src/templates/agents-md.ts +78 -16
  54. package/src/templates/claude-md-template.ts +12 -1
  55. package/src/templates/entry-point.ts +90 -6
  56. package/src/templates/inject-claude-md.ts +53 -0
  57. package/src/templates/package-json.ts +4 -1
  58. package/src/templates/readme.ts +4 -3
  59. package/src/templates/setup-script.ts +110 -4
  60. package/src/templates/shared-rules.ts +55 -17
  61. package/src/templates/test-facades.ts +156 -6
  62. package/src/types.ts +45 -2
  63. package/src/utils/detect-domain-packs.ts +129 -0
  64. package/tsconfig.json +0 -1
  65. package/vitest.config.ts +1 -2
@@ -4,9 +4,15 @@
4
4
  */
5
5
  export function generateSetupScript(config) {
6
6
  const setupTarget = config.setupTarget ?? 'claude';
7
- const claudeSetup = setupTarget === 'claude' || setupTarget === 'both';
8
- const codexSetup = setupTarget === 'codex' || setupTarget === 'both';
9
- const hostLabel = claudeSetup && codexSetup ? 'Claude Code + Codex' : claudeSetup ? 'Claude Code' : 'Codex';
7
+ const claudeSetup = setupTarget === 'claude' || setupTarget === 'both' || setupTarget === 'all';
8
+ const codexSetup = setupTarget === 'codex' || setupTarget === 'both' || setupTarget === 'all';
9
+ const opencodeSetup = setupTarget === 'opencode' || setupTarget === 'all';
10
+ const hostParts = [
11
+ ...(claudeSetup ? ['Claude Code'] : []),
12
+ ...(codexSetup ? ['Codex'] : []),
13
+ ...(opencodeSetup ? ['OpenCode'] : []),
14
+ ];
15
+ const hostLabel = hostParts.join(' + ');
10
16
  const claudeSection = claudeSetup
11
17
  ? `
12
18
  # Check Claude Code
@@ -188,6 +194,102 @@ if [ -d "$SKILLS_DIR" ]; then
188
194
  done
189
195
  echo "[ok] Codex skills: $skill_installed installed, $skill_skipped already present"
190
196
  fi
197
+ `
198
+ : '';
199
+ const opencodeSection = opencodeSetup
200
+ ? `
201
+ # Check and install OpenCode (Soleri fork with title branding)
202
+ if ! command -v opencode &>/dev/null; then
203
+ echo ""
204
+ INSTALLED=false
205
+ # Try Go install from Soleri fork (supports title branding)
206
+ if command -v go &>/dev/null; then
207
+ echo "Installing OpenCode (Soleri fork) via go install..."
208
+ if go install github.com/adrozdenko/opencode@latest 2>/dev/null; then
209
+ if command -v opencode &>/dev/null; then
210
+ echo "[ok] OpenCode installed from Soleri fork ($(opencode --version 2>/dev/null || echo 'installed'))"
211
+ INSTALLED=true
212
+ fi
213
+ fi
214
+ fi
215
+ # Fallback: upstream npm package (no title branding)
216
+ if [ "$INSTALLED" = false ]; then
217
+ echo "Installing OpenCode via npm (upstream — title branding requires Go)..."
218
+ npm install -g opencode-ai
219
+ if command -v opencode &>/dev/null; then
220
+ echo "[ok] OpenCode installed ($(opencode --version 2>/dev/null || echo 'unknown version'))"
221
+ else
222
+ echo ""
223
+ echo "Warning: Could not install OpenCode automatically."
224
+ echo "Install manually using one of:"
225
+ echo " go install github.com/adrozdenko/opencode@latest (recommended — includes title branding)"
226
+ echo " npm install -g opencode-ai (upstream)"
227
+ echo ""
228
+ fi
229
+ fi
230
+ else
231
+ echo "[ok] OpenCode found ($(opencode --version 2>/dev/null || echo 'installed'))"
232
+ fi
233
+
234
+ # Register MCP server with OpenCode
235
+ echo ""
236
+ echo "Registering ${config.name} with OpenCode..."
237
+ OPENCODE_CONFIG="$HOME/.opencode.json"
238
+ AGENT_DIST="$AGENT_DIR/dist/index.js"
239
+
240
+ OPENCODE_CONFIG="$OPENCODE_CONFIG" AGENT_NAME="$AGENT_NAME" AGENT_DIST="$AGENT_DIST" node <<'NODE'
241
+ const fs = require('node:fs');
242
+ const path = process.env.OPENCODE_CONFIG;
243
+ const agentName = process.env.AGENT_NAME;
244
+ const distPath = process.env.AGENT_DIST;
245
+
246
+ let config = {};
247
+ if (fs.existsSync(path)) {
248
+ try {
249
+ const raw = fs.readFileSync(path, 'utf-8');
250
+ const stripped = raw.replace(/^\\s*\\/\\/.*$/gm, '');
251
+ config = JSON.parse(stripped);
252
+ } catch {
253
+ config = {};
254
+ }
255
+ }
256
+
257
+ if (!config.mcp || typeof config.mcp !== 'object') {
258
+ config.mcp = {};
259
+ }
260
+
261
+ config.mcp[agentName] = {
262
+ type: 'local',
263
+ command: ['node', distPath],
264
+ enabled: true,
265
+ };
266
+
267
+ fs.writeFileSync(path, JSON.stringify(config, null, 2) + '\\n', 'utf-8');
268
+ NODE
269
+ echo "[ok] Registered ${config.name} as MCP server (OpenCode)"
270
+
271
+ # Create launcher script — type "${config.id}" to start OpenCode
272
+ LAUNCHER_PATH="/usr/local/bin/$AGENT_NAME"
273
+ LAUNCHER_CONTENT="#!/usr/bin/env bash
274
+ # Soleri agent launcher — starts OpenCode with $AGENT_NAME MCP agent
275
+ cd \\"$AGENT_DIR\\" || exit 1
276
+ exec opencode \\"\\$@\\""
277
+
278
+ if [ -w "/usr/local/bin" ]; then
279
+ echo "$LAUNCHER_CONTENT" > "$LAUNCHER_PATH"
280
+ chmod +x "$LAUNCHER_PATH"
281
+ echo "[ok] Launcher created: type \\"${config.id}\\" to start OpenCode"
282
+ else
283
+ echo "$LAUNCHER_CONTENT" > "$AGENT_DIR/scripts/$AGENT_NAME"
284
+ chmod +x "$AGENT_DIR/scripts/$AGENT_NAME"
285
+ if command -v sudo &>/dev/null; then
286
+ sudo ln -sf "$AGENT_DIR/scripts/$AGENT_NAME" "$LAUNCHER_PATH" 2>/dev/null && \\
287
+ echo "[ok] Launcher created: type \\"${config.id}\\" to start OpenCode" || \\
288
+ echo "Note: Run 'sudo ln -sf $AGENT_DIR/scripts/$AGENT_NAME $LAUNCHER_PATH' to enable \\"${config.id}\\" command"
289
+ else
290
+ echo "Note: Add $AGENT_DIR/scripts to PATH, or symlink $AGENT_DIR/scripts/$AGENT_NAME to /usr/local/bin/$AGENT_NAME"
291
+ fi
292
+ fi
191
293
  `
192
294
  : '';
193
295
  const nextSteps = [
@@ -199,6 +301,9 @@ fi
199
301
  ? ['echo " - Start a new Claude Code session (or restart if one is open)"']
200
302
  : []),
201
303
  ...(codexSetup ? ['echo " - Start a new Codex session (or restart if one is open)"'] : []),
304
+ ...(opencodeSetup
305
+ ? ['echo " - Start a new OpenCode session (or restart if one is open)"']
306
+ : []),
202
307
  `echo " - Say: \\"Hello, ${config.name}!\\""`,
203
308
  'echo ""',
204
309
  `echo "${config.name} is ready."`,
@@ -239,6 +344,7 @@ fi
239
344
  ${claudeSection}
240
345
  ${hookPackSection}
241
346
  ${codexSection}
347
+ ${opencodeSection}
242
348
  ${nextSteps}
243
349
  `;
244
350
  }
@@ -1 +1 @@
1
- {"version":3,"file":"setup-script.js","sourceRoot":"","sources":["../../src/templates/setup-script.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAmB;IACrD,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,IAAI,QAAQ,CAAC;IACnD,MAAM,WAAW,GAAG,WAAW,KAAK,QAAQ,IAAI,WAAW,KAAK,MAAM,CAAC;IACvE,MAAM,UAAU,GAAG,WAAW,KAAK,OAAO,IAAI,WAAW,KAAK,MAAM,CAAC;IACrE,MAAM,SAAS,GACb,WAAW,IAAI,UAAU,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC;IAE5F,MAAM,aAAa,GAAG,WAAW;QAC/B,CAAC,CAAC;;;;;;;;;;;;;;oBAcc,MAAM,CAAC,IAAI;;wBAEP,MAAM,CAAC,IAAI;;;;;;;;;;;;;;;;;;uFAkBoD,MAAM,CAAC,EAAE;;;;;;;;;;;;;;;;;;qFAkBX,MAAM,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiC7F;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,eAAe,GACnB,WAAW,IAAI,MAAM,CAAC,SAAS,EAAE,MAAM;QACrC,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;CAuBP;QACK,CAAC,CAAC,EAAE,CAAC;IAET,MAAM,YAAY,GAAG,UAAU;QAC7B,CAAC,CAAC;;;oBAGc,MAAM,CAAC,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAkCP,MAAM,CAAC,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BlC;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,SAAS,GAAG;QAChB,SAAS;QACT,+BAA+B;QAC/B,SAAS;QACT,cAAc;QACd,GAAG,CAAC,WAAW;YACb,CAAC,CAAC,CAAC,wEAAwE,CAAC;YAC5E,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,kEAAkE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3F,4BAA4B,MAAM,CAAC,IAAI,OAAO;QAC9C,SAAS;QACT,SAAS,MAAM,CAAC,IAAI,aAAa;KAClC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,OAAO;;;;cAIK,MAAM,CAAC,EAAE;;YAEX,MAAM,CAAC,IAAI,WAAW,SAAS;;;;;;;;;;;;;;;;;;;mBAmBxB,MAAM,CAAC,IAAI;;;;;;;;EAQ5B,aAAa;EACb,eAAe;EACf,YAAY;EACZ,SAAS;CACV,CAAC;AACF,CAAC"}
1
+ {"version":3,"file":"setup-script.js","sourceRoot":"","sources":["../../src/templates/setup-script.ts"],"names":[],"mappings":"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"}
@@ -23,6 +23,38 @@ const ENGINE_RULES_LINES = [
23
23
  '',
24
24
  "Shared behavioral rules for all Soleri agents. The active agent's facade table provides tool names.",
25
25
  '',
26
+ // ─── What is Soleri ─────────────────────────────────────
27
+ '## What is Soleri',
28
+ '<!-- soleri:what-is-soleri -->',
29
+ '',
30
+ 'You are powered by the **Soleri engine** — an intelligence framework that makes AI agents learn, remember, and improve over time. You are not a stateless chatbot. You are a knowledge-driven agent with:',
31
+ '',
32
+ "- **Vault** — your knowledge graph (Zettelkasten). Patterns, anti-patterns, principles you've learned. Grows with every session.",
33
+ '- **Brain** — pattern learning loop. Tracks what works (strengths) and recommends approaches based on past success.',
34
+ '- **Memory** — session history that persists across conversations and projects.',
35
+ '- **Planning** — structured workflow: plan → approve → execute → reconcile → capture knowledge.',
36
+ '- **Packs** — installable capability bundles (knowledge + skills + hooks). Add domains without code changes.',
37
+ '',
38
+ '### The 5-Step Rhythm',
39
+ '',
40
+ 'Every task follows this cycle — each iteration makes the next one better:',
41
+ '',
42
+ '1. **Search** — check vault for existing patterns before deciding anything',
43
+ '2. **Plan** — create a structured plan, get user approval',
44
+ '3. **Work** — execute with vault-informed decisions',
45
+ '4. **Capture** — persist what you learned (patterns, anti-patterns, decisions)',
46
+ '5. **Complete** — reconcile, capture knowledge, feed the brain',
47
+ '',
48
+ '### Growing Your Capabilities',
49
+ '',
50
+ 'You start with core capabilities (vault, brain, planning, memory). To add more:',
51
+ '',
52
+ '- **Install packs**: `soleri pack install <name>` — adds knowledge, skills, and hooks for a domain',
53
+ '- **Capture knowledge**: every pattern you capture makes you smarter for next time',
54
+ '- **Add domains**: `soleri add-domain <name>` — expands your expertise',
55
+ '',
56
+ 'When a user asks "what can you do?" — list your current domains and capabilities from your activation context, not a generic list.',
57
+ '',
26
58
  // ─── Response Integrity ─────────────────────────────────
27
59
  '## Response Integrity',
28
60
  '<!-- soleri:response-integrity -->',
@@ -41,14 +73,17 @@ const ENGINE_RULES_LINES = [
41
73
  '',
42
74
  "If in doubt, don't save. Less memory with high signal beats more memory with noise.",
43
75
  '',
44
- // ─── Vault-First Protocol ────────────────────────────────
45
- '## Vault as Source of Truth',
76
+ // ─── Vault-First Protocol (Zettelkasten) ─────────────────
77
+ '## Vault as Source of Truth (Zettelkasten)',
46
78
  '<!-- soleri:vault-protocol -->',
47
79
  '',
48
- '- **MANDATORY**: Consult the vault BEFORE every decision planning, design, architecture, patterns, problem-solving.',
49
- '- Lookup order: 1) VAULT (`op:search_intelligent`) → 2) MEMORY (`op:memory_search`) → 3) CODEBASE → 4) WEB/TRAINING.',
50
- '- If the vault has a pattern, follow it. If it has an anti-pattern, avoid it.',
51
- '- Persist lessons: call `op:capture_knowledge` don\'t just promise "I will remember this".',
80
+ 'The vault is a **Zettelkasten** a connected knowledge graph. Every knowledge operation follows Zettelkasten principles: atomic entries, typed links, dense connections.',
81
+ '',
82
+ '- **MANDATORY**: Consult the vault BEFORE every decision search + traverse the link graph.',
83
+ '- Lookup order: 1) VAULT search 2) VAULT traverse (follow links 2 hops) → 3) MEMORY → 4) CODEBASE → 5) WEB/TRAINING.',
84
+ "- **Search + Traverse**: Don't just search — traverse from the best result to discover connected knowledge and anti-patterns.",
85
+ '- Check `contradicts` links to know what to avoid. Check `sequences` links for ordering dependencies.',
86
+ '- Persist lessons: capture + link. An unlinked entry is incomplete.',
52
87
  '- Exceptions: runtime errors with stack traces → codebase first; user explicitly asks to search web.',
53
88
  '',
54
89
  // ─── Planning ────────────────────────────────────────────
@@ -152,20 +187,25 @@ const ENGINE_RULES_LINES = [
152
187
  'refactor: simplify data fetching logic',
153
188
  '```',
154
189
  '',
155
- // ─── Knowledge Capture ───────────────────────────────────
190
+ // ─── Knowledge Capture (Zettelkasten) ───────────────────
156
191
  '## Knowledge Capture',
157
192
  '<!-- soleri:knowledge-capture -->',
158
193
  '',
159
- "**MANDATORY**: Persist lessons, don't just promise them.",
194
+ "**MANDATORY**: Persist lessons, don't just promise them. **Always link after capturing.**",
160
195
  '',
161
196
  'When you learn something that should persist:',
162
197
  '1. **DON\'T** just say "I will remember this"',
163
198
  '2. **DO** call `op:capture_knowledge` to persist to vault',
164
- "3. **DO** update relevant files if it's a behavioral change",
199
+ '3. **DO** review `suggestedLinks` in the capture response',
200
+ '4. **DO** create links for relevant suggestions: `op:link_entries`',
201
+ "5. **DO** update relevant files if it's a behavioral change",
202
+ '',
203
+ 'An unlinked entry is an orphan — it adds noise, not knowledge.',
165
204
  '',
166
205
  '| Type | Op | Persists To |',
167
206
  '|------|-----|-------------|',
168
207
  '| Patterns/Anti-patterns | `op:capture_knowledge` | vault |',
208
+ '| Links between entries | `op:link_entries` | vault_links table |',
169
209
  '| Quick capture | `op:capture_quick` | vault |',
170
210
  '| Session summaries | `op:session_capture` | memory |',
171
211
  '',
@@ -259,12 +299,9 @@ const ENGINE_RULES_LINES = [
259
299
  '',
260
300
  '### Session Start Protocol',
261
301
  '',
262
- 'On EVERY new session:',
263
- '1. Register project: `op:register params:{ projectPath: "." }`',
264
- '2. Check activation response for `persistence.status`, `vault.connected`, `project.registered`.',
265
- '3. Check for plans awaiting reconciliation via `op:check_persistence`:',
266
- ' - `executing` → Remind user to call `op:plan_reconcile`.',
267
- ' - `reconciling` → Remind user to call `op:plan_complete_lifecycle`.',
302
+ 'Do NOT call tools automatically on session start — just greet the user in character.',
303
+ 'Call `op:register` only when you need project context for a task (not on every message).',
304
+ 'Call `op:activate` only when checking evolved capabilities or recovering session state.',
268
305
  '',
269
306
  '### Context Compaction',
270
307
  '',
@@ -283,7 +320,7 @@ const ENGINE_RULES_LINES = [
283
320
  '|---------|-------------|',
284
321
  '| `soleri agent status` | Health check — version, packs, vault, update availability |',
285
322
  '| `soleri agent update` | Update engine to latest compatible version (`--check` for dry run) |',
286
- '| `soleri agent refresh` | Regenerate CLAUDE.md from latest forge templates (`--dry-run` to preview) |',
323
+ '| `soleri agent refresh` | Regenerate AGENTS.md/CLAUDE.md from latest forge templates (`--dry-run` to preview) |',
287
324
  '| `soleri agent diff` | Show drift between current templates and latest engine |',
288
325
  '| `soleri doctor` | Full system health and project status check |',
289
326
  '| `soleri dev` | Run agent in development mode (stdio MCP) |',
@@ -324,7 +361,7 @@ const ENGINE_RULES_LINES = [
324
361
  '',
325
362
  '| Command | What it does |',
326
363
  '|---------|-------------|',
327
- '| `soleri install` | Register agent as MCP server (`--target claude\\|codex\\|both`) |',
364
+ '| `soleri install` | Register agent as MCP server (`--target opencode\\|claude\\|codex\\|all`) |',
328
365
  '| `soleri uninstall` | Remove agent MCP server entry |',
329
366
  '| `soleri governance --show` | Show vault governance policy |',
330
367
  '| `soleri governance --preset <name>` | Set policy preset (strict\\|moderate\\|permissive) |',
@@ -1 +1 @@
1
- {"version":3,"file":"shared-rules.js","sourceRoot":"","sources":["../../src/templates/shared-rules.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"shared-rules.js","sourceRoot":"","sources":["../../src/templates/shared-rules.ts"],"names":[],"mappings":"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"}
@@ -6,20 +6,28 @@ export function generateFacadesTest(config) {
6
6
  const domainDescribes = config.domains
7
7
  .map((d) => generateDomainDescribe(config.id, d))
8
8
  .join('\n\n');
9
+ const hasDomainPacks = config.domainPacks && config.domainPacks.length > 0;
10
+ const domainPackDescribes = hasDomainPacks
11
+ ? config.domainPacks.map((ref) => generateDomainPackDescribe(config.id, ref)).join('\n\n')
12
+ : '';
9
13
  return `import { describe, it, expect, beforeEach, afterEach } from 'vitest';
10
14
  import {
11
15
  createAgentRuntime,
12
16
  createSemanticFacades,
13
17
  createDomainFacade,
18
+ createDomainFacades,${hasDomainPacks ? `\n loadDomainPacksFromConfig,` : ''}
14
19
  } from '@soleri/core';
15
20
  import type { AgentRuntime, IntelligenceEntry, OpDefinition, FacadeConfig } from '@soleri/core';
16
21
  import { z } from 'zod';
17
22
  import { mkdirSync, readFileSync, rmSync, writeFileSync, existsSync } from 'node:fs';
18
- import { join } from 'node:path';
23
+ import { dirname, join } from 'node:path';
24
+ import { fileURLToPath } from 'node:url';
19
25
  import { tmpdir } from 'node:os';
20
26
  import { PERSONA } from '../identity/persona.js';
21
27
  import { activateAgent, deactivateAgent } from '../activation/activate.js';
22
- import { injectClaudeMd, injectClaudeMdGlobal, hasAgentMarker } from '../activation/inject-claude-md.js';
28
+ import { injectClaudeMd, injectClaudeMdGlobal, hasAgentMarker, injectAgentsMd, injectAgentsMdGlobal, hasAgentMarkerInAgentsMd } from '../activation/inject-claude-md.js';
29
+
30
+ const __dirname = dirname(fileURLToPath(import.meta.url));
23
31
 
24
32
  function makeEntry(overrides: Partial<IntelligenceEntry> = {}): IntelligenceEntry {
25
33
  return {
@@ -53,7 +61,7 @@ describe('Facades', () => {
53
61
  });
54
62
 
55
63
  ${domainDescribes}
56
-
64
+ ${domainPackDescribes ? `\n${domainPackDescribes}\n` : ''}
57
65
  // ─── Semantic Facades ────────────────────────────────────────
58
66
  describe('semantic facades', () => {
59
67
  function buildSemanticFacades(): FacadeConfig[] {
@@ -100,6 +108,12 @@ ${domainDescribes}
100
108
  expect(opNames).toContain('vault_import');
101
109
  expect(opNames).toContain('capture_knowledge');
102
110
  expect(opNames).toContain('intake_ingest_book');
111
+ // Zettelkasten linking ops
112
+ expect(opNames).toContain('link_entries');
113
+ expect(opNames).toContain('get_links');
114
+ expect(opNames).toContain('traverse');
115
+ expect(opNames).toContain('suggest_links');
116
+ expect(opNames).toContain('get_orphans');
103
117
  });
104
118
 
105
119
  it('search should query across all domains', async () => {
@@ -297,7 +311,7 @@ ${domainDescribes}
297
311
  }),
298
312
  handler: async (params) => {
299
313
  if (params.deactivate) return deactivateAgent();
300
- return activateAgent(runtime.vault, (params.projectPath as string) ?? '.', runtime.planner);
314
+ return activateAgent(runtime, (params.projectPath as string) ?? '.');
301
315
  },
302
316
  },
303
317
  {
@@ -313,6 +327,19 @@ ${domainDescribes}
313
327
  return injectClaudeMd((params.projectPath as string) ?? '.');
314
328
  },
315
329
  },
330
+ {
331
+ name: 'inject_agents_md',
332
+ description: 'Inject AGENTS.md',
333
+ auth: 'write',
334
+ schema: z.object({
335
+ projectPath: z.string().optional().default('.'),
336
+ global: z.boolean().optional(),
337
+ }),
338
+ handler: async (params) => {
339
+ if (params.global) return injectAgentsMdGlobal();
340
+ return injectAgentsMd((params.projectPath as string) ?? '.');
341
+ },
342
+ },
316
343
  {
317
344
  name: 'setup',
318
345
  description: 'Setup status',
@@ -386,6 +413,7 @@ ${domainDescribes}
386
413
  expect(allOps).not.toContain('identity');
387
414
  expect(allOps).not.toContain('activate');
388
415
  expect(allOps).not.toContain('inject_claude_md');
416
+ expect(allOps).not.toContain('inject_agents_md');
389
417
  expect(allOps).not.toContain('setup');
390
418
  });
391
419
 
@@ -409,10 +437,10 @@ ${domainDescribes}
409
437
  const activateOp = facade.ops.find((o) => o.name === 'activate')!;
410
438
  const result = (await activateOp.handler({ projectPath: '/tmp/nonexistent-test' })) as {
411
439
  activated: boolean;
412
- persona: { name: string; role: string };
440
+ origin: { name: string; role: string };
413
441
  };
414
442
  expect(result.activated).toBe(true);
415
- expect(result.persona.name).toBe('${escapeQuotes(config.name)}');
443
+ expect(result.origin.name).toBe('${escapeQuotes(config.name)}');
416
444
  });
417
445
 
418
446
  it('activate with deactivate flag should return deactivation', async () => {
@@ -444,6 +472,27 @@ ${domainDescribes}
444
472
  }
445
473
  });
446
474
 
475
+ it('inject_agents_md should create AGENTS.md in temp dir', async () => {
476
+ const tempDir = join(tmpdir(), 'forge-inject-agents-test-' + Date.now());
477
+ mkdirSync(tempDir, { recursive: true });
478
+ try {
479
+ const facade = buildAgentFacade();
480
+ const injectOp = facade.ops.find((o) => o.name === 'inject_agents_md')!;
481
+ const result = (await injectOp.handler({ projectPath: tempDir })) as {
482
+ injected: boolean;
483
+ path: string;
484
+ action: string;
485
+ };
486
+ expect(result.injected).toBe(true);
487
+ expect(result.action).toBe('created');
488
+ expect(existsSync(result.path)).toBe(true);
489
+ const content = readFileSync(result.path, 'utf-8');
490
+ expect(content).toContain('${config.id}:mode');
491
+ } finally {
492
+ rmSync(tempDir, { recursive: true, force: true });
493
+ }
494
+ });
495
+
447
496
  it('setup should return project and global CLAUDE.md status', async () => {
448
497
  const facade = buildAgentFacade();
449
498
  const setupOp = facade.ops.find((o) => o.name === 'setup')!;
@@ -459,6 +508,73 @@ ${domainDescribes}
459
508
  expect(result.recommendations.length).toBeGreaterThan(0);
460
509
  });
461
510
  });
511
+
512
+ // ─── Capability Registry ───────────────────────────────────
513
+ describe('Capability Registry', () => {
514
+ it('should register and resolve capabilities', () => {
515
+ const { CapabilityRegistry } = require('@soleri/core');
516
+ const registry = new CapabilityRegistry();
517
+
518
+ // Register a test capability
519
+ const handlers = new Map();
520
+ handlers.set('test.hello', async () => ({ success: true, data: {}, produced: ['greeting'] }));
521
+ registry.registerPack(
522
+ 'test-pack',
523
+ [{ id: 'test.hello', description: 'Test', provides: ['greeting'], requires: [] }],
524
+ handlers,
525
+ );
526
+
527
+ expect(registry.has('test.hello')).toBe(true);
528
+ expect(registry.has('test.missing')).toBe(false);
529
+
530
+ const resolved = registry.resolve('test.hello');
531
+ expect(resolved.available).toBe(true);
532
+ });
533
+
534
+ it('should track multiple capabilities from one pack', () => {
535
+ const { CapabilityRegistry } = require('@soleri/core');
536
+ const registry = new CapabilityRegistry();
537
+
538
+ const handlers = new Map();
539
+ handlers.set('test.alpha', async () => ({ success: true, data: {}, produced: ['a'] }));
540
+ handlers.set('test.beta', async () => ({ success: true, data: {}, produced: ['b'] }));
541
+ registry.registerPack(
542
+ 'multi-pack',
543
+ [
544
+ { id: 'test.alpha', description: 'Alpha', provides: ['a'], requires: [] },
545
+ { id: 'test.beta', description: 'Beta', provides: ['b'], requires: [] },
546
+ ],
547
+ handlers,
548
+ );
549
+
550
+ expect(registry.size).toBe(2);
551
+ expect(registry.has('test.alpha')).toBe(true);
552
+ expect(registry.has('test.beta')).toBe(true);
553
+ });
554
+
555
+ it('should report missing capabilities in flow validation', () => {
556
+ const { CapabilityRegistry } = require('@soleri/core');
557
+ const registry = new CapabilityRegistry();
558
+
559
+ const handlers = new Map();
560
+ handlers.set('vault.search', async () => ({ success: true, data: {}, produced: ['results'] }));
561
+ registry.registerPack(
562
+ 'core',
563
+ [{ id: 'vault.search', description: 'Search vault', provides: ['results'], requires: [] }],
564
+ handlers,
565
+ );
566
+
567
+ const flow = {
568
+ steps: [
569
+ { needs: ['vault.search', 'color.validate'] },
570
+ ],
571
+ };
572
+ const validation = registry.validateFlow(flow);
573
+ expect(validation.valid).toBe(false);
574
+ expect(validation.available).toContain('vault.search');
575
+ expect(validation.missing).toContain('color.validate');
576
+ });
577
+ });
462
578
  });
463
579
  `;
464
580
  }
@@ -538,6 +654,35 @@ function generateDomainDescribe(agentId, domain) {
538
654
  });
539
655
  });`;
540
656
  }
657
+ function generateDomainPackDescribe(agentId, ref) {
658
+ return ` describe('domain pack: ${ref.name}', () => {
659
+ it('should load and validate the domain pack', async () => {
660
+ const packs = await loadDomainPacksFromConfig([${JSON.stringify(ref)}]);
661
+ expect(packs.length).toBe(1);
662
+ expect(packs[0].name).toBe('${ref.name}');
663
+ expect(packs[0].ops.length).toBeGreaterThan(0);
664
+ });
665
+
666
+ it('should register pack ops in domain facades', async () => {
667
+ const packs = await loadDomainPacksFromConfig([${JSON.stringify(ref)}]);
668
+ const facades = createDomainFacades(runtime, '${agentId}', ${JSON.stringify([ref.name])}, packs);
669
+ expect(facades.length).toBeGreaterThanOrEqual(1);
670
+ // Pack ops should be present
671
+ const allOps = facades.flatMap(f => f.ops.map(o => o.name));
672
+ expect(allOps.length).toBeGreaterThan(5); // More than standard 5
673
+ });
674
+
675
+ it('pack custom ops should be callable', async () => {
676
+ const packs = await loadDomainPacksFromConfig([${JSON.stringify(ref)}]);
677
+ const facades = createDomainFacades(runtime, '${agentId}', ${JSON.stringify([ref.name])}, packs);
678
+ const facade = facades[0];
679
+ // Test first custom op returns without error
680
+ const firstOp = facade.ops[0];
681
+ const result = await firstOp.handler({});
682
+ expect(result).toBeDefined();
683
+ });
684
+ });`;
685
+ }
541
686
  function escapeQuotes(s) {
542
687
  return s.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
543
688
  }
@@ -1 +1 @@
1
- {"version":3,"file":"test-facades.js","sourceRoot":"","sources":["../../src/templates/test-facades.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"test-facades.js","sourceRoot":"","sources":["../../src/templates/test-facades.ts"],"names":[],"mappings":"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"}