@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.
- package/assets/prompts/core/standard/default/behavior.prompt.yaml +37 -30
- package/assets/prompts/core/standard/v9/behavior.prompt.yaml +37 -30
- package/dist/ai/behavior-ai-service.d.ts +35 -28
- package/dist/ai/behavior-ai-service.d.ts.map +1 -1
- package/dist/ai/behavior-ai-service.js +95 -128
- package/dist/ai/behavior-ai-service.js.map +1 -1
- package/dist/ai/index.d.ts +26 -26
- package/dist/ai/index.d.ts.map +1 -1
- package/dist/ai/index.js +40 -29
- package/dist/ai/index.js.map +1 -1
- package/dist/ai/model-resolver.d.ts +13 -0
- package/dist/ai/model-resolver.d.ts.map +1 -0
- package/dist/ai/model-resolver.js +87 -0
- package/dist/ai/model-resolver.js.map +1 -0
- package/dist/ai/providers/claude-cli.d.ts +25 -0
- package/dist/ai/providers/claude-cli.d.ts.map +1 -0
- package/dist/ai/providers/claude-cli.js +185 -0
- package/dist/ai/providers/claude-cli.js.map +1 -0
- package/dist/ai/providers/index.d.ts +8 -5
- package/dist/ai/providers/index.d.ts.map +1 -1
- package/dist/ai/providers/index.js +7 -5
- package/dist/ai/providers/index.js.map +1 -1
- package/dist/ai/providers/stub.d.ts +15 -0
- package/dist/ai/providers/stub.d.ts.map +1 -0
- package/dist/ai/providers/stub.js +64 -0
- package/dist/ai/providers/stub.js.map +1 -0
- package/dist/ai/skill-detection.d.ts +5 -0
- package/dist/ai/skill-detection.d.ts.map +1 -0
- package/dist/ai/skill-detection.js +27 -0
- package/dist/ai/skill-detection.js.map +1 -0
- package/dist/libs/instance-factories/tools/templates/mcp/mcp-server-generator.js +2 -2
- package/libs/instance-factories/tools/templates/mcp/mcp-server-generator.ts +2 -2
- 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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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,
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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,
|
|
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 @@
|
|
|
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": "^
|
|
133
|
+
"@specverse/engines": "^6.0.0",
|
|
134
134
|
"@specverse/entities": "^5.1.0",
|
|
135
|
-
"@specverse/self": "^5.
|
|
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': '^
|
|
211
|
+
'@specverse/engines': '^6.0.0',
|
|
212
212
|
'@specverse/entities': '^5.1.0',
|
|
213
|
-
'@specverse/self': '^5.
|
|
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": "
|
|
4
|
-
"description": "SpecVerse toolchain
|
|
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",
|