@specverse/engines 5.2.0 → 6.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 (33) hide show
  1. package/assets/prompts/core/standard/default/behavior.prompt.yaml +37 -30
  2. package/assets/prompts/core/standard/v9/behavior.prompt.yaml +37 -30
  3. package/dist/ai/behavior-ai-service.d.ts +35 -28
  4. package/dist/ai/behavior-ai-service.d.ts.map +1 -1
  5. package/dist/ai/behavior-ai-service.js +95 -128
  6. package/dist/ai/behavior-ai-service.js.map +1 -1
  7. package/dist/ai/index.d.ts +26 -26
  8. package/dist/ai/index.d.ts.map +1 -1
  9. package/dist/ai/index.js +40 -29
  10. package/dist/ai/index.js.map +1 -1
  11. package/dist/ai/model-resolver.d.ts +13 -0
  12. package/dist/ai/model-resolver.d.ts.map +1 -0
  13. package/dist/ai/model-resolver.js +87 -0
  14. package/dist/ai/model-resolver.js.map +1 -0
  15. package/dist/ai/providers/claude-cli.d.ts +25 -0
  16. package/dist/ai/providers/claude-cli.d.ts.map +1 -0
  17. package/dist/ai/providers/claude-cli.js +185 -0
  18. package/dist/ai/providers/claude-cli.js.map +1 -0
  19. package/dist/ai/providers/index.d.ts +8 -5
  20. package/dist/ai/providers/index.d.ts.map +1 -1
  21. package/dist/ai/providers/index.js +7 -5
  22. package/dist/ai/providers/index.js.map +1 -1
  23. package/dist/ai/providers/stub.d.ts +15 -0
  24. package/dist/ai/providers/stub.d.ts.map +1 -0
  25. package/dist/ai/providers/stub.js +64 -0
  26. package/dist/ai/providers/stub.js.map +1 -0
  27. package/dist/ai/skill-detection.d.ts +5 -0
  28. package/dist/ai/skill-detection.d.ts.map +1 -0
  29. package/dist/ai/skill-detection.js +27 -0
  30. package/dist/ai/skill-detection.js.map +1 -0
  31. package/dist/libs/instance-factories/tools/templates/mcp/mcp-server-generator.js +2 -2
  32. package/libs/instance-factories/tools/templates/mcp/mcp-server-generator.ts +2 -2
  33. package/package.json +8 -3
