@convilyn/sdk-author 0.7.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/CHANGELOG.md +280 -0
- package/LICENSE +201 -0
- package/README.md +310 -0
- package/dist/chunk-ZNZXT5ZP.js +1311 -0
- package/dist/chunk-ZNZXT5ZP.js.map +1 -0
- package/dist/cli.cjs +1391 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.js +471 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +1627 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1158 -0
- package/dist/index.d.ts +1158 -0
- package/dist/index.js +279 -0
- package/dist/index.js.map +1 -0
- package/package.json +84 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { VERSION, allChecksPassed, serve, runComplianceChecks, ConvilynClient, ConvilynApiError, WorkflowSpec } from './chunk-ZNZXT5ZP.js';
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { mkdir, writeFile, stat, readdir } from 'fs/promises';
|
|
5
|
+
import { resolve, join, extname } from 'path';
|
|
6
|
+
import { pathToFileURL } from 'url';
|
|
7
|
+
|
|
8
|
+
// src/cli/print.ts
|
|
9
|
+
var consolePrinter = {
|
|
10
|
+
out: (line) => {
|
|
11
|
+
process.stdout.write(`${line}
|
|
12
|
+
`);
|
|
13
|
+
},
|
|
14
|
+
err: (line) => {
|
|
15
|
+
process.stderr.write(`${line}
|
|
16
|
+
`);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
var NAME_RE = /^[a-zA-Z0-9_-]+$/;
|
|
20
|
+
function isValidProjectName(name) {
|
|
21
|
+
return NAME_RE.test(name);
|
|
22
|
+
}
|
|
23
|
+
function serverTs(name) {
|
|
24
|
+
return `import { defineTool, ToolServer, ToolResult } from '@convilyn/sdk-author'
|
|
25
|
+
import { z } from 'zod'
|
|
26
|
+
|
|
27
|
+
const echo = defineTool({
|
|
28
|
+
name: 'echo',
|
|
29
|
+
description: 'Echo the input text back.',
|
|
30
|
+
input: z.object({ text: z.string().min(1) }),
|
|
31
|
+
idempotent: true,
|
|
32
|
+
handler: (args) => ToolResult.ok({ echoed: args.text }, \`Echoed \${args.text.length} chars\`),
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
export const server = new ToolServer(
|
|
36
|
+
{ name: '${name}', version: '0.1.0', description: 'A Convilyn tool server.' },
|
|
37
|
+
{ tools: [echo] }
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
export default server
|
|
41
|
+
`;
|
|
42
|
+
}
|
|
43
|
+
function packageJson(name) {
|
|
44
|
+
return `${JSON.stringify(
|
|
45
|
+
{
|
|
46
|
+
name,
|
|
47
|
+
version: "0.1.0",
|
|
48
|
+
private: true,
|
|
49
|
+
type: "module",
|
|
50
|
+
scripts: {
|
|
51
|
+
build: "tsc",
|
|
52
|
+
synth: "convilyn-author synth --file dist/server.js",
|
|
53
|
+
dev: "convilyn-author dev --file dist/server.js",
|
|
54
|
+
test: "convilyn-author test --file dist/server.js"
|
|
55
|
+
},
|
|
56
|
+
dependencies: {
|
|
57
|
+
"@convilyn/sdk-author": `^${VERSION}`,
|
|
58
|
+
zod: "^3.23.0"
|
|
59
|
+
},
|
|
60
|
+
devDependencies: {
|
|
61
|
+
typescript: "^5.7.2"
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
null,
|
|
65
|
+
2
|
|
66
|
+
)}
|
|
67
|
+
`;
|
|
68
|
+
}
|
|
69
|
+
var TSCONFIG = `${JSON.stringify(
|
|
70
|
+
{
|
|
71
|
+
compilerOptions: {
|
|
72
|
+
target: "ES2022",
|
|
73
|
+
module: "NodeNext",
|
|
74
|
+
moduleResolution: "NodeNext",
|
|
75
|
+
outDir: "dist",
|
|
76
|
+
strict: true,
|
|
77
|
+
skipLibCheck: true,
|
|
78
|
+
declaration: false
|
|
79
|
+
},
|
|
80
|
+
include: ["server.ts"]
|
|
81
|
+
},
|
|
82
|
+
null,
|
|
83
|
+
2
|
|
84
|
+
)}
|
|
85
|
+
`;
|
|
86
|
+
var GITIGNORE = `node_modules/
|
|
87
|
+
dist/
|
|
88
|
+
convilyn.manifest.json
|
|
89
|
+
.env
|
|
90
|
+
`;
|
|
91
|
+
var ENV_EXAMPLE = `# Inbound HMAC secret (enables POST /mcp signature verification)
|
|
92
|
+
CONVILYN_HMAC_SECRET=
|
|
93
|
+
# Local dev server port
|
|
94
|
+
CONVILYN_PORT=8080
|
|
95
|
+
# Platform API (used by push/deploy once those land)
|
|
96
|
+
CONVILYN_PLATFORM_URL=https://api.convilyn.corenovus.com
|
|
97
|
+
CONVILYN_API_KEY=
|
|
98
|
+
`;
|
|
99
|
+
function readme(name) {
|
|
100
|
+
return `# ${name}
|
|
101
|
+
|
|
102
|
+
A Convilyn tool server, scaffolded by \`convilyn-author init\`.
|
|
103
|
+
|
|
104
|
+
## Develop
|
|
105
|
+
|
|
106
|
+
\`\`\`bash
|
|
107
|
+
npm install
|
|
108
|
+
npm run build # server.ts -> dist/server.js
|
|
109
|
+
npx convilyn-author dev # run the JSON-RPC /mcp server locally
|
|
110
|
+
npx convilyn-author synth # write convilyn.manifest.json
|
|
111
|
+
npx convilyn-author test # local compliance checks
|
|
112
|
+
\`\`\`
|
|
113
|
+
|
|
114
|
+
Edit \`server.ts\` to add tools with \`defineTool\`.
|
|
115
|
+
`;
|
|
116
|
+
}
|
|
117
|
+
function projectFiles(name) {
|
|
118
|
+
return {
|
|
119
|
+
"server.ts": serverTs(name),
|
|
120
|
+
"package.json": packageJson(name),
|
|
121
|
+
"tsconfig.json": TSCONFIG,
|
|
122
|
+
".gitignore": GITIGNORE,
|
|
123
|
+
".env.example": ENV_EXAMPLE,
|
|
124
|
+
"README.md": readme(name)
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
async function isNonEmptyDir(dir) {
|
|
128
|
+
try {
|
|
129
|
+
const entries = await readdir(dir);
|
|
130
|
+
return entries.length > 0;
|
|
131
|
+
} catch {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async function scaffoldProject(options) {
|
|
136
|
+
const { name } = options;
|
|
137
|
+
if (!isValidProjectName(name)) {
|
|
138
|
+
throw new Error(
|
|
139
|
+
`Invalid project name "${name}": use letters, digits, hyphens, underscores only.`
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
const path = resolve(options.dir ?? `./${name}`);
|
|
143
|
+
if (await isNonEmptyDir(path)) {
|
|
144
|
+
throw new Error(`Target directory "${path}" is not empty \u2014 refusing to overwrite.`);
|
|
145
|
+
}
|
|
146
|
+
await mkdir(path, { recursive: true });
|
|
147
|
+
const files = projectFiles(name);
|
|
148
|
+
const written = [];
|
|
149
|
+
for (const [rel, content] of Object.entries(files)) {
|
|
150
|
+
await writeFile(join(path, rel), content, "utf8");
|
|
151
|
+
written.push(rel);
|
|
152
|
+
}
|
|
153
|
+
return { path, files: written.sort() };
|
|
154
|
+
}
|
|
155
|
+
function isToolServerLike(value) {
|
|
156
|
+
if (typeof value !== "object" || value === null) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
const candidate = value;
|
|
160
|
+
return typeof candidate.manifest === "function" && typeof candidate.dispatch === "function" && typeof candidate.server === "object" && candidate.server !== null;
|
|
161
|
+
}
|
|
162
|
+
function pickServer(mod) {
|
|
163
|
+
if (isToolServerLike(mod.default)) {
|
|
164
|
+
return mod.default;
|
|
165
|
+
}
|
|
166
|
+
if (isToolServerLike(mod.server)) {
|
|
167
|
+
return mod.server;
|
|
168
|
+
}
|
|
169
|
+
for (const value of Object.values(mod)) {
|
|
170
|
+
if (isToolServerLike(value)) {
|
|
171
|
+
return value;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return void 0;
|
|
175
|
+
}
|
|
176
|
+
async function loadToolServer(file) {
|
|
177
|
+
const absolute = resolve(file);
|
|
178
|
+
let mod;
|
|
179
|
+
try {
|
|
180
|
+
mod = await import(pathToFileURL(absolute).href);
|
|
181
|
+
} catch (err) {
|
|
182
|
+
throw new Error(
|
|
183
|
+
`Could not import server module "${file}": ${err.message}. Point --file at a built .js module (e.g. "npm run build" then --file dist/server.js).`
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
const server = pickServer(mod);
|
|
187
|
+
if (server === void 0) {
|
|
188
|
+
throw new Error(
|
|
189
|
+
`No ToolServer found in "${file}". Export it as the default export or as a named "server" export.`
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
return server;
|
|
193
|
+
}
|
|
194
|
+
function isWorkflowSpecLike(value) {
|
|
195
|
+
if (typeof value !== "object" || value === null) {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
const candidate = value;
|
|
199
|
+
return typeof candidate.compile === "function" && typeof candidate.name === "string";
|
|
200
|
+
}
|
|
201
|
+
function pickWorkflow(mod) {
|
|
202
|
+
if (isWorkflowSpecLike(mod.default)) {
|
|
203
|
+
return mod.default;
|
|
204
|
+
}
|
|
205
|
+
if (isWorkflowSpecLike(mod.workflow)) {
|
|
206
|
+
return mod.workflow;
|
|
207
|
+
}
|
|
208
|
+
for (const value of Object.values(mod)) {
|
|
209
|
+
if (isWorkflowSpecLike(value)) {
|
|
210
|
+
return value;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return void 0;
|
|
214
|
+
}
|
|
215
|
+
async function loadWorkflowSpec(file) {
|
|
216
|
+
const absolute = resolve(file);
|
|
217
|
+
if (extname(absolute).toLowerCase() === ".json") {
|
|
218
|
+
try {
|
|
219
|
+
return await WorkflowSpec.load(absolute);
|
|
220
|
+
} catch (err) {
|
|
221
|
+
throw new Error(
|
|
222
|
+
`Could not load workflow spec "${file}": ${err.message}. Point --workflow-file at a compiled spec JSON (from WorkflowSpec.save()) or a built .js module that exports a WorkflowSpec.`
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
let mod;
|
|
227
|
+
try {
|
|
228
|
+
mod = await import(pathToFileURL(absolute).href);
|
|
229
|
+
} catch (err) {
|
|
230
|
+
throw new Error(
|
|
231
|
+
`Could not import workflow module "${file}": ${err.message}. Point --workflow-file at a built .js module (e.g. "npm run build" then --workflow-file dist/workflow.js) or a compiled .spec.json.`
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
const workflow = pickWorkflow(mod);
|
|
235
|
+
if (workflow === void 0) {
|
|
236
|
+
throw new Error(
|
|
237
|
+
`No WorkflowSpec found in "${file}". Export it as the default export or as a named "workflow" export.`
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
return workflow;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// src/cli/commands.ts
|
|
244
|
+
var DEFAULT_SERVER_FILE = "server.js";
|
|
245
|
+
var DEFAULT_WORKFLOW_FILE = "workflow.spec.json";
|
|
246
|
+
var DEFAULT_MANIFEST_OUTPUT = "convilyn.manifest.json";
|
|
247
|
+
async function runSynth(options) {
|
|
248
|
+
const server = await loadToolServer(options.file ?? DEFAULT_SERVER_FILE);
|
|
249
|
+
const manifest = server.manifest();
|
|
250
|
+
const path = await manifest.save(options.output ?? DEFAULT_MANIFEST_OUTPUT);
|
|
251
|
+
return { path, toolCount: manifest.tools.length, toolNames: manifest.tools.map((t) => t.name) };
|
|
252
|
+
}
|
|
253
|
+
async function runDev(options) {
|
|
254
|
+
const server = await loadToolServer(options.file ?? DEFAULT_SERVER_FILE);
|
|
255
|
+
return serve(server, {
|
|
256
|
+
host: options.host,
|
|
257
|
+
port: options.port,
|
|
258
|
+
hmacSecret: options.hmacSecret,
|
|
259
|
+
// `dev` IS the explicit insecure-local opt-in (mirror of the Python
|
|
260
|
+
// CLI's run(dev=True)). A configured secret still wins — the opt-in
|
|
261
|
+
// never bypasses verification.
|
|
262
|
+
allowInsecure: true
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
async function runTest(options) {
|
|
266
|
+
const server = await loadToolServer(options.file ?? DEFAULT_SERVER_FILE);
|
|
267
|
+
return runComplianceChecks(server);
|
|
268
|
+
}
|
|
269
|
+
async function runPush(options) {
|
|
270
|
+
if (!options.endpointUrl) {
|
|
271
|
+
throw new Error(
|
|
272
|
+
"push requires --endpoint-url <https://...> \u2014 the HTTPS URL where your tool server is deployed. Use `deploy --hosted` for a Convilyn-hosted server."
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
const server = await loadToolServer(options.file ?? DEFAULT_SERVER_FILE);
|
|
276
|
+
const workflow = await loadWorkflowSpec(options.workflowFile ?? DEFAULT_WORKFLOW_FILE);
|
|
277
|
+
const client = options.client ?? new ConvilynClient();
|
|
278
|
+
const manifest = server.manifest().toWire();
|
|
279
|
+
const serverResult = await client.submitServer({
|
|
280
|
+
manifest,
|
|
281
|
+
endpoint_url: options.endpointUrl
|
|
282
|
+
});
|
|
283
|
+
const workflowResult = await client.submitWorkflow({
|
|
284
|
+
// CompilableWorkflow.compile() is typed `unknown` (the file loader duck-types
|
|
285
|
+
// both a built WorkflowSpec and a pre-compiled JSON blueprint).
|
|
286
|
+
workflow_spec: workflow.compile(),
|
|
287
|
+
server_ids: [serverResult.server_id]
|
|
288
|
+
});
|
|
289
|
+
return {
|
|
290
|
+
serverId: serverResult.server_id,
|
|
291
|
+
serverName: serverResult.server_name,
|
|
292
|
+
serverStatus: serverResult.status,
|
|
293
|
+
workflowId: workflowResult.workflow_id,
|
|
294
|
+
workflowSpecId: workflowResult.spec_id,
|
|
295
|
+
workflowStatus: workflowResult.status
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
async function runDeploy(options) {
|
|
299
|
+
if (!options.hosted) {
|
|
300
|
+
throw new Error(
|
|
301
|
+
"deploy currently requires --hosted. Use `convilyn-author push --endpoint-url <https://...>` for caller-deployed (BYO) servers."
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
const server = await loadToolServer(options.file ?? DEFAULT_SERVER_FILE);
|
|
305
|
+
const manifest = server.manifest().toWire();
|
|
306
|
+
const workflowFile = options.workflowFile ?? DEFAULT_WORKFLOW_FILE;
|
|
307
|
+
let workflowSpec;
|
|
308
|
+
if (await stat(workflowFile).then(
|
|
309
|
+
() => true,
|
|
310
|
+
() => false
|
|
311
|
+
)) {
|
|
312
|
+
const workflow = await loadWorkflowSpec(workflowFile);
|
|
313
|
+
workflowSpec = workflow.compile();
|
|
314
|
+
}
|
|
315
|
+
const client = options.client ?? new ConvilynClient();
|
|
316
|
+
const result = await client.deployHostedRuntime(manifest, {
|
|
317
|
+
region: options.region ?? "us-east-1",
|
|
318
|
+
...workflowSpec !== void 0 ? { workflowSpec } : {}
|
|
319
|
+
});
|
|
320
|
+
return {
|
|
321
|
+
runtimeId: result.runtime_id,
|
|
322
|
+
endpointUrl: result.endpoint_url ?? null,
|
|
323
|
+
status: result.status,
|
|
324
|
+
region: result.region,
|
|
325
|
+
version: result.version,
|
|
326
|
+
...result.workflow_id != null ? { workflowId: result.workflow_id } : {},
|
|
327
|
+
workflowIncluded: workflowSpec !== void 0
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
async function runRollback(options) {
|
|
331
|
+
const client = options.client ?? new ConvilynClient();
|
|
332
|
+
return client.rollbackHostedRuntime(options.runtimeId);
|
|
333
|
+
}
|
|
334
|
+
async function runLogs(options) {
|
|
335
|
+
const client = options.client ?? new ConvilynClient();
|
|
336
|
+
return client.getHostedRuntimeLogs(options.runtimeId, {
|
|
337
|
+
...options.since !== void 0 ? { since: options.since } : {},
|
|
338
|
+
...options.limit !== void 0 ? { limit: options.limit } : {}
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// src/cli/program.ts
|
|
343
|
+
function fail(printer, err) {
|
|
344
|
+
printer.err(`error: ${err.message}`);
|
|
345
|
+
process.exitCode = 1;
|
|
346
|
+
}
|
|
347
|
+
function failHosted(printer, err) {
|
|
348
|
+
if (err instanceof ConvilynApiError && (err.status === 501 || err.status === 503)) {
|
|
349
|
+
printer.err(
|
|
350
|
+
`error: hosted runtime not yet available on this platform (${err.message}). Use \`convilyn-author push --endpoint-url ...\` as a BYO fallback.`
|
|
351
|
+
);
|
|
352
|
+
process.exitCode = 1;
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
fail(printer, err);
|
|
356
|
+
}
|
|
357
|
+
function buildProgram(printer = consolePrinter) {
|
|
358
|
+
const program = new Command();
|
|
359
|
+
program.name("convilyn-author").description("Author and run Convilyn tool servers.").version(VERSION);
|
|
360
|
+
program.command("init").description("Scaffold a new tool-server project.").argument("<name>", "project name (letters, digits, hyphens, underscores)").option("--dir <dir>", "target directory (default ./<name>)").action(async (name, opts) => {
|
|
361
|
+
try {
|
|
362
|
+
const result = await scaffoldProject({ name, dir: opts.dir });
|
|
363
|
+
printer.out(`Project created: ${result.path}`);
|
|
364
|
+
printer.out(` ${result.files.join(", ")}`);
|
|
365
|
+
printer.out(` cd ${name} && npm install && npm run build && npx convilyn-author dev`);
|
|
366
|
+
} catch (err) {
|
|
367
|
+
fail(printer, err);
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
program.command("synth").description("Compile the server manifest to JSON.").option("--file <file>", "built server module (default server.js)").option("--output <output>", "manifest output path (default convilyn.manifest.json)").action(async (opts) => {
|
|
371
|
+
try {
|
|
372
|
+
const result = await runSynth(opts);
|
|
373
|
+
printer.out(`Found ${result.toolCount} tool(s): ${result.toolNames.join(", ")}`);
|
|
374
|
+
printer.out(`Manifest written: ${result.path}`);
|
|
375
|
+
} catch (err) {
|
|
376
|
+
fail(printer, err);
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
program.command("dev").description("Run the JSON-RPC /mcp server locally.").option("--file <file>", "built server module (default server.js)").option("--host <host>", "bind host (default from CONVILYN_HOST)").option("--port <port>", "bind port (default from CONVILYN_PORT)", (v) => parseInt(v, 10)).action(async (opts) => {
|
|
380
|
+
try {
|
|
381
|
+
await runDev(opts);
|
|
382
|
+
printer.out("convilyn-author dev: serving /mcp (Ctrl+C to stop)");
|
|
383
|
+
} catch (err) {
|
|
384
|
+
fail(printer, err);
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
program.command("test").description("Run local compliance checks (no platform calls).").option("--file <file>", "built server module (default server.js)").action(async (opts) => {
|
|
388
|
+
try {
|
|
389
|
+
const report = await runTest(opts);
|
|
390
|
+
for (const r of report.results) {
|
|
391
|
+
printer.out(` [${r.passed ? "PASS" : "FAIL"}] ${r.checkName}: ${r.message}`);
|
|
392
|
+
}
|
|
393
|
+
if (allChecksPassed(report)) {
|
|
394
|
+
printer.out(`All ${report.results.length} checks passed`);
|
|
395
|
+
} else {
|
|
396
|
+
const failed = report.results.filter((r) => !r.passed).length;
|
|
397
|
+
printer.err(`${failed} of ${report.results.length} checks failed`);
|
|
398
|
+
process.exitCode = 1;
|
|
399
|
+
}
|
|
400
|
+
} catch (err) {
|
|
401
|
+
fail(printer, err);
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
program.command("push").description("Submit a server + workflow to the Developer Portal.").option("--file <file>", "built server module (default server.js)").option(
|
|
405
|
+
"--workflow-file <file>",
|
|
406
|
+
"compiled workflow spec or built module (default workflow.spec.json)"
|
|
407
|
+
).option("--endpoint-url <url>", "HTTPS URL of your deployed server (required)").action(async (opts) => {
|
|
408
|
+
try {
|
|
409
|
+
const result = await runPush(opts);
|
|
410
|
+
printer.out(`Server submitted: ${result.serverId} (${result.serverStatus})`);
|
|
411
|
+
printer.out(`Workflow submitted: ${result.workflowId} (${result.workflowStatus})`);
|
|
412
|
+
printer.out("Check verification with the ConvilynClient serverStatus() / workflowStatus().");
|
|
413
|
+
} catch (err) {
|
|
414
|
+
fail(printer, err);
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
program.command("deploy").description("Deploy a tool server to the Convilyn-Hosted Author Runtime.").option("--file <file>", "built server module (default server.js)").option(
|
|
418
|
+
"--workflow-file <file>",
|
|
419
|
+
"compiled workflow spec (default workflow.spec.json; optional \u2014 skipped when absent)"
|
|
420
|
+
).option("--hosted", "use the managed runtime (required \u2014 BYO uses push)").option("--region <region>", "AWS region the hosted Lambda is provisioned in", "us-east-1").action(
|
|
421
|
+
async (opts) => {
|
|
422
|
+
try {
|
|
423
|
+
printer.out(`Deploying to Convilyn-Hosted Runtime in ${opts.region ?? "us-east-1"}...`);
|
|
424
|
+
const result = await runDeploy(opts);
|
|
425
|
+
printer.out(`Runtime provisioned: ${result.runtimeId} (${result.status})`);
|
|
426
|
+
printer.out(`Endpoint URL: ${result.endpointUrl ?? "pending (provisioning)"}`);
|
|
427
|
+
if (result.workflowId != null) {
|
|
428
|
+
printer.out(`Workflow registered: ${result.workflowId}`);
|
|
429
|
+
}
|
|
430
|
+
printer.out(
|
|
431
|
+
`Use 'convilyn-author logs ${result.runtimeId}' to follow runtime logs, 'convilyn-author rollback ${result.runtimeId}' to revert.`
|
|
432
|
+
);
|
|
433
|
+
} catch (err) {
|
|
434
|
+
failHosted(printer, err);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
);
|
|
438
|
+
program.command("rollback").description("Roll a hosted runtime back to its previous active version.").argument("<runtimeId>", "runtime id returned by deploy --hosted").action(async (runtimeId) => {
|
|
439
|
+
try {
|
|
440
|
+
printer.out(`Rolling back ${runtimeId}...`);
|
|
441
|
+
const result = await runRollback({ runtimeId });
|
|
442
|
+
printer.out(`Rollback complete: now-active version ${result.version} (${result.status})`);
|
|
443
|
+
} catch (err) {
|
|
444
|
+
fail(printer, err);
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
program.command("logs").description("Fetch recent logs for a hosted runtime.").argument("<runtimeId>", "runtime id returned by deploy --hosted").option("--since <since>", "relative window (e.g. '5m', '1h') or ISO-8601 timestamp").option("--limit <limit>", "maximum log entries to fetch", (v) => parseInt(v, 10)).action(async (runtimeId, opts) => {
|
|
448
|
+
try {
|
|
449
|
+
const entries = await runLogs({ runtimeId, ...opts });
|
|
450
|
+
if (entries.length === 0) {
|
|
451
|
+
printer.out(`No log entries for ${runtimeId} in the requested window.`);
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
for (const entry of entries) {
|
|
455
|
+
printer.out(`[${entry.timestamp}] ${entry.level} ${entry.message}`);
|
|
456
|
+
}
|
|
457
|
+
} catch (err) {
|
|
458
|
+
fail(printer, err);
|
|
459
|
+
}
|
|
460
|
+
});
|
|
461
|
+
return program;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// src/cli.ts
|
|
465
|
+
buildProgram().parseAsync(process.argv).catch((err) => {
|
|
466
|
+
process.stderr.write(`error: ${err.message}
|
|
467
|
+
`);
|
|
468
|
+
process.exitCode = 1;
|
|
469
|
+
});
|
|
470
|
+
//# sourceMappingURL=cli.js.map
|
|
471
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/print.ts","../src/cli/scaffold.ts","../src/cli/load-server.ts","../src/cli/load-workflow.ts","../src/cli/commands.ts","../src/cli/program.ts","../src/cli.ts"],"names":["resolve","pathToFileURL"],"mappings":"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","file":"cli.js","sourcesContent":["/**\n * A tiny output seam for the CLI so command cores stay testable (inject a\n * capturing {@link Printer} in tests) and the package keeps no raw `console.log`.\n */\n\nexport interface Printer {\n out(line: string): void\n err(line: string): void\n}\n\n/** Default {@link Printer} writing to the real stdout / stderr. */\nexport const consolePrinter: Printer = {\n out: (line) => {\n process.stdout.write(`${line}\\n`)\n },\n err: (line) => {\n process.stderr.write(`${line}\\n`)\n },\n}\n","/**\n * `convilyn-author init` — scaffold a new tool-server project. Pure local file\n * writes; no platform calls. Refuses to write into a non-empty directory.\n *\n * The scaffold authors in TypeScript and builds to `dist/server.js`; the\n * generated `synth` / `dev` / `test` scripts point the CLI at that built module\n * (the CLI loads JS, not TS — no TS runtime is pulled in).\n */\n\nimport { mkdir, readdir, writeFile } from 'node:fs/promises'\nimport { resolve, join } from 'node:path'\nimport { VERSION } from '../version'\n\nconst NAME_RE = /^[a-zA-Z0-9_-]+$/\n\n/** Validate a project name (alphanumeric, hyphen, underscore). */\nexport function isValidProjectName(name: string): boolean {\n return NAME_RE.test(name)\n}\n\nfunction serverTs(name: string): string {\n return `import { defineTool, ToolServer, ToolResult } from '@convilyn/sdk-author'\nimport { z } from 'zod'\n\nconst echo = defineTool({\n name: 'echo',\n description: 'Echo the input text back.',\n input: z.object({ text: z.string().min(1) }),\n idempotent: true,\n handler: (args) => ToolResult.ok({ echoed: args.text }, \\`Echoed \\${args.text.length} chars\\`),\n})\n\nexport const server = new ToolServer(\n { name: '${name}', version: '0.1.0', description: 'A Convilyn tool server.' },\n { tools: [echo] }\n)\n\nexport default server\n`\n}\n\nfunction packageJson(name: string): string {\n return `${JSON.stringify(\n {\n name,\n version: '0.1.0',\n private: true,\n type: 'module',\n scripts: {\n build: 'tsc',\n synth: 'convilyn-author synth --file dist/server.js',\n dev: 'convilyn-author dev --file dist/server.js',\n test: 'convilyn-author test --file dist/server.js',\n },\n dependencies: {\n '@convilyn/sdk-author': `^${VERSION}`,\n zod: '^3.23.0',\n },\n devDependencies: {\n typescript: '^5.7.2',\n },\n },\n null,\n 2\n )}\\n`\n}\n\nconst TSCONFIG = `${JSON.stringify(\n {\n compilerOptions: {\n target: 'ES2022',\n module: 'NodeNext',\n moduleResolution: 'NodeNext',\n outDir: 'dist',\n strict: true,\n skipLibCheck: true,\n declaration: false,\n },\n include: ['server.ts'],\n },\n null,\n 2\n)}\\n`\n\nconst GITIGNORE = `node_modules/\ndist/\nconvilyn.manifest.json\n.env\n`\n\nconst ENV_EXAMPLE = `# Inbound HMAC secret (enables POST /mcp signature verification)\nCONVILYN_HMAC_SECRET=\n# Local dev server port\nCONVILYN_PORT=8080\n# Platform API (used by push/deploy once those land)\nCONVILYN_PLATFORM_URL=https://api.convilyn.corenovus.com\nCONVILYN_API_KEY=\n`\n\nfunction readme(name: string): string {\n return `# ${name}\n\nA Convilyn tool server, scaffolded by \\`convilyn-author init\\`.\n\n## Develop\n\n\\`\\`\\`bash\nnpm install\nnpm run build # server.ts -> dist/server.js\nnpx convilyn-author dev # run the JSON-RPC /mcp server locally\nnpx convilyn-author synth # write convilyn.manifest.json\nnpx convilyn-author test # local compliance checks\n\\`\\`\\`\n\nEdit \\`server.ts\\` to add tools with \\`defineTool\\`.\n`\n}\n\n/** The files {@link scaffoldProject} writes, keyed by their relative path. */\nexport function projectFiles(name: string): Record<string, string> {\n return {\n 'server.ts': serverTs(name),\n 'package.json': packageJson(name),\n 'tsconfig.json': TSCONFIG,\n '.gitignore': GITIGNORE,\n '.env.example': ENV_EXAMPLE,\n 'README.md': readme(name),\n }\n}\n\nasync function isNonEmptyDir(dir: string): Promise<boolean> {\n try {\n const entries = await readdir(dir)\n return entries.length > 0\n } catch {\n return false // does not exist yet\n }\n}\n\n/** Result of {@link scaffoldProject}. */\nexport interface ScaffoldResult {\n path: string\n files: string[]\n}\n\n/**\n * Scaffold a project named `name` into `dir` (default `./<name>`). Throws on an\n * invalid name or a non-empty target directory.\n */\nexport async function scaffoldProject(options: {\n name: string\n dir?: string\n}): Promise<ScaffoldResult> {\n const { name } = options\n if (!isValidProjectName(name)) {\n throw new Error(\n `Invalid project name \"${name}\": use letters, digits, hyphens, underscores only.`\n )\n }\n const path = resolve(options.dir ?? `./${name}`)\n if (await isNonEmptyDir(path)) {\n throw new Error(`Target directory \"${path}\" is not empty — refusing to overwrite.`)\n }\n await mkdir(path, { recursive: true })\n const files = projectFiles(name)\n const written: string[] = []\n for (const [rel, content] of Object.entries(files)) {\n await writeFile(join(path, rel), content, 'utf8')\n written.push(rel)\n }\n return { path, files: written.sort() }\n}\n","/**\n * Locate and load the author's {@link ToolServer} from a built JS module. Used by\n * the `synth` / `dev` / `test` commands.\n *\n * The export is **duck-typed**, never `instanceof`-checked: the CLI binary bundles\n * its own copy of `ToolServer`, while the author's instance comes from *their*\n * installed `@convilyn/sdk-author` — two distinct class identities. We therefore\n * recognise a server by the shape the commands actually use (`server` metadata +\n * `manifest()` + `dispatch()`).\n *\n * The author points at a built `.js`/`.mjs`/`.cjs` module (default `server.js`)\n * exporting the server as the default export or a named `server` export.\n */\n\nimport { resolve } from 'node:path'\nimport { pathToFileURL } from 'node:url'\nimport type { ToolServer } from '../tool-server'\n\nfunction isToolServerLike(value: unknown): boolean {\n if (typeof value !== 'object' || value === null) {\n return false\n }\n const candidate = value as Record<string, unknown>\n return (\n typeof candidate.manifest === 'function' &&\n typeof candidate.dispatch === 'function' &&\n typeof candidate.server === 'object' &&\n candidate.server !== null\n )\n}\n\nfunction pickServer(mod: Record<string, unknown>): unknown {\n if (isToolServerLike(mod.default)) {\n return mod.default\n }\n if (isToolServerLike(mod.server)) {\n return mod.server\n }\n for (const value of Object.values(mod)) {\n if (isToolServerLike(value)) {\n return value\n }\n }\n return undefined\n}\n\n/**\n * Import `file` and return the {@link ToolServer} it exports. Throws a\n * descriptive error when the module cannot be imported or exports no server.\n */\nexport async function loadToolServer(file: string): Promise<ToolServer> {\n const absolute = resolve(file)\n let mod: Record<string, unknown>\n try {\n mod = (await import(pathToFileURL(absolute).href)) as Record<string, unknown>\n } catch (err) {\n throw new Error(\n `Could not import server module \"${file}\": ${(err as Error).message}. ` +\n `Point --file at a built .js module (e.g. \"npm run build\" then --file dist/server.js).`\n )\n }\n const server = pickServer(mod)\n if (server === undefined) {\n throw new Error(\n `No ToolServer found in \"${file}\". Export it as the default export or as a named \"server\" export.`\n )\n }\n return server as ToolServer\n}\n","/**\n * Locate and load the author's {@link WorkflowSpec} for the `push` command.\n *\n * Two shapes are accepted, mirroring how authors persist a spec:\n * - a compiled `.json` file written by `WorkflowSpec.save()` — loaded via\n * `WorkflowSpec.load()`;\n * - a built `.js`/`.mjs`/`.cjs` module exporting a `WorkflowSpec` as its\n * default or a named `workflow` export — duck-typed, never\n * `instanceof`-checked, because the CLI binary bundles its own copy of\n * `WorkflowSpec` while the author's instance comes from *their* installed\n * `@convilyn/sdk-author` (two distinct class identities). This matches the\n * `loadToolServer` contract for the server side.\n */\n\nimport { extname, resolve } from 'node:path'\nimport { pathToFileURL } from 'node:url'\nimport { WorkflowSpec } from '../workflow'\n\n/** The minimal surface `push` needs from a loaded workflow. */\nexport interface CompilableWorkflow {\n readonly name: string\n compile(): unknown\n}\n\nfunction isWorkflowSpecLike(value: unknown): value is CompilableWorkflow {\n if (typeof value !== 'object' || value === null) {\n return false\n }\n const candidate = value as Record<string, unknown>\n return typeof candidate.compile === 'function' && typeof candidate.name === 'string'\n}\n\nfunction pickWorkflow(mod: Record<string, unknown>): CompilableWorkflow | undefined {\n if (isWorkflowSpecLike(mod.default)) {\n return mod.default\n }\n if (isWorkflowSpecLike(mod.workflow)) {\n return mod.workflow\n }\n for (const value of Object.values(mod)) {\n if (isWorkflowSpecLike(value)) {\n return value\n }\n }\n return undefined\n}\n\n/**\n * Load the {@link WorkflowSpec} at `file`. A `.json` file is parsed as a\n * compiled spec; any other extension is imported as a built module. Throws a\n * descriptive error when the file cannot be loaded or exports no workflow.\n */\nexport async function loadWorkflowSpec(file: string): Promise<CompilableWorkflow> {\n const absolute = resolve(file)\n\n if (extname(absolute).toLowerCase() === '.json') {\n try {\n return await WorkflowSpec.load(absolute)\n } catch (err) {\n throw new Error(\n `Could not load workflow spec \"${file}\": ${(err as Error).message}. ` +\n `Point --workflow-file at a compiled spec JSON (from WorkflowSpec.save()) ` +\n `or a built .js module that exports a WorkflowSpec.`\n )\n }\n }\n\n let mod: Record<string, unknown>\n try {\n mod = (await import(pathToFileURL(absolute).href)) as Record<string, unknown>\n } catch (err) {\n throw new Error(\n `Could not import workflow module \"${file}\": ${(err as Error).message}. ` +\n `Point --workflow-file at a built .js module (e.g. \"npm run build\" then ` +\n `--workflow-file dist/workflow.js) or a compiled .spec.json.`\n )\n }\n const workflow = pickWorkflow(mod)\n if (workflow === undefined) {\n throw new Error(\n `No WorkflowSpec found in \"${file}\". Export it as the default export or as a named \"workflow\" export.`\n )\n }\n return workflow\n}\n","/**\n * Core logic for each `convilyn-author` subcommand, kept transport- and\n * process-free so it is unit-testable: each returns a value (or throws) and the\n * commander action layer (`program.ts`) handles printing + exit codes.\n *\n * `synth` / `dev` / `test` are fully local. `push` submits a server + workflow\n * to the **Developer Portal** (`/api/v1/developers/*`) via {@link ConvilynClient}\n * — the wire contract lives at `docs/contracts/developer_portal/` and the\n * behaviour mirrors the Python SDK's `ConvilynClient.push`. `deploy` /\n * `rollback` / `logs` drive the Convilyn-Hosted Author Runtime\n * (`/developers/runtimes/*`), ported from the Python CLI.\n */\n\nimport { stat } from 'node:fs/promises'\nimport type { Server } from 'node:http'\nimport { loadToolServer } from './load-server'\nimport { loadWorkflowSpec } from './load-workflow'\nimport { ConvilynClient } from '../client'\nimport { serve } from '../http-runtime'\nimport { runComplianceChecks } from '../compliance'\nimport type { ComplianceReport } from '../types'\nimport type { RollbackResponse, RuntimeLogEntry } from '../platform-types'\n\nconst DEFAULT_SERVER_FILE = 'server.js'\nconst DEFAULT_WORKFLOW_FILE = 'workflow.spec.json'\nconst DEFAULT_MANIFEST_OUTPUT = 'convilyn.manifest.json'\n\n/** `synth`: load the server and write its manifest. */\nexport async function runSynth(options: {\n file?: string\n output?: string\n}): Promise<{ path: string; toolCount: number; toolNames: string[] }> {\n const server = await loadToolServer(options.file ?? DEFAULT_SERVER_FILE)\n const manifest = server.manifest()\n const path = await manifest.save(options.output ?? DEFAULT_MANIFEST_OUTPUT)\n return { path, toolCount: manifest.tools.length, toolNames: manifest.tools.map((t) => t.name) }\n}\n\n/** `dev`: load the server and start the local JSON-RPC `/mcp` runtime. */\nexport async function runDev(options: {\n file?: string\n host?: string\n port?: number\n hmacSecret?: string\n}): Promise<Server> {\n const server = await loadToolServer(options.file ?? DEFAULT_SERVER_FILE)\n return serve(server, {\n host: options.host,\n port: options.port,\n hmacSecret: options.hmacSecret,\n // `dev` IS the explicit insecure-local opt-in (mirror of the Python\n // CLI's run(dev=True)). A configured secret still wins — the opt-in\n // never bypasses verification.\n allowInsecure: true,\n })\n}\n\n/** `test`: load the server and run the local compliance suite. */\nexport async function runTest(options: { file?: string }): Promise<ComplianceReport> {\n const server = await loadToolServer(options.file ?? DEFAULT_SERVER_FILE)\n return runComplianceChecks(server)\n}\n\n/** Combined result of a successful `push` (server + workflow submission). */\nexport interface PushResult {\n serverId: string\n serverName: string\n serverStatus: string\n workflowId: string\n workflowSpecId: string\n workflowStatus: string\n}\n\n/**\n * `push`: submit a tool server + workflow to the Developer Portal in one call.\n *\n * Mirrors the Python SDK's `ConvilynClient.push`: synth the manifest → submit\n * the server (registering the caller-hosted `endpoint_url`) → compile the\n * workflow → submit it referencing the new server id. The {@link ConvilynClient}\n * is injectable so this is unit-testable against a fake `fetch` with no network.\n *\n * @throws if `--endpoint-url` is missing, if the server/workflow cannot be\n * loaded, or if the portal rejects a submission (`ConvilynApiError`).\n */\nexport async function runPush(options: {\n file?: string\n workflowFile?: string\n endpointUrl?: string\n client?: ConvilynClient\n}): Promise<PushResult> {\n if (!options.endpointUrl) {\n throw new Error(\n 'push requires --endpoint-url <https://...> — the HTTPS URL where your tool ' +\n 'server is deployed. Use `deploy --hosted` for a Convilyn-hosted server.'\n )\n }\n\n const server = await loadToolServer(options.file ?? DEFAULT_SERVER_FILE)\n const workflow = await loadWorkflowSpec(options.workflowFile ?? DEFAULT_WORKFLOW_FILE)\n const client = options.client ?? new ConvilynClient()\n\n const manifest = server.manifest().toWire()\n const serverResult = await client.submitServer({\n manifest,\n endpoint_url: options.endpointUrl,\n })\n\n const workflowResult = await client.submitWorkflow({\n // CompilableWorkflow.compile() is typed `unknown` (the file loader duck-types\n // both a built WorkflowSpec and a pre-compiled JSON blueprint).\n workflow_spec: workflow.compile() as Record<string, unknown>,\n server_ids: [serverResult.server_id],\n })\n\n return {\n serverId: serverResult.server_id,\n serverName: serverResult.server_name,\n serverStatus: serverResult.status,\n workflowId: workflowResult.workflow_id,\n workflowSpecId: workflowResult.spec_id,\n workflowStatus: workflowResult.status,\n }\n}\n\n/** Result of a successful `deploy --hosted`. */\nexport interface DeployResult {\n runtimeId: string\n endpointUrl: string | null\n status: string\n region: string\n version: number\n workflowId?: string\n workflowIncluded: boolean\n}\n\n/**\n * `deploy --hosted`: hand the server manifest (plus the compiled workflow\n * spec, when the workflow file exists) to the platform, which provisions a\n * sandboxed runtime in Convilyn's cloud (mirror of the Python CLI `deploy`).\n *\n * Without `--hosted` the command errors and points at `push` — BYO\n * deployments stay on `push --endpoint-url` so one subcommand never has two\n * meanings. The workflow file is optional and silently skipped when absent\n * (Python-CLI parity).\n */\nexport async function runDeploy(options: {\n file?: string\n workflowFile?: string\n hosted?: boolean\n region?: string\n client?: ConvilynClient\n}): Promise<DeployResult> {\n if (!options.hosted) {\n throw new Error(\n 'deploy currently requires --hosted. Use ' +\n '`convilyn-author push --endpoint-url <https://...>` for ' +\n 'caller-deployed (BYO) servers.'\n )\n }\n\n const server = await loadToolServer(options.file ?? DEFAULT_SERVER_FILE)\n const manifest = server.manifest().toWire()\n\n const workflowFile = options.workflowFile ?? DEFAULT_WORKFLOW_FILE\n let workflowSpec: Record<string, unknown> | undefined\n if (\n await stat(workflowFile).then(\n () => true,\n () => false\n )\n ) {\n const workflow = await loadWorkflowSpec(workflowFile)\n workflowSpec = workflow.compile() as Record<string, unknown>\n }\n\n const client = options.client ?? new ConvilynClient()\n const result = await client.deployHostedRuntime(manifest, {\n region: options.region ?? 'us-east-1',\n ...(workflowSpec !== undefined ? { workflowSpec } : {}),\n })\n\n return {\n runtimeId: result.runtime_id,\n endpointUrl: result.endpoint_url ?? null,\n status: result.status,\n region: result.region,\n version: result.version,\n ...(result.workflow_id != null ? { workflowId: result.workflow_id } : {}),\n workflowIncluded: workflowSpec !== undefined,\n }\n}\n\n/** `rollback <runtimeId>`: flip a hosted runtime to its previous version. */\nexport async function runRollback(options: {\n runtimeId: string\n client?: ConvilynClient\n}): Promise<RollbackResponse> {\n const client = options.client ?? new ConvilynClient()\n return client.rollbackHostedRuntime(options.runtimeId)\n}\n\n/** `logs <runtimeId>`: fetch recent log lines for a hosted runtime. */\nexport async function runLogs(options: {\n runtimeId: string\n since?: string\n limit?: number\n client?: ConvilynClient\n}): Promise<RuntimeLogEntry[]> {\n const client = options.client ?? new ConvilynClient()\n return client.getHostedRuntimeLogs(options.runtimeId, {\n ...(options.since !== undefined ? { since: options.since } : {}),\n ...(options.limit !== undefined ? { limit: options.limit } : {}),\n })\n}\n","/**\n * Builds the `convilyn-author` commander program. Kept separate from the `bin`\n * entry (`../cli.ts`) so it can be constructed with an injected {@link Printer}\n * and parsed in tests without touching the real process streams.\n *\n * Command cores live in `./commands`; the actions here only translate their\n * return values into printed output + exit codes.\n */\n\nimport { Command } from 'commander'\nimport { VERSION } from '../version'\nimport { ConvilynApiError } from '../errors'\nimport { allChecksPassed } from '../types'\nimport { consolePrinter, type Printer } from './print'\nimport { scaffoldProject } from './scaffold'\nimport { runDeploy, runDev, runLogs, runPush, runRollback, runSynth, runTest } from './commands'\n\nfunction fail(printer: Printer, err: unknown): void {\n printer.err(`error: ${(err as Error).message}`)\n process.exitCode = 1\n}\n\n/** Hosted-runtime error printer: 501/503 get the BYO-fallback hint (Python parity). */\nfunction failHosted(printer: Printer, err: unknown): void {\n if (err instanceof ConvilynApiError && (err.status === 501 || err.status === 503)) {\n printer.err(\n `error: hosted runtime not yet available on this platform (${err.message}). ` +\n 'Use `convilyn-author push --endpoint-url ...` as a BYO fallback.'\n )\n process.exitCode = 1\n return\n }\n fail(printer, err)\n}\n\n/** Construct the CLI program. `printer` defaults to real stdout/stderr. */\nexport function buildProgram(printer: Printer = consolePrinter): Command {\n const program = new Command()\n program\n .name('convilyn-author')\n .description('Author and run Convilyn tool servers.')\n .version(VERSION)\n\n program\n .command('init')\n .description('Scaffold a new tool-server project.')\n .argument('<name>', 'project name (letters, digits, hyphens, underscores)')\n .option('--dir <dir>', 'target directory (default ./<name>)')\n .action(async (name: string, opts: { dir?: string }) => {\n try {\n const result = await scaffoldProject({ name, dir: opts.dir })\n printer.out(`Project created: ${result.path}`)\n printer.out(` ${result.files.join(', ')}`)\n printer.out(` cd ${name} && npm install && npm run build && npx convilyn-author dev`)\n } catch (err) {\n fail(printer, err)\n }\n })\n\n program\n .command('synth')\n .description('Compile the server manifest to JSON.')\n .option('--file <file>', 'built server module (default server.js)')\n .option('--output <output>', 'manifest output path (default convilyn.manifest.json)')\n .action(async (opts: { file?: string; output?: string }) => {\n try {\n const result = await runSynth(opts)\n printer.out(`Found ${result.toolCount} tool(s): ${result.toolNames.join(', ')}`)\n printer.out(`Manifest written: ${result.path}`)\n } catch (err) {\n fail(printer, err)\n }\n })\n\n program\n .command('dev')\n .description('Run the JSON-RPC /mcp server locally.')\n .option('--file <file>', 'built server module (default server.js)')\n .option('--host <host>', 'bind host (default from CONVILYN_HOST)')\n .option('--port <port>', 'bind port (default from CONVILYN_PORT)', (v) => parseInt(v, 10))\n .action(async (opts: { file?: string; host?: string; port?: number }) => {\n try {\n await runDev(opts)\n printer.out('convilyn-author dev: serving /mcp (Ctrl+C to stop)')\n } catch (err) {\n fail(printer, err)\n }\n })\n\n program\n .command('test')\n .description('Run local compliance checks (no platform calls).')\n .option('--file <file>', 'built server module (default server.js)')\n .action(async (opts: { file?: string }) => {\n try {\n const report = await runTest(opts)\n for (const r of report.results) {\n printer.out(` [${r.passed ? 'PASS' : 'FAIL'}] ${r.checkName}: ${r.message}`)\n }\n if (allChecksPassed(report)) {\n printer.out(`All ${report.results.length} checks passed`)\n } else {\n const failed = report.results.filter((r) => !r.passed).length\n printer.err(`${failed} of ${report.results.length} checks failed`)\n process.exitCode = 1\n }\n } catch (err) {\n fail(printer, err)\n }\n })\n\n program\n .command('push')\n .description('Submit a server + workflow to the Developer Portal.')\n .option('--file <file>', 'built server module (default server.js)')\n .option(\n '--workflow-file <file>',\n 'compiled workflow spec or built module (default workflow.spec.json)'\n )\n .option('--endpoint-url <url>', 'HTTPS URL of your deployed server (required)')\n .action(async (opts: { file?: string; workflowFile?: string; endpointUrl?: string }) => {\n try {\n const result = await runPush(opts)\n printer.out(`Server submitted: ${result.serverId} (${result.serverStatus})`)\n printer.out(`Workflow submitted: ${result.workflowId} (${result.workflowStatus})`)\n printer.out('Check verification with the ConvilynClient serverStatus() / workflowStatus().')\n } catch (err) {\n fail(printer, err)\n }\n })\n\n program\n .command('deploy')\n .description('Deploy a tool server to the Convilyn-Hosted Author Runtime.')\n .option('--file <file>', 'built server module (default server.js)')\n .option(\n '--workflow-file <file>',\n 'compiled workflow spec (default workflow.spec.json; optional — skipped when absent)'\n )\n .option('--hosted', 'use the managed runtime (required — BYO uses push)')\n .option('--region <region>', 'AWS region the hosted Lambda is provisioned in', 'us-east-1')\n .action(\n async (opts: { file?: string; workflowFile?: string; hosted?: boolean; region?: string }) => {\n try {\n printer.out(`Deploying to Convilyn-Hosted Runtime in ${opts.region ?? 'us-east-1'}...`)\n const result = await runDeploy(opts)\n printer.out(`Runtime provisioned: ${result.runtimeId} (${result.status})`)\n printer.out(`Endpoint URL: ${result.endpointUrl ?? 'pending (provisioning)'}`)\n if (result.workflowId != null) {\n printer.out(`Workflow registered: ${result.workflowId}`)\n }\n printer.out(\n `Use 'convilyn-author logs ${result.runtimeId}' to follow runtime logs, ` +\n `'convilyn-author rollback ${result.runtimeId}' to revert.`\n )\n } catch (err) {\n failHosted(printer, err)\n }\n }\n )\n\n program\n .command('rollback')\n .description('Roll a hosted runtime back to its previous active version.')\n .argument('<runtimeId>', 'runtime id returned by deploy --hosted')\n .action(async (runtimeId: string) => {\n try {\n printer.out(`Rolling back ${runtimeId}...`)\n const result = await runRollback({ runtimeId })\n printer.out(`Rollback complete: now-active version ${result.version} (${result.status})`)\n } catch (err) {\n fail(printer, err)\n }\n })\n\n program\n .command('logs')\n .description('Fetch recent logs for a hosted runtime.')\n .argument('<runtimeId>', 'runtime id returned by deploy --hosted')\n .option('--since <since>', \"relative window (e.g. '5m', '1h') or ISO-8601 timestamp\")\n .option('--limit <limit>', 'maximum log entries to fetch', (v) => parseInt(v, 10))\n .action(async (runtimeId: string, opts: { since?: string; limit?: number }) => {\n try {\n const entries = await runLogs({ runtimeId, ...opts })\n if (entries.length === 0) {\n printer.out(`No log entries for ${runtimeId} in the requested window.`)\n return\n }\n for (const entry of entries) {\n printer.out(`[${entry.timestamp}] ${entry.level} ${entry.message}`)\n }\n } catch (err) {\n fail(printer, err)\n }\n })\n\n return program\n}\n","#!/usr/bin/env node\n/**\n * `convilyn-author` CLI entry (the package `bin`). Thin by design: it builds the\n * commander program (see `./cli/program`) and parses argv. All logic lives in\n * `./cli/*` so it is unit-testable without spawning a process.\n */\n\nimport { buildProgram } from './cli/program'\n\n// No top-level await: the bin is emitted as CJS (dist/cli.cjs), where TLA is illegal.\nbuildProgram()\n .parseAsync(process.argv)\n .catch((err: unknown) => {\n process.stderr.write(`error: ${(err as Error).message}\\n`)\n process.exitCode = 1\n })\n"]}
|