@moda-ai/cli 1.20.1 → 1.21.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/init/index.d.ts +2 -0
- package/dist/init/index.js +101 -26
- package/dist/init/sdk-catalog.d.ts +10 -0
- package/dist/init/sdk-catalog.js +80 -0
- package/dist/init/sdk-guide.d.ts +5 -34
- package/dist/init/sdk-guide.js +74 -290
- package/dist/init/sdk-integration.d.ts +43 -44
- package/dist/init/sdk-integration.js +796 -133
- package/dist/init/sdk-protocol.d.ts +135 -0
- package/dist/init/sdk-protocol.js +152 -0
- package/dist/init/sdk-verification.d.ts +27 -0
- package/dist/init/sdk-verification.js +123 -0
- package/package.json +1 -1
- package/skills/integration/index.json +2 -2
- package/dist/init/skill-resolver.d.ts +0 -19
- package/dist/init/skill-resolver.js +0 -78
package/dist/init/sdk-guide.js
CHANGED
|
@@ -1,176 +1,75 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync,
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { dirname, join } from 'node:path';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { readBundledIndex } from '../skills-bundled.js';
|
|
4
|
+
import { renderCatalogListing } from './sdk-catalog.js';
|
|
5
5
|
export const SDK_GUIDE_PATH = '.moda/SDK_INTEGRATION.md';
|
|
6
6
|
/**
|
|
7
7
|
* Write the human/agent-readable fallback guide (.moda/SDK_INTEGRATION.md).
|
|
8
|
-
*
|
|
9
|
-
* When a bundled integration skill matches the detected stack, the guide is
|
|
10
|
-
* rendered from that skill's content plus the detection block (one shared
|
|
11
|
-
* renderer with the agent-prompt path). When no skill resolves (no language
|
|
12
|
-
* detected) the slim generic guide is used; when a skill resolved but its
|
|
13
|
-
* content could not be loaded (missing/unreadable bundle) the generic guide is
|
|
14
|
-
* flagged as a degraded fallback and pinned to the detected stack.
|
|
8
|
+
* Used when automatic SDK integration did not complete successfully.
|
|
15
9
|
*/
|
|
16
10
|
export function writeSdkIntegrationGuide(cwd = process.cwd()) {
|
|
17
11
|
const relativePath = SDK_GUIDE_PATH;
|
|
18
12
|
const absolutePath = join(cwd, relativePath);
|
|
19
|
-
const
|
|
20
|
-
const skillId = resolveIntegrationSkillId(context);
|
|
21
|
-
const skillMd = skillId ? readBundledSkillMd(skillId) : null;
|
|
22
|
-
const content = skillId && skillMd
|
|
23
|
-
? renderSkillBasedGuide(skillId, skillMd, context)
|
|
24
|
-
: renderSdkIntegrationGuide(context, skillId ?? undefined);
|
|
13
|
+
const content = renderSdkIntegrationGuideContent();
|
|
25
14
|
mkdirSync(dirname(absolutePath), { recursive: true });
|
|
26
15
|
writeFileSync(absolutePath, content);
|
|
27
16
|
return relativePath;
|
|
28
17
|
}
|
|
29
|
-
|
|
30
|
-
|
|
18
|
+
export function renderSdkIntegrationGuideContent() {
|
|
19
|
+
const index = readBundledIndex();
|
|
20
|
+
const catalogSection = index
|
|
21
|
+
? [
|
|
22
|
+
'## Available integration skills',
|
|
23
|
+
'',
|
|
24
|
+
renderCatalogListing(index),
|
|
25
|
+
'',
|
|
26
|
+
'During `moda init`, Moda materializes these skills into a temporary catalog for your',
|
|
27
|
+
'coding agent. To integrate by hand, read the matching skill inside the installed CLI',
|
|
28
|
+
'package (`.../@moda-ai/cli/skills/integration/<id>/SKILL.md`), re-run `moda init` with',
|
|
29
|
+
'a coding agent CLI installed, or follow https://docs.moda.dev/ingestion.',
|
|
30
|
+
'',
|
|
31
|
+
]
|
|
32
|
+
: [
|
|
33
|
+
'## Available integration skills',
|
|
34
|
+
'',
|
|
35
|
+
'_The bundled skill index is unavailable in this install; use the generic steps below',
|
|
36
|
+
'and https://docs.moda.dev/ingestion for stack-specific guidance._',
|
|
37
|
+
'',
|
|
38
|
+
];
|
|
31
39
|
return [
|
|
32
40
|
'# Moda SDK Integration Guide',
|
|
33
41
|
'',
|
|
34
|
-
|
|
35
|
-
'
|
|
36
|
-
`\`.claude/skills/${skillId}/SKILL.md\`, prefer reading it there (EXAMPLE.md`,
|
|
37
|
-
'beside it shows the finished integration).',
|
|
42
|
+
'Generated by `moda init`. **The SDK integration was not applied automatically.**',
|
|
43
|
+
'This checklist gets you there by hand or with your coding agent.',
|
|
38
44
|
'',
|
|
39
|
-
|
|
45
|
+
...catalogSection,
|
|
46
|
+
'## 1. Install the SDK',
|
|
40
47
|
'',
|
|
41
|
-
'
|
|
48
|
+
'Install the Moda SDK for your stack with **your** package manager. If a catalog skill',
|
|
49
|
+
'above matches your repo, use its exact package name and install command.',
|
|
42
50
|
'',
|
|
43
|
-
|
|
44
|
-
'',
|
|
45
|
-
].join('\n');
|
|
46
|
-
}
|
|
47
|
-
/** The "What Moda Detected" section, shared by prompts and guides. */
|
|
48
|
-
export function renderDetectionBlock(context) {
|
|
49
|
-
const languages = context.languages.length > 0 ? context.languages.join(', ') : 'Not detected yet';
|
|
50
|
-
const packageManagers = context.packageManagers.length > 0 ? context.packageManagers.join(', ') : 'Not detected yet';
|
|
51
|
-
const providers = context.providerHints.length > 0 ? context.providerHints.join(', ') : 'No provider imports detected yet';
|
|
52
|
-
const frameworks = context.frameworkHints.length > 0 ? context.frameworkHints.join(', ') : 'No agent framework detected yet';
|
|
53
|
-
const runtimeNames = context.runtimeSummary.runtimeAgentNames.slice(0, 8);
|
|
54
|
-
return [
|
|
55
|
-
'## What Moda Detected',
|
|
56
|
-
'',
|
|
57
|
-
`- Languages: ${languages}`,
|
|
58
|
-
`- Package managers: ${packageManagers}`,
|
|
59
|
-
...(context.installCommands.length > 0 ? [`- Install command(s): ${context.installCommands.join(' | ')}`] : []),
|
|
60
|
-
`- Model providers: ${providers}`,
|
|
61
|
-
`- Agent frameworks: ${frameworks}`,
|
|
62
|
-
`- Harness graph: ${context.runtimeSummary.runtimeAgents} runtime agent(s), ${context.runtimeSummary.agentFamilies} agent family/families`,
|
|
63
|
-
...(runtimeNames.length > 0 ? [`- Runtime agents: ${runtimeNames.join(', ')}`] : []),
|
|
64
|
-
].join('\n');
|
|
65
|
-
}
|
|
66
|
-
const GUIDE_FRONTMATTER_RE = /^---\r?\n[\s\S]*?\r?\n---\r?\n/;
|
|
67
|
-
/** Drop a SKILL.md's YAML frontmatter so only the prose body is rendered. */
|
|
68
|
-
export function stripSkillFrontmatter(markdown) {
|
|
69
|
-
return markdown.replace(GUIDE_FRONTMATTER_RE, '');
|
|
70
|
-
}
|
|
71
|
-
export function detectSdkGuideContext(cwd) {
|
|
72
|
-
const languages = [];
|
|
73
|
-
const installCommands = [];
|
|
74
|
-
const packageManagers = [];
|
|
75
|
-
const providerHints = new Set();
|
|
76
|
-
const frameworkHints = new Set();
|
|
77
|
-
const packageJsonPath = join(cwd, 'package.json');
|
|
78
|
-
if (existsSync(packageJsonPath)) {
|
|
79
|
-
languages.push('Node.js / TypeScript');
|
|
80
|
-
const packageManager = detectNodePackageManager(cwd);
|
|
81
|
-
packageManagers.push(packageManager);
|
|
82
|
-
installCommands.push(nodeInstallCommand(packageManager));
|
|
83
|
-
const packageJson = readPackageJson(packageJsonPath);
|
|
84
|
-
for (const dependency of packageDependencyNames(packageJson)) {
|
|
85
|
-
addDependencyHint(dependency, providerHints, frameworkHints);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
const pythonFiles = ['pyproject.toml', 'requirements.txt', 'requirements-dev.txt', 'Pipfile', 'setup.py']
|
|
89
|
-
.filter((file) => existsSync(join(cwd, file)));
|
|
90
|
-
if (pythonFiles.length > 0) {
|
|
91
|
-
languages.push('Python');
|
|
92
|
-
const packageManager = detectPythonPackageManager(cwd);
|
|
93
|
-
packageManagers.push(packageManager);
|
|
94
|
-
installCommands.push(pythonInstallCommand(packageManager));
|
|
95
|
-
for (const file of pythonFiles) {
|
|
96
|
-
const text = safeRead(join(cwd, file));
|
|
97
|
-
addPythonHints(text, providerHints, frameworkHints);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
const sourceHints = addSourceHints(cwd, providerHints, frameworkHints);
|
|
101
|
-
if (sourceHints.hasNodeSource && !languages.includes('Node.js / TypeScript')) {
|
|
102
|
-
const packageManager = detectNodePackageManager(cwd);
|
|
103
|
-
languages.push('Node.js / TypeScript');
|
|
104
|
-
packageManagers.push(packageManager);
|
|
105
|
-
installCommands.push(nodeInstallCommand(packageManager));
|
|
106
|
-
}
|
|
107
|
-
if (sourceHints.hasPythonSource && !languages.includes('Python')) {
|
|
108
|
-
const packageManager = detectPythonPackageManager(cwd);
|
|
109
|
-
languages.push('Python');
|
|
110
|
-
packageManagers.push(packageManager);
|
|
111
|
-
installCommands.push(pythonInstallCommand(packageManager));
|
|
112
|
-
}
|
|
113
|
-
const runtimeSummary = readRuntimeSummary(cwd);
|
|
114
|
-
for (const provider of runtimeSummary.providers)
|
|
115
|
-
providerHints.add(provider);
|
|
116
|
-
for (const framework of runtimeSummary.frameworks)
|
|
117
|
-
frameworkHints.add(framework);
|
|
118
|
-
return {
|
|
119
|
-
languages: unique(languages),
|
|
120
|
-
installCommands: unique(installCommands),
|
|
121
|
-
providerHints: unique([...providerHints]),
|
|
122
|
-
frameworkHints: unique([...frameworkHints]),
|
|
123
|
-
packageManagers: unique(packageManagers),
|
|
124
|
-
runtimeSummary,
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* Slim last-resort guide, used when no bundled skill resolves (no language
|
|
129
|
-
* detected) or when a skill resolved but its content could not be loaded (the
|
|
130
|
-
* bundle is missing/unreadable). Detected stacks with readable content get the
|
|
131
|
-
* far richer skill-based guide via renderSkillBasedGuide().
|
|
132
|
-
*
|
|
133
|
-
* When `resolvedSkillId` is set the intro flags the degradation and pins the
|
|
134
|
-
* reader to the detection block instead of claiming no stack was detected —
|
|
135
|
-
* mirrors the degraded fallback in the agent-prompt path so a successful
|
|
136
|
-
* detection never reads as stack-less.
|
|
137
|
-
*/
|
|
138
|
-
export function renderSdkIntegrationGuide(context, resolvedSkillId) {
|
|
139
|
-
const installCommands = context.installCommands.length > 0
|
|
140
|
-
? context.installCommands
|
|
141
|
-
: ['npm install moda-ai', 'pip install moda-ai'];
|
|
142
|
-
const intro = resolvedSkillId
|
|
143
|
-
? [
|
|
144
|
-
`Generated by \`moda init\`. This repo's stack resolved to the bundled integration skill`,
|
|
145
|
-
`\`${resolvedSkillId}\`, but its content could not be loaded (the skill bundle is missing`,
|
|
146
|
-
'or unreadable in this install), so this is the general checklist. Tailor every step to',
|
|
147
|
-
'the stack in "What Moda Detected" below rather than treating this as a repo with no',
|
|
148
|
-
'detected stack.',
|
|
149
|
-
]
|
|
150
|
-
: [
|
|
151
|
-
'Generated by `moda init`. No specific stack was detected, so this is the',
|
|
152
|
-
'general checklist; the full per-framework references live at',
|
|
153
|
-
'https://docs.moda.dev/ingestion.',
|
|
154
|
-
];
|
|
155
|
-
return `${[
|
|
156
|
-
'# Moda SDK Integration Guide',
|
|
51
|
+
'Examples (adapt to your stack):',
|
|
157
52
|
'',
|
|
158
|
-
|
|
53
|
+
'Node.js / TypeScript:',
|
|
159
54
|
'',
|
|
160
|
-
|
|
55
|
+
'```bash',
|
|
56
|
+
'npm install moda-ai # or: bun add / pnpm add / yarn add',
|
|
57
|
+
'```',
|
|
161
58
|
'',
|
|
162
|
-
'
|
|
59
|
+
'Python:',
|
|
163
60
|
'',
|
|
164
|
-
'
|
|
61
|
+
'```bash',
|
|
62
|
+
'pip install moda-ai # or: uv add / poetry add',
|
|
63
|
+
'```',
|
|
165
64
|
'',
|
|
166
|
-
|
|
167
|
-
'
|
|
65
|
+
'Do not paste `MODA_API_KEY` into source or `.env` files. Keep it in your deployment',
|
|
66
|
+
'environment, secret manager, or local shell.',
|
|
168
67
|
'',
|
|
169
|
-
'## 2. Initialize Moda
|
|
68
|
+
'## 2. Initialize Moda before LLM clients',
|
|
170
69
|
'',
|
|
171
70
|
'Initialize before any LLM client is created.',
|
|
172
71
|
'',
|
|
173
|
-
'Node.js / TypeScript:',
|
|
72
|
+
'Node.js / TypeScript (example):',
|
|
174
73
|
'',
|
|
175
74
|
'```ts',
|
|
176
75
|
"import { Moda } from 'moda-ai';",
|
|
@@ -178,7 +77,7 @@ export function renderSdkIntegrationGuide(context, resolvedSkillId) {
|
|
|
178
77
|
'await Moda.init(process.env.MODA_API_KEY!);',
|
|
179
78
|
'```',
|
|
180
79
|
'',
|
|
181
|
-
'Python:',
|
|
80
|
+
'Python (example):',
|
|
182
81
|
'',
|
|
183
82
|
'```python',
|
|
184
83
|
'import os',
|
|
@@ -188,166 +87,45 @@ export function renderSdkIntegrationGuide(context, resolvedSkillId) {
|
|
|
188
87
|
'moda.init(os.environ["MODA_API_KEY"])',
|
|
189
88
|
'```',
|
|
190
89
|
'',
|
|
191
|
-
'## 3. Set
|
|
90
|
+
'## 3. Set conversation and user context',
|
|
192
91
|
'',
|
|
193
|
-
'Set a stable conversation id before each LLM call, and a user id when one user can be
|
|
92
|
+
'Set a stable conversation id before each LLM call, and a user id when one user can be',
|
|
93
|
+
'identified. For concurrent request handlers, use scoped context helpers from the SDK',
|
|
94
|
+
'instead of setting global context across overlapping requests.',
|
|
194
95
|
'',
|
|
195
|
-
'Node.js / TypeScript:',
|
|
96
|
+
'Node.js / TypeScript (example):',
|
|
196
97
|
'',
|
|
197
98
|
'```ts',
|
|
198
99
|
'Moda.conversationId = sessionId;',
|
|
199
100
|
'Moda.userId = userId;',
|
|
200
101
|
'```',
|
|
201
102
|
'',
|
|
202
|
-
'Python:',
|
|
103
|
+
'Python (example):',
|
|
203
104
|
'',
|
|
204
105
|
'```python',
|
|
205
106
|
'moda.conversation_id = session_id',
|
|
206
107
|
'moda.user_id = user_id',
|
|
207
108
|
'```',
|
|
208
109
|
'',
|
|
209
|
-
'## 4. Flush
|
|
110
|
+
'## 4. Flush before exit',
|
|
210
111
|
'',
|
|
211
112
|
'Node.js / TypeScript: `await Moda.flush();` — Python: `moda.flush()`.',
|
|
212
113
|
'',
|
|
213
114
|
'## 5. Validate',
|
|
214
115
|
'',
|
|
116
|
+
'Tenant health (does not prove this integration by itself):',
|
|
117
|
+
'',
|
|
215
118
|
'```bash',
|
|
216
119
|
'moda doctor --online --json',
|
|
217
120
|
'```',
|
|
218
121
|
'',
|
|
219
|
-
'
|
|
122
|
+
'Exact-trace confirmation: send one request through your app with a known conversation id,',
|
|
123
|
+
'then run `moda audit <that-id>` — you should see your llm span(s).',
|
|
220
124
|
'',
|
|
221
|
-
].join('\n')
|
|
222
|
-
}
|
|
223
|
-
function detectNodePackageManager(cwd) {
|
|
224
|
-
if (existsSync(join(cwd, 'bun.lock')) || existsSync(join(cwd, 'bun.lockb')))
|
|
225
|
-
return 'bun';
|
|
226
|
-
if (existsSync(join(cwd, 'pnpm-lock.yaml')))
|
|
227
|
-
return 'pnpm';
|
|
228
|
-
if (existsSync(join(cwd, 'yarn.lock')))
|
|
229
|
-
return 'yarn';
|
|
230
|
-
return 'npm';
|
|
231
|
-
}
|
|
232
|
-
function detectPythonPackageManager(cwd) {
|
|
233
|
-
if (existsSync(join(cwd, 'uv.lock')))
|
|
234
|
-
return 'uv';
|
|
235
|
-
if (existsSync(join(cwd, 'poetry.lock')))
|
|
236
|
-
return 'poetry';
|
|
237
|
-
return 'pip';
|
|
238
|
-
}
|
|
239
|
-
function nodeInstallCommand(packageManager) {
|
|
240
|
-
if (packageManager === 'bun')
|
|
241
|
-
return 'bun add moda-ai';
|
|
242
|
-
if (packageManager === 'pnpm')
|
|
243
|
-
return 'pnpm add moda-ai';
|
|
244
|
-
if (packageManager === 'yarn')
|
|
245
|
-
return 'yarn add moda-ai';
|
|
246
|
-
return 'npm install moda-ai';
|
|
247
|
-
}
|
|
248
|
-
function pythonInstallCommand(packageManager) {
|
|
249
|
-
if (packageManager === 'uv')
|
|
250
|
-
return 'uv add moda-ai';
|
|
251
|
-
if (packageManager === 'poetry')
|
|
252
|
-
return 'poetry add moda-ai';
|
|
253
|
-
return 'pip install moda-ai';
|
|
254
|
-
}
|
|
255
|
-
function readPackageJson(path) {
|
|
256
|
-
try {
|
|
257
|
-
const parsed = JSON.parse(readFileSync(path, 'utf8'));
|
|
258
|
-
return isRecord(parsed) ? parsed : {};
|
|
259
|
-
}
|
|
260
|
-
catch {
|
|
261
|
-
return {};
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
function packageDependencyNames(packageJson) {
|
|
265
|
-
const names = new Set();
|
|
266
|
-
for (const key of ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies']) {
|
|
267
|
-
const deps = packageJson[key];
|
|
268
|
-
if (!isRecord(deps))
|
|
269
|
-
continue;
|
|
270
|
-
for (const name of Object.keys(deps))
|
|
271
|
-
names.add(name);
|
|
272
|
-
}
|
|
273
|
-
return [...names];
|
|
274
|
-
}
|
|
275
|
-
function addDependencyHint(dependency, providers, frameworks) {
|
|
276
|
-
const name = dependency.toLowerCase();
|
|
277
|
-
if (name === 'openai' || name.includes('@ai-sdk/openai'))
|
|
278
|
-
providers.add('OpenAI');
|
|
279
|
-
if (name === '@anthropic-ai/sdk' || name.includes('@ai-sdk/anthropic'))
|
|
280
|
-
providers.add('Anthropic');
|
|
281
|
-
if (name === 'ai' || name.startsWith('@ai-sdk/'))
|
|
282
|
-
frameworks.add('Vercel AI SDK');
|
|
283
|
-
if (name.includes('langchain') || name.includes('langgraph'))
|
|
284
|
-
frameworks.add('LangChain / LangGraph');
|
|
285
|
-
if (name.includes('crewai'))
|
|
286
|
-
frameworks.add('CrewAI');
|
|
287
|
-
if (name.includes('autogen'))
|
|
288
|
-
frameworks.add('AutoGen');
|
|
289
|
-
}
|
|
290
|
-
function addPythonHints(text, providers, frameworks) {
|
|
291
|
-
const lower = text.toLowerCase();
|
|
292
|
-
if (/\bopenai\b/.test(lower))
|
|
293
|
-
providers.add('OpenAI');
|
|
294
|
-
if (/\banthropic\b/.test(lower))
|
|
295
|
-
providers.add('Anthropic');
|
|
296
|
-
if (/\blangchain\b|\blanggraph\b/.test(lower))
|
|
297
|
-
frameworks.add('LangChain / LangGraph');
|
|
298
|
-
if (/claude[-_]agent[-_]sdk/.test(lower))
|
|
299
|
-
frameworks.add('Claude Agent SDK');
|
|
300
|
-
if (/\bcrewai\b/.test(lower))
|
|
301
|
-
frameworks.add('CrewAI');
|
|
302
|
-
if (/\bautogen\b/.test(lower))
|
|
303
|
-
frameworks.add('AutoGen');
|
|
304
|
-
}
|
|
305
|
-
function addSourceHints(cwd, providers, frameworks) {
|
|
306
|
-
let hasNodeSource = false;
|
|
307
|
-
let hasPythonSource = false;
|
|
308
|
-
for (const dir of ['src', 'app', 'lib', 'agents', 'python']) {
|
|
309
|
-
const root = join(cwd, dir);
|
|
310
|
-
if (!existsSync(root))
|
|
311
|
-
continue;
|
|
312
|
-
for (const file of listShallowSourceFiles(root).slice(0, 80)) {
|
|
313
|
-
if (/\.(ts|tsx|js|jsx|mjs)$/i.test(file))
|
|
314
|
-
hasNodeSource = true;
|
|
315
|
-
if (/\.py$/i.test(file))
|
|
316
|
-
hasPythonSource = true;
|
|
317
|
-
addPythonHints(safeRead(file), providers, frameworks);
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
return { hasNodeSource, hasPythonSource };
|
|
321
|
-
}
|
|
322
|
-
function listShallowSourceFiles(root) {
|
|
323
|
-
const files = [];
|
|
324
|
-
const stack = [{ path: root, depth: 0 }];
|
|
325
|
-
while (stack.length > 0 && files.length < 120) {
|
|
326
|
-
const current = stack.pop();
|
|
327
|
-
if (!current)
|
|
328
|
-
continue;
|
|
329
|
-
let entries;
|
|
330
|
-
try {
|
|
331
|
-
entries = readdirSync(current.path, { withFileTypes: true });
|
|
332
|
-
}
|
|
333
|
-
catch {
|
|
334
|
-
continue;
|
|
335
|
-
}
|
|
336
|
-
for (const entry of entries) {
|
|
337
|
-
const path = join(current.path, entry.name);
|
|
338
|
-
if (entry.isDirectory()) {
|
|
339
|
-
if (current.depth < 2 && !['node_modules', '.git', 'dist', 'build', '.venv'].includes(entry.name)) {
|
|
340
|
-
stack.push({ path, depth: current.depth + 1 });
|
|
341
|
-
}
|
|
342
|
-
continue;
|
|
343
|
-
}
|
|
344
|
-
if (/\.(ts|tsx|js|jsx|mjs|py|md|toml|json|ya?ml)$/i.test(entry.name))
|
|
345
|
-
files.push(path);
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
return files;
|
|
125
|
+
].join('\n');
|
|
349
126
|
}
|
|
350
|
-
|
|
127
|
+
/** Read optional harness discovery context from `.moda/harness.json`. */
|
|
128
|
+
export function readRuntimeSummary(cwd) {
|
|
351
129
|
const empty = {
|
|
352
130
|
runtimeAgents: 0,
|
|
353
131
|
agentFamilies: 0,
|
|
@@ -384,16 +162,22 @@ function readRuntimeSummary(cwd) {
|
|
|
384
162
|
return empty;
|
|
385
163
|
}
|
|
386
164
|
}
|
|
387
|
-
function
|
|
388
|
-
|
|
389
|
-
|
|
165
|
+
export function renderRuntimeSummaryBlock(summary) {
|
|
166
|
+
const runtimeNames = summary.runtimeAgentNames.slice(0, 8);
|
|
167
|
+
const lines = [
|
|
168
|
+
`- Runtime agents: ${summary.runtimeAgents}`,
|
|
169
|
+
`- Agent families: ${summary.agentFamilies}`,
|
|
170
|
+
];
|
|
171
|
+
if (summary.frameworks.length > 0) {
|
|
172
|
+
lines.push(`- Frameworks: ${summary.frameworks.join(', ')}`);
|
|
390
173
|
}
|
|
391
|
-
|
|
392
|
-
|
|
174
|
+
if (summary.providers.length > 0) {
|
|
175
|
+
lines.push(`- Providers: ${summary.providers.join(', ')}`);
|
|
393
176
|
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
177
|
+
if (runtimeNames.length > 0) {
|
|
178
|
+
lines.push(`- Runtime agent names: ${runtimeNames.join(', ')}`);
|
|
179
|
+
}
|
|
180
|
+
return lines.join('\n');
|
|
397
181
|
}
|
|
398
182
|
function isRecord(value) {
|
|
399
183
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
@@ -1,54 +1,53 @@
|
|
|
1
|
-
import { type CodingAgentAdapter, type CodingAgentEvent } from '../harness.js';
|
|
1
|
+
import { type CodingAgentAdapter, type CodingAgentEvent, runCodingAgent } from '../harness.js';
|
|
2
|
+
import { type SdkAgentResult } from './sdk-protocol.js';
|
|
3
|
+
import { verifyExactTrace, type VerificationEvidence } from './sdk-verification.js';
|
|
4
|
+
import { readRuntimeSummary } from './sdk-guide.js';
|
|
2
5
|
export { describeCodingAgentEvent } from '../harness.js';
|
|
3
|
-
|
|
4
|
-
export
|
|
5
|
-
status:
|
|
6
|
-
adapter
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
detail
|
|
14
|
-
}
|
|
6
|
+
export type SdkIntegrationStatus = 'integrated_verified' | 'needs_human_input' | 'repository_checks_failed' | 'smoke_execution_failed' | 'telemetry_not_observed' | 'nothing_to_integrate' | 'agent_failed' | 'agent_unavailable' | 'cancelled';
|
|
7
|
+
export interface SdkIntegrationOutcome {
|
|
8
|
+
status: SdkIntegrationStatus;
|
|
9
|
+
adapter?: CodingAgentAdapter;
|
|
10
|
+
verification_id?: string;
|
|
11
|
+
verification?: VerificationEvidence;
|
|
12
|
+
agent_result?: SdkAgentResult;
|
|
13
|
+
repair_attempts: number;
|
|
14
|
+
security_findings?: string[];
|
|
15
|
+
installed_skill_ids?: string[];
|
|
16
|
+
detail?: string;
|
|
17
|
+
}
|
|
15
18
|
export interface SdkIntegrationOptions {
|
|
16
19
|
cwd?: string;
|
|
17
|
-
/** Explicit adapter override (e.g. from --analyst); otherwise best-ranked installed CLI. */
|
|
18
20
|
adapter?: CodingAgentAdapter;
|
|
19
|
-
/** Stream the agent's progress to the user (human terminals only). */
|
|
20
21
|
human?: boolean;
|
|
21
22
|
onProgress?: (message: string) => void;
|
|
22
|
-
/**
|
|
23
|
-
* Receive the structured coding-agent stream events incrementally (tool use,
|
|
24
|
-
* commands, agent text) so callers like the init progress board can render
|
|
25
|
-
* their own live view. Providing it enables the streaming invocation even
|
|
26
|
-
* when `human` is false.
|
|
27
|
-
*/
|
|
28
23
|
onEvent?: (event: CodingAgentEvent) => void;
|
|
24
|
+
onPhase?: (phase: 'investigating' | 'verifying' | 'repairing', message: string) => void;
|
|
25
|
+
apiKey?: string;
|
|
26
|
+
ingestUrl?: string;
|
|
27
|
+
maxRepairAttempts?: number;
|
|
28
|
+
verifyTimeoutMs?: number;
|
|
29
|
+
runAgent?: typeof runCodingAgent;
|
|
30
|
+
verify?: typeof verifyExactTrace;
|
|
31
|
+
fetchAudit?: (id: string) => Promise<unknown>;
|
|
32
|
+
}
|
|
33
|
+
type RepairableClassification = 'telemetry_not_observed' | 'repository_checks_failed' | 'smoke_execution_failed' | 'protocol_violation' | 'failed';
|
|
34
|
+
export declare function runSdkIntegration(options?: SdkIntegrationOptions): Promise<SdkIntegrationOutcome>;
|
|
35
|
+
export interface SdkIntegrationPromptOptions {
|
|
36
|
+
catalogDir: string;
|
|
37
|
+
catalogListing: string;
|
|
38
|
+
verificationId: string;
|
|
39
|
+
harnessSummary?: ReturnType<typeof readRuntimeSummary>;
|
|
29
40
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
/** Skill materialized to `.claude/skills/<id>/` — point the agent at it. */
|
|
39
|
-
installedSkillId?: string;
|
|
40
|
-
/** Resolved skill we could read but not materialize — inline its content. */
|
|
41
|
-
inlineSkill?: {
|
|
42
|
-
skillId: string;
|
|
43
|
-
markdown: string;
|
|
44
|
-
};
|
|
45
|
-
/**
|
|
46
|
-
* The skill the detected stack resolved to, if any. Set even when neither
|
|
47
|
-
* install nor inline succeeded (e.g. the bundle is entirely absent) so the
|
|
48
|
-
* generic fallback can flag the degradation and tell the agent to tailor the
|
|
49
|
-
* checklist to the detected stack instead of treating it as stack-less.
|
|
50
|
-
*/
|
|
51
|
-
resolvedSkillId?: string;
|
|
41
|
+
export declare function renderSdkIntegrationPrompt(opts: SdkIntegrationPromptOptions): string;
|
|
42
|
+
export interface SdkRepairPromptOptions extends SdkIntegrationPromptOptions {
|
|
43
|
+
attempt: number;
|
|
44
|
+
maxAttempts: number;
|
|
45
|
+
classification: RepairableClassification;
|
|
46
|
+
previousResult?: SdkAgentResult;
|
|
47
|
+
verification?: VerificationEvidence;
|
|
48
|
+
securityFindings?: string[];
|
|
52
49
|
}
|
|
53
|
-
export declare function
|
|
50
|
+
export declare function renderSdkRepairPrompt(opts: SdkRepairPromptOptions): string;
|
|
51
|
+
export declare function parseGitDeltaPaths(deltaLines: string[]): string[];
|
|
52
|
+
export declare function redactSecretText(text: string, apiKey?: string): string;
|
|
54
53
|
//# sourceMappingURL=sdk-integration.d.ts.map
|