@@ -0,0 +1,185 @@
1
+ /**
2
+ * claude-cli provider — wraps the locally-installed `claude` binary as an
3
+ * AI SDK v3 LanguageModel. Preserves the Max-subscription zero-cost path
4
+ * by spawning `claude --print` with the user's authenticated session.
5
+ *
6
+ * Session caching: first call uses `--session-id <uuid>`, subsequent calls
7
+ * `--resume <uuid>` — gives the same 98% token savings the Claude Code
8
+ * session mechanism provides.
9
+ *
10
+ * If the user has run `spv skill install --global`, the SpecVerse skill is
11
+ * auto-loaded by Claude Code into every session started by this provider.
12
+ * See detectInstalledSkill() in ../skill-detection.ts.
13
+ */
14
+ import { spawn, execSync } from 'child_process';
15
+ import { existsSync } from 'fs';
16
+ import { randomUUID } from 'crypto';
17
+ import { join } from 'path';
18
+ /**
19
+ * Find the first working `claude` binary. Tries:
20
+ * 1. Explicit path override if given
21
+ * 2. ~/.claude/local/claude (Claude Code's user install)
22
+ * 3. `claude` on PATH (Homebrew / manual installs)
23
+ * Returns null if none respond to `--version`.
24
+ */
25
+ export function detectClaudePath(override) {
26
+ const home = process.env.HOME || '';
27
+ const candidates = override
28
+ ? [override]
29
+ : [join(home, '.claude', 'local', 'claude'), 'claude'];
30
+ for (const candidate of candidates) {
31
+ // For explicit paths, require existence on disk before exec.
32
+ if (candidate !== 'claude' && !existsSync(candidate))
33
+ continue;
34
+ try {
35
+ execSync(`${candidate} --version`, { stdio: 'ignore', timeout: 5000 });
36
+ return candidate;
37
+ }
38
+ catch {
39
+ /* try next */
40
+ }
41
+ }
42
+ return null;
43
+ }
44
+ /** True if any candidate claude binary responds to --version. */
45
+ export function isClaudeCliAvailable(override) {
46
+ return detectClaudePath(override) !== null;
47
+ }
48
+ /**
49
+ * Extract a flat { system, user } pair from the AI SDK's message array.
50
+ * The claude CLI's --system-prompt / -p flags only accept one string each.
51
+ * For now we concatenate any system messages, and join all user turns with
52
+ * blank lines. (In practice behavior generation is single-turn; this
53
+ * provider isn't targeting multi-turn conversational use.)
54
+ */
55
+ function flattenPrompt(messages) {
56
+ const systemChunks = [];
57
+ const userChunks = [];
58
+ for (const msg of messages) {
59
+ if (msg.role === 'system') {
60
+ systemChunks.push(msg.content);
61
+ }
62
+ else if (msg.role === 'user') {
63
+ for (const part of msg.content) {
64
+ if (part.type === 'text')
65
+ userChunks.push(part.text);
66
+ }
67
+ }
68
+ else if (msg.role === 'assistant') {
69
+ // Prior assistant turns get included into the user prompt as context
70
+ // so the CLI can see them. Unusual for our use case.
71
+ const text = msg.content
72
+ .filter((p) => p.type === 'text')
73
+ .map((p) => p.text)
74
+ .join('');
75
+ if (text)
76
+ userChunks.push(`[Assistant previously said]\n${text}`);
77
+ }
78
+ }
79
+ return {
80
+ system: systemChunks.join('\n\n').trim(),
81
+ user: userChunks.join('\n\n').trim(),
82
+ };
83
+ }
84
+ /**
85
+ * Factory for a claude-cli-backed LanguageModelV3. Session state is held
86
+ * inside the closure, so each call to claudeCli() gets its own session.
87
+ */
88
+ export function claudeCli(options = {}) {
89
+ const claudePath = options.claudePath || detectClaudePath() || 'claude';
90
+ const timeout = options.timeout ?? 120_000;
91
+ const modelId = options.model ?? 'default';
92
+ const sessionId = randomUUID();
93
+ let initialized = false;
94
+ async function spawnClaude(args, stdinPrompt) {
95
+ return new Promise((resolve, reject) => {
96
+ const proc = spawn(claudePath, args, {
97
+ stdio: ['ignore', 'pipe', 'pipe'],
98
+ env: { ...process.env },
99
+ });
100
+ let out = '';
101
+ let err = '';
102
+ const timer = setTimeout(() => {
103
+ proc.kill();
104
+ reject(new Error(`claude-cli timed out after ${timeout}ms`));
105
+ }, timeout);
106
+ proc.stdout?.on('data', (d) => {
107
+ out += d.toString();
108
+ });
109
+ proc.stderr?.on('data', (d) => {
110
+ err += d.toString();
111
+ });
112
+ proc.on('close', (code) => {
113
+ clearTimeout(timer);
114
+ if (code !== 0) {
115
+ reject(new Error(`claude-cli exited ${code}: ${err || out}`));
116
+ return;
117
+ }
118
+ resolve(out);
119
+ });
120
+ proc.on('error', (e) => {
121
+ clearTimeout(timer);
122
+ reject(e);
123
+ });
124
+ });
125
+ }
126
+ const model = {
127
+ specificationVersion: 'v3',
128
+ provider: 'claude-cli',
129
+ modelId,
130
+ supportedUrls: {},
131
+ async doGenerate(opts) {
132
+ const { system, user } = flattenPrompt(opts.prompt);
133
+ const args = ['--print'];
134
+ if (!initialized) {
135
+ args.push('--session-id', sessionId);
136
+ if (system)
137
+ args.push('--system-prompt', system);
138
+ }
139
+ else {
140
+ args.push('--resume', sessionId);
141
+ }
142
+ if (modelId !== 'default')
143
+ args.push('--model', modelId);
144
+ args.push('-p', user);
145
+ const out = await spawnClaude(args, user);
146
+ initialized = true;
147
+ return {
148
+ content: [{ type: 'text', text: out.trim() }],
149
+ finishReason: { unified: 'stop', raw: undefined },
150
+ usage: {
151
+ // The CLI doesn't expose token counts in --print mode.
152
+ inputTokens: { total: undefined, noCache: undefined, cacheRead: undefined, cacheWrite: undefined },
153
+ outputTokens: { total: undefined, text: undefined, reasoning: undefined },
154
+ },
155
+ warnings: [],
156
+ };
157
+ },
158
+ async doStream(opts) {
159
+ // v1 of this provider: no real streaming — buffer the doGenerate result
160
+ // and emit it as a single chunk. Revisit if behavior-service ever wants
161
+ // partial-output UX.
162
+ const result = await model.doGenerate(opts);
163
+ const text = result.content
164
+ .filter((c) => c.type === 'text')
165
+ .map((c) => c.text)
166
+ .join('');
167
+ const parts = [
168
+ { type: 'text-start', id: 'single' },
169
+ { type: 'text-delta', id: 'single', delta: text },
170
+ { type: 'text-end', id: 'single' },
171
+ { type: 'finish', finishReason: { unified: 'stop', raw: undefined }, usage: result.usage },
172
+ ];
173
+ const stream = new ReadableStream({
174
+ start(controller) {
175
+ for (const part of parts)
176
+ controller.enqueue(part);
177
+ controller.close();
178
+ },
179
+ });
180
+ return { stream };
181
+ },
182
+ };
183
+ return model;
184
+ }
185
+ //# sourceMappingURL=claude-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-cli.js","sourceRoot":"","sources":["../../../src/ai/providers/claude-cli.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,9 @@
1
- export * from './llm-provider.js';
2
- export * from './provider-factory.js';
3
- export * from './openai-provider.js';
4
- export * from './anthropic-provider.js';
5
- export * from './interactive-provider.js';
1
+ /**
2
+ * AI providers — custom LanguageModelV3 implementations that plug into the
3
+ * Vercel AI SDK. Most consumers should call `resolveModel()` from the parent
4
+ * module rather than instantiating these directly.
5
+ */
6
+ export { claudeCli, isClaudeCliAvailable, detectClaudePath } from './claude-cli.js';
7
+ export type { ClaudeCliOptions } from './claude-cli.js';
8
+ export { stubModel } from './stub.js';
6
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ai/providers/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ai/providers/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACpF,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC"}
@@ -1,6 +1,8 @@
1
- export * from './llm-provider.js';
2
- export * from './provider-factory.js';
3
- export * from './openai-provider.js';
4
- export * from './anthropic-provider.js';
5
- export * from './interactive-provider.js';
1
+ /**
2
+ * AI providers — custom LanguageModelV3 implementations that plug into the
3
+ * Vercel AI SDK. Most consumers should call `resolveModel()` from the parent
4
+ * module rather than instantiating these directly.
5
+ */
6
+ export { claudeCli, isClaudeCliAvailable, detectClaudePath } from './claude-cli.js';
7
+ export { stubModel } from './stub.js';
6
8
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ai/providers/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ai/providers/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEpF,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * stub provider — an AI SDK v3 LanguageModel that doesn't call any LLM.
3
+ * Emits the user prompt verbatim with a marker comment so the ambient
4
+ * runtime (MCP client, user's editor, etc.) can see what was asked and
5
+ * execute it themselves.
6
+ *
7
+ * Used in two scenarios:
8
+ * 1. Inside an MCP server context (MCP_SERVER=1) — the Claude Desktop /
9
+ * client session IS the LLM; calling a separate API would be wasteful.
10
+ * 2. As the safe default when no provider is configured — gives a clear
11
+ * diagnostic instead of a silent failure or a cryptic auth error.
12
+ */
13
+ import type { LanguageModelV3 } from '@ai-sdk/provider';
14
+ export declare function stubModel(): LanguageModelV3;
15
+ //# sourceMappingURL=stub.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stub.d.ts","sourceRoot":"","sources":["../../../src/ai/providers/stub.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EACV,eAAe,EAMhB,MAAM,kBAAkB,CAAC;AAkB1B,wBAAgB,SAAS,IAAI,eAAe,CAqD3C"}
@@ -0,0 +1,64 @@
1
+ function formatAsText(messages) {
2
+ const sections = [];
3
+ for (const msg of messages) {
4
+ if (msg.role === 'system') {
5
+ sections.push(`--- system ---\n${msg.content}`);
6
+ }
7
+ else if (msg.role === 'user') {
8
+ const text = msg.content
9
+ .filter((p) => p.type === 'text')
10
+ .map((p) => p.text)
11
+ .join('');
12
+ sections.push(`--- user ---\n${text}`);
13
+ }
14
+ }
15
+ return sections.join('\n\n');
16
+ }
17
+ export function stubModel() {
18
+ const model = {
19
+ specificationVersion: 'v3',
20
+ provider: 'specverse-stub',
21
+ modelId: 'stub',
22
+ supportedUrls: {},
23
+ async doGenerate(opts) {
24
+ const text = '// SPECVERSE_AI_PROVIDER=stub — no LLM was called.\n' +
25
+ '// The ambient runtime (MCP client, agent, or user) is expected to\n' +
26
+ '// execute the prompt below. To enable real generation, set\n' +
27
+ '// SPECVERSE_AI_PROVIDER to one of: claude-cli, anthropic, openai-compatible.\n' +
28
+ '\n' +
29
+ formatAsText(opts.prompt);
30
+ return {
31
+ content: [{ type: 'text', text }],
32
+ finishReason: { unified: 'stop', raw: undefined },
33
+ usage: {
34
+ inputTokens: { total: 0, noCache: 0, cacheRead: 0, cacheWrite: 0 },
35
+ outputTokens: { total: 0, text: 0, reasoning: 0 },
36
+ },
37
+ warnings: [],
38
+ };
39
+ },
40
+ async doStream(opts) {
41
+ const result = await model.doGenerate(opts);
42
+ const text = result.content
43
+ .filter((c) => c.type === 'text')
44
+ .map((c) => c.text)
45
+ .join('');
46
+ const parts = [
47
+ { type: 'text-start', id: 'stub' },
48
+ { type: 'text-delta', id: 'stub', delta: text },
49
+ { type: 'text-end', id: 'stub' },
50
+ { type: 'finish', finishReason: { unified: 'stop', raw: undefined }, usage: result.usage },
51
+ ];
52
+ const stream = new ReadableStream({
53
+ start(controller) {
54
+ for (const part of parts)
55
+ controller.enqueue(part);
56
+ controller.close();
57
+ },
58
+ });
59
+ return { stream };
60
+ },
61
+ };
62
+ return model;
63
+ }
64
+ //# sourceMappingURL=stub.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stub.js","sourceRoot":"","sources":["../../../src/ai/providers/stub.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare function detectInstalledSkill(skillName?: string): {
2
+ found: boolean;
3
+ location: string | null;
4
+ };
5
+ //# sourceMappingURL=skill-detection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-detection.d.ts","sourceRoot":"","sources":["../../src/ai/skill-detection.ts"],"names":[],"mappings":"AAgBA,wBAAgB,oBAAoB,CAAC,SAAS,SAAc,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CASzG"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Detect whether the SpecVerse Claude skill is installed in a location
3
+ * that Claude Code will auto-load.
4
+ *
5
+ * Claude Code discovers skills from:
6
+ * - ~/.claude/skills/<name>/ (global — shipped by `spv skill install --global`)
7
+ * - <cwd>/.claude/skills/<name>/ (project-local — `spv skill install --project`)
8
+ *
9
+ * If either is present with a SKILL.md, we assume Claude-CLI-backed behavior
10
+ * generation will benefit from the skill's auto-loaded context — meaning we
11
+ * can send a leaner system prompt (skip the fullContext block).
12
+ */
13
+ import { existsSync } from 'fs';
14
+ import { homedir } from 'os';
15
+ import { join } from 'path';
16
+ export function detectInstalledSkill(skillName = 'specverse') {
17
+ const candidates = [
18
+ join(process.cwd(), '.claude', 'skills', skillName, 'SKILL.md'),
19
+ join(homedir(), '.claude', 'skills', skillName, 'SKILL.md'),
20
+ ];
21
+ for (const path of candidates) {
22
+ if (existsSync(path))
23
+ return { found: true, location: path };
24
+ }
25
+ return { found: false, location: null };
26
+ }
27
+ //# sourceMappingURL=skill-detection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-detection.js","sourceRoot":"","sources":["../../src/ai/skill-detection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,MAAM,UAAU,oBAAoB,CAAC,SAAS,GAAG,WAAW;IAC1D,MAAM,UAAU,GAAG;QACjB,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,CAAC;QAC/D,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,CAAC;KAC5D,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,IAAI,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC/D,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAC1C,CAAC"}
@@ -130,9 +130,9 @@ function generatePackageJson(version, description) {
130
130
  },
131
131
  dependencies: {
132
132
  "@modelcontextprotocol/sdk": "^1.17.4",
133
- "@specverse/engines": "^5.2.0",
133
+ "@specverse/engines": "^6.0.0",
134
134
  "@specverse/entities": "^5.1.0",
135
- "@specverse/self": "^5.2.0",
135
+ "@specverse/self": "^5.3.0",
136
136
  "js-yaml": "^4.1.0"
137
137
  },
138
138
  devDependencies: {
@@ -208,9 +208,9 @@ function generatePackageJson(version: string, description: string): string {
208
208
  },
209
209
  dependencies: {
210
210
  '@modelcontextprotocol/sdk': '^1.17.4',
211
- '@specverse/engines': '^5.2.0',
211
+ '@specverse/engines': '^6.0.0',
212
212
  '@specverse/entities': '^5.1.0',
213
- '@specverse/self': '^5.2.0',
213
+ '@specverse/self': '^5.3.0',
214
214
  'js-yaml': '^4.1.0',
215
215
  },
216
216
  devDependencies: {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@specverse/engines",
3
- "version": "5.2.0",
4
- "description": "SpecVerse toolchain \u2014 parser, inference, realize, generators, AI, registry, bundles",
3
+ "version": "6.0.0",
4
+ "description": "SpecVerse toolchain parser, inference, realize, generators, AI, registry, bundles",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -46,16 +46,21 @@
46
46
  "clean": "rm -rf dist"
47
47
  },
48
48
  "dependencies": {
49
+ "@ai-sdk/anthropic": "^3.0.71",
50
+ "@ai-sdk/openai-compatible": "^2.0.41",
51
+ "@ai-sdk/provider": "^3.0.8",
49
52
  "@specverse/entities": "^5.1.0",
50
53
  "@specverse/runtime": "^5.0.1",
51
54
  "@specverse/types": "^5.1.0",
55
+ "ai": "^6.0.168",
52
56
  "ajv": "^8.17.0",
53
57
  "ajv-formats": "^2.1.0",
54
58
  "glob": "^10.0.0",
55
59
  "handlebars": "^4.7.9",
56
60
  "js-yaml": "^4.1.0",
57
61
  "semver": "^7.0.0",
58
- "yaml": "^2.8.1"
62
+ "yaml": "^2.8.1",
63
+ "zod": "^4.3.6"
59
64
  },
60
65
  "devDependencies": {
61
66
  "@types/node": "^25.5.0",