@syrin/cli 1.3.1 → 1.4.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/README.md +36 -0
- package/dist/cli/commands/config.d.ts +47 -0
- package/dist/cli/commands/config.js +360 -0
- package/dist/cli/commands/dev.d.ts +6 -0
- package/dist/cli/commands/dev.js +67 -15
- package/dist/cli/commands/doctor.js +49 -13
- package/dist/cli/commands/init.d.ts +2 -0
- package/dist/cli/commands/init.js +89 -18
- package/dist/cli/commands/status.d.ts +10 -0
- package/dist/cli/commands/status.js +162 -0
- package/dist/cli/index.js +211 -12
- package/dist/cli/prompts/init-prompt.d.ts +18 -0
- package/dist/cli/prompts/init-prompt.js +159 -99
- package/dist/cli/utils/command-error-handler.js +2 -5
- package/dist/config/env-checker.d.ts +12 -2
- package/dist/config/env-checker.js +88 -38
- package/dist/config/env-templates.d.ts +15 -0
- package/dist/config/env-templates.js +49 -0
- package/dist/config/generator.js +17 -0
- package/dist/config/global-loader.d.ts +50 -0
- package/dist/config/global-loader.js +244 -0
- package/dist/config/loader.d.ts +28 -0
- package/dist/config/loader.js +95 -9
- package/dist/config/merger.d.ts +37 -0
- package/dist/config/merger.js +68 -0
- package/dist/config/schema.d.ts +26 -1
- package/dist/config/schema.js +73 -8
- package/dist/config/types.d.ts +19 -0
- package/dist/config/types.js +26 -1
- package/dist/constants/messages.d.ts +7 -0
- package/dist/constants/messages.js +8 -0
- package/dist/constants/paths.d.ts +6 -0
- package/dist/constants/paths.js +10 -0
- package/dist/events/emitter.js +7 -7
- package/dist/index.js +0 -0
- package/dist/presentation/config-ui.d.ts +34 -0
- package/dist/presentation/config-ui.js +139 -0
- package/dist/presentation/doctor-ui.d.ts +11 -0
- package/dist/presentation/doctor-ui.js +52 -1
- package/dist/presentation/init-ui.d.ts +9 -0
- package/dist/presentation/init-ui.js +33 -0
- package/dist/runtime/analysis/analyser.js +2 -2
- package/dist/runtime/analysis/rules/warnings/w104-generic-description.d.ts +1 -1
- package/dist/runtime/analysis/rules/warnings/w104-generic-description.js +1 -1
- package/dist/runtime/dev/event-mapper.js +19 -3
- package/dist/runtime/dev/session.d.ts +4 -0
- package/dist/runtime/dev/session.js +52 -3
- package/dist/runtime/llm/ollama.js +4 -4
- package/dist/runtime/mcp/client/manager.js +3 -3
- package/dist/runtime/sandbox/executor.js +5 -5
- package/dist/runtime/test/orchestrator.js +4 -4
- package/dist/utils/editor.d.ts +37 -0
- package/dist/utils/editor.js +137 -0
- package/dist/utils/logger.d.ts +24 -6
- package/dist/utils/logger.js +51 -8
- package/package.json +4 -4
- package/dist/runtime/analysis/rules/errors/e001-missing-output-schema.d.ts +0 -22
- package/dist/runtime/analysis/rules/errors/e001-missing-output-schema.js +0 -30
- package/dist/runtime/analysis/rules/errors/e002-underspecified-input.d.ts +0 -24
- package/dist/runtime/analysis/rules/errors/e002-underspecified-input.js +0 -52
- package/dist/runtime/analysis/rules/errors/e003-type-mismatch.d.ts +0 -23
- package/dist/runtime/analysis/rules/errors/e003-type-mismatch.js +0 -73
- package/dist/runtime/analysis/rules/errors/e004-free-text-propagation.d.ts +0 -23
- package/dist/runtime/analysis/rules/errors/e004-free-text-propagation.js +0 -47
- package/dist/runtime/analysis/rules/errors/e005-tool-ambiguity.d.ts +0 -25
- package/dist/runtime/analysis/rules/errors/e005-tool-ambiguity.js +0 -73
- package/dist/runtime/analysis/rules/errors/e006-param-not-in-description.d.ts +0 -22
- package/dist/runtime/analysis/rules/errors/e006-param-not-in-description.js +0 -57
- package/dist/runtime/analysis/rules/errors/e007-output-not-guaranteed.d.ts +0 -23
- package/dist/runtime/analysis/rules/errors/e007-output-not-guaranteed.js +0 -56
- package/dist/runtime/analysis/rules/errors/e008-circular-dependency.d.ts +0 -22
- package/dist/runtime/analysis/rules/errors/e008-circular-dependency.js +0 -84
- package/dist/runtime/analysis/rules/errors/e009-implicit-user-input.d.ts +0 -23
- package/dist/runtime/analysis/rules/errors/e009-implicit-user-input.js +0 -89
- package/dist/runtime/analysis/rules/errors/e010-non-serializable.d.ts +0 -25
- package/dist/runtime/analysis/rules/errors/e010-non-serializable.js +0 -46
- package/dist/runtime/analysis/rules/errors/e011-missing-tool-description.d.ts +0 -24
- package/dist/runtime/analysis/rules/errors/e011-missing-tool-description.js +0 -33
- package/dist/runtime/analysis/rules/errors/e012-side-effect-detected.d.ts +0 -39
- package/dist/runtime/analysis/rules/errors/e012-side-effect-detected.js +0 -40
- package/dist/runtime/analysis/rules/errors/e013-non-deterministic-output.d.ts +0 -37
- package/dist/runtime/analysis/rules/errors/e013-non-deterministic-output.js +0 -34
- package/dist/runtime/analysis/rules/errors/e013-output-explosion.d.ts +0 -39
- package/dist/runtime/analysis/rules/errors/e013-output-explosion.js +0 -36
- package/dist/runtime/analysis/rules/errors/e014-hidden-dependency.d.ts +0 -42
- package/dist/runtime/analysis/rules/errors/e014-hidden-dependency.js +0 -46
- package/dist/runtime/analysis/rules/errors/e014-output-explosion.d.ts +0 -39
- package/dist/runtime/analysis/rules/errors/e014-output-explosion.js +0 -36
- package/dist/runtime/analysis/rules/errors/e015-hidden-dependency.d.ts +0 -42
- package/dist/runtime/analysis/rules/errors/e015-hidden-dependency.js +0 -46
- package/dist/runtime/analysis/rules/errors/e015-unbounded-execution.d.ts +0 -44
- package/dist/runtime/analysis/rules/errors/e015-unbounded-execution.js +0 -66
- package/dist/runtime/analysis/rules/errors/e016-output-validation-failed.d.ts +0 -43
- package/dist/runtime/analysis/rules/errors/e016-output-validation-failed.js +0 -42
- package/dist/runtime/analysis/rules/errors/e016-unbounded-execution.d.ts +0 -44
- package/dist/runtime/analysis/rules/errors/e016-unbounded-execution.js +0 -66
- package/dist/runtime/analysis/rules/errors/e017-input-validation-failed.d.ts +0 -57
- package/dist/runtime/analysis/rules/errors/e017-input-validation-failed.js +0 -80
- package/dist/runtime/analysis/rules/errors/e017-output-validation-failed.d.ts +0 -43
- package/dist/runtime/analysis/rules/errors/e017-output-validation-failed.js +0 -42
- package/dist/runtime/analysis/rules/errors/e018-input-validation-failed.d.ts +0 -57
- package/dist/runtime/analysis/rules/errors/e018-input-validation-failed.js +0 -80
- package/dist/runtime/analysis/rules/errors/e018-tool-execution-failed.d.ts +0 -38
- package/dist/runtime/analysis/rules/errors/e018-tool-execution-failed.js +0 -37
- package/dist/runtime/analysis/rules/errors/e019-tool-execution-failed.d.ts +0 -38
- package/dist/runtime/analysis/rules/errors/e019-tool-execution-failed.js +0 -37
- package/dist/runtime/analysis/rules/errors/e019-unexpected-test-result.d.ts +0 -65
- package/dist/runtime/analysis/rules/errors/e019-unexpected-test-result.js +0 -109
- package/dist/runtime/analysis/rules/errors/e020-unexpected-test-result.d.ts +0 -65
- package/dist/runtime/analysis/rules/errors/e020-unexpected-test-result.js +0 -109
- package/dist/runtime/analysis/rules/warnings/w001-implicit-dependency.d.ts +0 -22
- package/dist/runtime/analysis/rules/warnings/w001-implicit-dependency.js +0 -39
- package/dist/runtime/analysis/rules/warnings/w002-free-text-without-normalization.d.ts +0 -24
- package/dist/runtime/analysis/rules/warnings/w002-free-text-without-normalization.js +0 -40
- package/dist/runtime/analysis/rules/warnings/w003-missing-examples.d.ts +0 -22
- package/dist/runtime/analysis/rules/warnings/w003-missing-examples.js +0 -84
- package/dist/runtime/analysis/rules/warnings/w004-overloaded-responsibility.d.ts +0 -23
- package/dist/runtime/analysis/rules/warnings/w004-overloaded-responsibility.js +0 -96
- package/dist/runtime/analysis/rules/warnings/w005-generic-description.d.ts +0 -53
- package/dist/runtime/analysis/rules/warnings/w005-generic-description.js +0 -108
- package/dist/runtime/analysis/rules/warnings/w006-optional-as-required.d.ts +0 -22
- package/dist/runtime/analysis/rules/warnings/w006-optional-as-required.js +0 -44
- package/dist/runtime/analysis/rules/warnings/w007-broad-output-schema.d.ts +0 -23
- package/dist/runtime/analysis/rules/warnings/w007-broad-output-schema.js +0 -37
- package/dist/runtime/analysis/rules/warnings/w008-multiple-entry-points.d.ts +0 -22
- package/dist/runtime/analysis/rules/warnings/w008-multiple-entry-points.js +0 -97
- package/dist/runtime/analysis/rules/warnings/w009-hidden-side-effects.d.ts +0 -23
- package/dist/runtime/analysis/rules/warnings/w009-hidden-side-effects.js +0 -88
- package/dist/runtime/analysis/rules/warnings/w010-output-not-reusable.d.ts +0 -22
- package/dist/runtime/analysis/rules/warnings/w010-output-not-reusable.js +0 -81
- package/dist/runtime/analysis/rules/warnings/w021-weak-schema.d.ts +0 -40
- package/dist/runtime/analysis/rules/warnings/w021-weak-schema.js +0 -32
- package/dist/runtime/analysis/rules/warnings/w022-high-entropy-output.d.ts +0 -39
- package/dist/runtime/analysis/rules/warnings/w022-high-entropy-output.js +0 -36
- package/dist/runtime/analysis/rules/warnings/w023-unstable-defaults.d.ts +0 -38
- package/dist/runtime/analysis/rules/warnings/w023-unstable-defaults.js +0 -36
- package/dist/runtime/test/dependency-tracker.d.ts +0 -66
- package/dist/runtime/test/dependency-tracker.js +0 -80
- package/dist/runtime/test/formatters.d.ts +0 -18
- package/dist/runtime/test/formatters.js +0 -172
- package/dist/runtime/test/input-generator.d.ts +0 -33
- package/dist/runtime/test/input-generator.js +0 -498
- package/dist/runtime/test/mcp-root-detector.d.ts +0 -31
- package/dist/runtime/test/mcp-root-detector.js +0 -105
- package/dist/runtime/test/retry-tester.d.ts +0 -44
- package/dist/runtime/test/retry-tester.js +0 -103
- package/dist/runtime/test/synthetic-input-generator.d.ts +0 -11
- package/dist/runtime/test/synthetic-input-generator.js +0 -154
- package/dist/runtime/test/test-runner.d.ts +0 -28
- package/dist/runtime/test/test-runner.js +0 -55
package/dist/cli/index.js
CHANGED
|
@@ -11,7 +11,9 @@ import { executeAnalyse } from '../cli/commands/analyse.js';
|
|
|
11
11
|
import { executeDev } from '../cli/commands/dev.js';
|
|
12
12
|
import { executeUpdate } from '../cli/commands/update.js';
|
|
13
13
|
import { executeRollback } from '../cli/commands/rollback.js';
|
|
14
|
-
import {
|
|
14
|
+
import { executeStatus } from '../cli/commands/status.js';
|
|
15
|
+
import { executeConfigSet, executeConfigGet, executeConfigList, executeConfigShow, executeConfigEdit, executeConfigEditEnv, executeConfigSetDefault, executeConfigRemove, } from '../cli/commands/config.js';
|
|
16
|
+
import { log, setQuietMode, setVerboseMode } from '../utils/logger.js';
|
|
15
17
|
import { Messages, ListTypes } from '../constants/index.js';
|
|
16
18
|
import { getCurrentVersion } from '../utils/version-checker.js';
|
|
17
19
|
/**
|
|
@@ -19,7 +21,6 @@ import { getCurrentVersion } from '../utils/version-checker.js';
|
|
|
19
21
|
* Logs full error to internal logger and concise message to user.
|
|
20
22
|
*/
|
|
21
23
|
function reportAnalyseError(error) {
|
|
22
|
-
logger.error('Analyse command failed', error);
|
|
23
24
|
log.error(`Analyse command failed: ${error.message}`);
|
|
24
25
|
}
|
|
25
26
|
const program = new Command();
|
|
@@ -32,29 +33,46 @@ export function setupCLI() {
|
|
|
32
33
|
program
|
|
33
34
|
.name('syrin')
|
|
34
35
|
.description('Syrin - Runtime intelligence system for MCP servers')
|
|
35
|
-
.version(currentVersion, '-v, --version', 'Display version number')
|
|
36
|
+
.version(currentVersion, '-v, --version', 'Display version number')
|
|
37
|
+
.option('-q, --quiet', 'Minimal output (errors only)')
|
|
38
|
+
.option('--verbose', 'Verbose output for debugging')
|
|
39
|
+
.hook('preAction', (_thisCommand, actionCommand) => {
|
|
40
|
+
const opts = actionCommand.optsWithGlobals();
|
|
41
|
+
if (opts.quiet) {
|
|
42
|
+
setQuietMode(true);
|
|
43
|
+
}
|
|
44
|
+
if (opts.verbose) {
|
|
45
|
+
setVerboseMode(true);
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
.addHelpText('after', '\nAliases:\n' +
|
|
49
|
+
' ls Alias for list\n' +
|
|
50
|
+
' doc Alias for doctor\n' +
|
|
51
|
+
' cfg Alias for config');
|
|
36
52
|
// init command
|
|
37
53
|
program
|
|
38
54
|
.command('init')
|
|
39
55
|
.description('Initialize a new Syrin project')
|
|
40
56
|
.option('-y, --yes', 'Skip interactive prompts and use default values')
|
|
41
57
|
.option('--project-root <path>', 'Project root directory (defaults to current directory)')
|
|
58
|
+
.option('--global', 'Create global configuration (LLM providers only)')
|
|
42
59
|
.action(async (options) => {
|
|
43
60
|
try {
|
|
44
61
|
await executeInit({
|
|
45
62
|
yes: options.yes || false,
|
|
46
63
|
projectRoot: options.projectRoot,
|
|
64
|
+
global: options.global || false,
|
|
47
65
|
});
|
|
48
66
|
}
|
|
49
67
|
catch (error) {
|
|
50
68
|
// Handle ALREADY_INITIALIZED case first with early return
|
|
51
|
-
if (error instanceof Error &&
|
|
69
|
+
if (error instanceof Error &&
|
|
70
|
+
error.message === 'ALREADY_INITIALIZED') {
|
|
52
71
|
// Already handled in executeInit, just exit
|
|
53
72
|
return;
|
|
54
73
|
}
|
|
55
74
|
// Handle other Error cases
|
|
56
75
|
if (error instanceof Error) {
|
|
57
|
-
logger.error('Init command failed', error);
|
|
58
76
|
log.blank();
|
|
59
77
|
log.error(`Error: ${error.message}`);
|
|
60
78
|
log.blank();
|
|
@@ -67,6 +85,7 @@ export function setupCLI() {
|
|
|
67
85
|
// doctor command
|
|
68
86
|
program
|
|
69
87
|
.command('doctor')
|
|
88
|
+
.alias('doc')
|
|
70
89
|
.description('Validate Syrin project configuration and setup')
|
|
71
90
|
.option('--project-root <path>', 'Project root directory (defaults to current directory)')
|
|
72
91
|
.action(async (options) => {
|
|
@@ -76,8 +95,9 @@ export function setupCLI() {
|
|
|
76
95
|
catch (error) {
|
|
77
96
|
// Error handling is done in executeDoctor, this is a safety net
|
|
78
97
|
if (error instanceof Error) {
|
|
79
|
-
|
|
98
|
+
log.error(`Error: ${error.message}`);
|
|
80
99
|
}
|
|
100
|
+
process.exit(1);
|
|
81
101
|
}
|
|
82
102
|
});
|
|
83
103
|
// test command
|
|
@@ -171,13 +191,15 @@ export function setupCLI() {
|
|
|
171
191
|
catch (error) {
|
|
172
192
|
// Error handling is done in executeTest
|
|
173
193
|
if (error instanceof Error) {
|
|
174
|
-
|
|
194
|
+
log.error(`Error: ${error.message}`);
|
|
195
|
+
process.exit(1);
|
|
175
196
|
}
|
|
176
197
|
}
|
|
177
198
|
});
|
|
178
199
|
// list command
|
|
179
200
|
program
|
|
180
201
|
.command('list')
|
|
202
|
+
.alias('ls')
|
|
181
203
|
.description('List tools, resources, or prompts from an MCP server')
|
|
182
204
|
.argument('[type]', `Type to list: ${ListTypes.TOOLS}, ${ListTypes.RESOURCES}, or ${ListTypes.PROMPTS} (default: ${ListTypes.TOOLS})`, ListTypes.TOOLS)
|
|
183
205
|
.option('--transport <type>', 'Transport type (http or stdio). If not provided, uses transport from config.yaml')
|
|
@@ -216,7 +238,8 @@ export function setupCLI() {
|
|
|
216
238
|
catch (error) {
|
|
217
239
|
// Error handling is done in executeList
|
|
218
240
|
if (error instanceof Error) {
|
|
219
|
-
|
|
241
|
+
log.error(`Error: ${error.message}`);
|
|
242
|
+
process.exit(1);
|
|
220
243
|
}
|
|
221
244
|
}
|
|
222
245
|
});
|
|
@@ -273,6 +296,9 @@ export function setupCLI() {
|
|
|
273
296
|
.option('--save-events', 'Save events to file for debugging')
|
|
274
297
|
.option('--event-file <path>', 'Directory path for event files (default: .syrin/events). Events are saved as {sessionId}.jsonl')
|
|
275
298
|
.option('--run-script', 'Run script to spawn server internally. If not provided, stdio uses script automatically, http connects to existing server')
|
|
299
|
+
.option('--transport <type>', 'Transport type (stdio or http). Required when using global config.')
|
|
300
|
+
.option('--mcp-url <url>', 'MCP server URL (required for http transport when using global config)')
|
|
301
|
+
.option('--script <command>', 'Script command to run MCP server (required for stdio transport when using global config)')
|
|
276
302
|
.action(async (options) => {
|
|
277
303
|
try {
|
|
278
304
|
await executeDev({
|
|
@@ -282,12 +308,16 @@ export function setupCLI() {
|
|
|
282
308
|
saveEvents: options.saveEvents || false,
|
|
283
309
|
eventFile: options.eventFile,
|
|
284
310
|
runScript: options.runScript || false,
|
|
311
|
+
transport: options.transport,
|
|
312
|
+
mcpUrl: options.mcpUrl,
|
|
313
|
+
script: options.script,
|
|
285
314
|
});
|
|
286
315
|
}
|
|
287
316
|
catch (error) {
|
|
288
317
|
// Error handling is done in executeDev
|
|
289
318
|
if (error instanceof Error) {
|
|
290
|
-
|
|
319
|
+
log.error(`Error: ${error.message}`);
|
|
320
|
+
process.exit(1);
|
|
291
321
|
}
|
|
292
322
|
}
|
|
293
323
|
});
|
|
@@ -302,7 +332,8 @@ export function setupCLI() {
|
|
|
302
332
|
catch (error) {
|
|
303
333
|
// Error handling is done in executeUpdate
|
|
304
334
|
if (error instanceof Error) {
|
|
305
|
-
|
|
335
|
+
log.error(`Error: ${error.message}`);
|
|
336
|
+
process.exit(1);
|
|
306
337
|
}
|
|
307
338
|
}
|
|
308
339
|
});
|
|
@@ -318,10 +349,178 @@ export function setupCLI() {
|
|
|
318
349
|
catch (error) {
|
|
319
350
|
// Error handling is done in executeRollback
|
|
320
351
|
if (error instanceof Error) {
|
|
321
|
-
|
|
352
|
+
log.error(`Error: ${error.message}`);
|
|
353
|
+
process.exit(1);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
// status command
|
|
358
|
+
program
|
|
359
|
+
.command('status')
|
|
360
|
+
.description('Show project health overview (config, LLM, MCP connection)')
|
|
361
|
+
.option('--project-root <path>', 'Project root directory (defaults to current directory)')
|
|
362
|
+
.action(async (options) => {
|
|
363
|
+
try {
|
|
364
|
+
await executeStatus(options.projectRoot);
|
|
365
|
+
}
|
|
366
|
+
catch (error) {
|
|
367
|
+
if (error instanceof Error) {
|
|
368
|
+
log.error(`Error: ${error.message}`);
|
|
369
|
+
process.exit(1);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
// config command
|
|
374
|
+
const configCommand = program
|
|
375
|
+
.command('config')
|
|
376
|
+
.alias('cfg')
|
|
377
|
+
.description('Manage Syrin configuration (local or global)');
|
|
378
|
+
// config set
|
|
379
|
+
configCommand
|
|
380
|
+
.command('set')
|
|
381
|
+
.description('Set a configuration value')
|
|
382
|
+
.argument('<key>', 'Configuration key (e.g., "openai.model", "agent_name")')
|
|
383
|
+
.argument('<value>', 'Value to set')
|
|
384
|
+
.option('--global', 'Operate on global config')
|
|
385
|
+
.option('--local', 'Operate on local config')
|
|
386
|
+
.action(async (key, value, options) => {
|
|
387
|
+
try {
|
|
388
|
+
await executeConfigSet(key, value, options);
|
|
389
|
+
}
|
|
390
|
+
catch (error) {
|
|
391
|
+
if (error instanceof Error) {
|
|
392
|
+
log.error(`Error: ${error.message}`);
|
|
393
|
+
}
|
|
394
|
+
process.exit(1);
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
// config get
|
|
398
|
+
configCommand
|
|
399
|
+
.command('get')
|
|
400
|
+
.description('Get a configuration value')
|
|
401
|
+
.argument('<key>', 'Configuration key')
|
|
402
|
+
.option('--global', 'Operate on global config')
|
|
403
|
+
.option('--local', 'Operate on local config')
|
|
404
|
+
.action(async (key, options) => {
|
|
405
|
+
try {
|
|
406
|
+
await executeConfigGet(key, options);
|
|
407
|
+
}
|
|
408
|
+
catch (error) {
|
|
409
|
+
if (error instanceof Error) {
|
|
410
|
+
log.error(`Error: ${error.message}`);
|
|
411
|
+
}
|
|
412
|
+
process.exit(1);
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
// config list
|
|
416
|
+
configCommand
|
|
417
|
+
.command('list')
|
|
418
|
+
.description('List all configuration values')
|
|
419
|
+
.option('--global', 'Operate on global config')
|
|
420
|
+
.option('--local', 'Operate on local config')
|
|
421
|
+
.action(async (options) => {
|
|
422
|
+
try {
|
|
423
|
+
await executeConfigList(options);
|
|
424
|
+
}
|
|
425
|
+
catch (error) {
|
|
426
|
+
if (error instanceof Error) {
|
|
427
|
+
log.error(`Error: ${error.message}`);
|
|
322
428
|
}
|
|
429
|
+
process.exit(1);
|
|
323
430
|
}
|
|
324
431
|
});
|
|
432
|
+
// config show
|
|
433
|
+
configCommand
|
|
434
|
+
.command('show')
|
|
435
|
+
.description('Show full configuration')
|
|
436
|
+
.option('--global', 'Operate on global config')
|
|
437
|
+
.option('--local', 'Operate on local config')
|
|
438
|
+
.action(async (options) => {
|
|
439
|
+
try {
|
|
440
|
+
await executeConfigShow(options);
|
|
441
|
+
}
|
|
442
|
+
catch (error) {
|
|
443
|
+
if (error instanceof Error) {
|
|
444
|
+
log.error(`Error: ${error.message}`);
|
|
445
|
+
}
|
|
446
|
+
process.exit(1);
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
// config edit
|
|
450
|
+
configCommand
|
|
451
|
+
.command('edit')
|
|
452
|
+
.description('Edit configuration file in editor')
|
|
453
|
+
.option('--global', 'Operate on global config')
|
|
454
|
+
.option('--local', 'Operate on local config')
|
|
455
|
+
.action(async (options) => {
|
|
456
|
+
try {
|
|
457
|
+
await executeConfigEdit(options);
|
|
458
|
+
}
|
|
459
|
+
catch (error) {
|
|
460
|
+
if (error instanceof Error) {
|
|
461
|
+
log.error(`Error: ${error.message}`);
|
|
462
|
+
}
|
|
463
|
+
process.exit(1);
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
// config edit-env
|
|
467
|
+
configCommand
|
|
468
|
+
.command('edit-env')
|
|
469
|
+
.description('Edit environment file in editor')
|
|
470
|
+
.option('--global', 'Operate on global config')
|
|
471
|
+
.option('--local', 'Operate on local config')
|
|
472
|
+
.action(async (options) => {
|
|
473
|
+
try {
|
|
474
|
+
await executeConfigEditEnv(options);
|
|
475
|
+
}
|
|
476
|
+
catch (error) {
|
|
477
|
+
if (error instanceof Error) {
|
|
478
|
+
log.error(`Error: ${error.message}`);
|
|
479
|
+
}
|
|
480
|
+
process.exit(1);
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
// config set-default
|
|
484
|
+
configCommand
|
|
485
|
+
.command('set-default')
|
|
486
|
+
.description('Set default LLM provider')
|
|
487
|
+
.argument('<provider>', 'LLM provider name (e.g., openai, claude)')
|
|
488
|
+
.option('--global', 'Operate on global config')
|
|
489
|
+
.option('--local', 'Operate on local config')
|
|
490
|
+
.action(async (provider, options) => {
|
|
491
|
+
try {
|
|
492
|
+
await executeConfigSetDefault(provider, options);
|
|
493
|
+
}
|
|
494
|
+
catch (error) {
|
|
495
|
+
if (error instanceof Error) {
|
|
496
|
+
log.error(`Error: ${error.message}`);
|
|
497
|
+
}
|
|
498
|
+
process.exit(1);
|
|
499
|
+
}
|
|
500
|
+
});
|
|
501
|
+
// config remove
|
|
502
|
+
configCommand
|
|
503
|
+
.command('remove')
|
|
504
|
+
.description('Remove an LLM provider from configuration')
|
|
505
|
+
.argument('<provider>', 'LLM provider name to remove')
|
|
506
|
+
.option('--global', 'Operate on global config')
|
|
507
|
+
.option('--local', 'Operate on local config')
|
|
508
|
+
.action(async (provider, options) => {
|
|
509
|
+
try {
|
|
510
|
+
await executeConfigRemove(provider, options);
|
|
511
|
+
}
|
|
512
|
+
catch (error) {
|
|
513
|
+
if (error instanceof Error) {
|
|
514
|
+
log.error(`Error: ${error.message}`);
|
|
515
|
+
}
|
|
516
|
+
process.exit(1);
|
|
517
|
+
}
|
|
518
|
+
});
|
|
519
|
+
// Handle no command provided - show help and exit with 0
|
|
520
|
+
if (process.argv.length <= 2) {
|
|
521
|
+
program.outputHelp();
|
|
522
|
+
process.exit(0);
|
|
523
|
+
}
|
|
325
524
|
// Parse command line arguments
|
|
326
525
|
program.parse();
|
|
327
526
|
}
|
|
@@ -334,7 +533,7 @@ export function run() {
|
|
|
334
533
|
}
|
|
335
534
|
catch (error) {
|
|
336
535
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
337
|
-
|
|
536
|
+
log.error(`Error: ${err.message}`);
|
|
338
537
|
log.error(Messages.CLI_START_FAILED);
|
|
339
538
|
process.exit(1);
|
|
340
539
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Interactive prompts for the `syrin init` command.
|
|
3
3
|
*/
|
|
4
4
|
import type { InitOptions } from '../../config/types.js';
|
|
5
|
+
import { makeAgentName } from '../../types/factories.js';
|
|
5
6
|
/**
|
|
6
7
|
* Prompt user for project initialization details.
|
|
7
8
|
* @param defaults - Default values for non-interactive mode
|
|
@@ -14,4 +15,21 @@ export declare function promptInitOptions(defaults?: Partial<InitOptions>): Prom
|
|
|
14
15
|
* @returns Default options
|
|
15
16
|
*/
|
|
16
17
|
export declare function getDefaultInitOptions(projectRoot: string): InitOptions;
|
|
18
|
+
/**
|
|
19
|
+
* Global init options (LLM providers only).
|
|
20
|
+
*/
|
|
21
|
+
export interface GlobalInitOptions {
|
|
22
|
+
agentName: ReturnType<typeof makeAgentName>;
|
|
23
|
+
llmProviders: InitOptions['llmProviders'];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Prompt user for global initialization details (LLM providers only).
|
|
27
|
+
* @returns User's answers for global config
|
|
28
|
+
*/
|
|
29
|
+
export declare function promptGlobalInitOptions(): Promise<GlobalInitOptions>;
|
|
30
|
+
/**
|
|
31
|
+
* Create default global init options for non-interactive mode.
|
|
32
|
+
* @returns Default options for global config
|
|
33
|
+
*/
|
|
34
|
+
export declare function getDefaultGlobalInitOptions(): GlobalInitOptions;
|
|
17
35
|
//# sourceMappingURL=init-prompt.d.ts.map
|
|
@@ -6,116 +6,33 @@ import * as path from 'path';
|
|
|
6
6
|
import { makeProjectName, makeAgentName, makeMCPURL, makeAPIKey, makeModelName, makeScriptCommand, } from '../../types/factories.js';
|
|
7
7
|
import { Messages, TransportTypes, LLMProviders, LLMProviderDisplayNames, Defaults, EnvVars, } from '../../constants/index.js';
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
* @param
|
|
11
|
-
* @returns
|
|
9
|
+
* Get LLM provider prompts (shared between init and global init).
|
|
10
|
+
* @param defaultProviders - Default providers to check (for non-interactive mode)
|
|
11
|
+
* @returns Array of inquirer questions for LLM provider configuration
|
|
12
12
|
*/
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const defaultProjectName = defaults?.projectName ||
|
|
16
|
-
currentDirName.replace(/[^a-z0-9-]/gi, '-').toLowerCase();
|
|
17
|
-
const answers = await inquirer.prompt([
|
|
18
|
-
{
|
|
19
|
-
type: 'input',
|
|
20
|
-
name: 'projectName',
|
|
21
|
-
message: 'Project name:',
|
|
22
|
-
default: defaultProjectName,
|
|
23
|
-
validate: (input) => {
|
|
24
|
-
if (!input.trim()) {
|
|
25
|
-
return Messages.PROMPT_PROJECT_NAME_REQUIRED;
|
|
26
|
-
}
|
|
27
|
-
if (!/^[a-z0-9-]+$/i.test(input)) {
|
|
28
|
-
return Messages.PROMPT_PROJECT_NAME_INVALID;
|
|
29
|
-
}
|
|
30
|
-
return true;
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
type: 'input',
|
|
35
|
-
name: 'agentName',
|
|
36
|
-
message: 'Agent name:',
|
|
37
|
-
default: defaults?.agentName
|
|
38
|
-
? String(defaults.agentName)
|
|
39
|
-
: Defaults.AGENT_NAME,
|
|
40
|
-
validate: (input) => {
|
|
41
|
-
if (!input.trim()) {
|
|
42
|
-
return Messages.PROMPT_AGENT_NAME_REQUIRED;
|
|
43
|
-
}
|
|
44
|
-
return true;
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
type: 'list',
|
|
49
|
-
name: 'transport',
|
|
50
|
-
message: 'Transport type:',
|
|
51
|
-
choices: [
|
|
52
|
-
{
|
|
53
|
-
name: `${TransportTypes.STDIO} - Spawn MCP server as a subprocess`,
|
|
54
|
-
value: TransportTypes.STDIO,
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
name: `${TransportTypes.HTTP} - Connect to a running MCP server via HTTP`,
|
|
58
|
-
value: TransportTypes.HTTP,
|
|
59
|
-
},
|
|
60
|
-
],
|
|
61
|
-
default: defaults?.transport || Defaults.TRANSPORT,
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
type: 'input',
|
|
65
|
-
name: 'mcpUrl',
|
|
66
|
-
message: 'MCP server URL:',
|
|
67
|
-
default: defaults?.mcpUrl ? String(defaults.mcpUrl) : Defaults.MCP_URL,
|
|
68
|
-
when: (answers) => answers?.transport === TransportTypes.HTTP,
|
|
69
|
-
validate: (input, answers) => {
|
|
70
|
-
if (answers?.transport === TransportTypes.HTTP) {
|
|
71
|
-
if (!input.trim()) {
|
|
72
|
-
return Messages.PROMPT_MCP_URL_REQUIRED;
|
|
73
|
-
}
|
|
74
|
-
try {
|
|
75
|
-
new URL(input);
|
|
76
|
-
return true;
|
|
77
|
-
}
|
|
78
|
-
catch {
|
|
79
|
-
return Messages.PROMPT_URL_INVALID;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return true;
|
|
83
|
-
},
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
type: 'input',
|
|
87
|
-
name: 'script',
|
|
88
|
-
message: 'Script command to run MCP server:',
|
|
89
|
-
default: defaults?.script ? String(defaults.script) : 'python3 server.py',
|
|
90
|
-
validate: (input) => {
|
|
91
|
-
if (!input.trim()) {
|
|
92
|
-
return Messages.PROMPT_SCRIPT_REQUIRED;
|
|
93
|
-
}
|
|
94
|
-
return true;
|
|
95
|
-
},
|
|
96
|
-
},
|
|
13
|
+
function getLLMProviderPrompts(defaultProviders) {
|
|
14
|
+
return [
|
|
97
15
|
{
|
|
98
16
|
type: 'checkbox',
|
|
99
17
|
name: 'llmProviders',
|
|
100
|
-
message: 'Select LLM providers to configure:',
|
|
18
|
+
message: 'Select LLM providers to configure (SPACE to toggle, ENTER to confirm):',
|
|
101
19
|
choices: [
|
|
102
20
|
{
|
|
103
21
|
name: LLMProviderDisplayNames.OPENAI,
|
|
104
22
|
value: LLMProviders.OPENAI,
|
|
105
|
-
checked: true,
|
|
23
|
+
checked: defaultProviders?.includes(LLMProviders.OPENAI) ?? true,
|
|
106
24
|
},
|
|
107
25
|
{
|
|
108
26
|
name: LLMProviderDisplayNames.CLAUDE,
|
|
109
27
|
value: LLMProviders.CLAUDE,
|
|
28
|
+
checked: defaultProviders?.includes(LLMProviders.CLAUDE) ?? false,
|
|
110
29
|
},
|
|
111
30
|
{
|
|
112
31
|
name: LLMProviderDisplayNames.OLLAMA,
|
|
113
32
|
value: LLMProviders.OLLAMA,
|
|
33
|
+
checked: defaultProviders?.includes(LLMProviders.OLLAMA) ?? false,
|
|
114
34
|
},
|
|
115
35
|
],
|
|
116
|
-
default: defaults?.llmProviders
|
|
117
|
-
? Object.keys(defaults.llmProviders)
|
|
118
|
-
: [LLMProviders.OPENAI],
|
|
119
36
|
validate: (input) => {
|
|
120
37
|
if (input.length === 0) {
|
|
121
38
|
return Messages.PROMPT_LLM_PROVIDER_REQUIRED;
|
|
@@ -198,23 +115,29 @@ export async function promptInitOptions(defaults) {
|
|
|
198
115
|
name: 'defaultProvider',
|
|
199
116
|
message: 'Default LLM provider:',
|
|
200
117
|
choices: (answers) => answers.llmProviders || [],
|
|
201
|
-
default: (answers) => answers.llmProviders?.[0]
|
|
118
|
+
default: (answers) => answers.llmProviders?.[0],
|
|
202
119
|
},
|
|
203
|
-
]
|
|
204
|
-
|
|
120
|
+
];
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Build LLM providers config from answers (shared between init and global init).
|
|
124
|
+
* @param answers - User answers containing LLM provider selections
|
|
125
|
+
* @returns LLM providers configuration object
|
|
126
|
+
*/
|
|
127
|
+
function buildLLMProvidersConfig(answers) {
|
|
205
128
|
const llmProviders = {};
|
|
206
129
|
if (answers.llmProviders.includes('openai')) {
|
|
207
130
|
llmProviders.openai = {
|
|
208
131
|
apiKey: makeAPIKey(answers.openaiApiKey || ''),
|
|
209
132
|
modelName: makeModelName(answers.openaiModel || ''),
|
|
210
|
-
default: answers.defaultProvider === 'openai'
|
|
133
|
+
default: answers.defaultProvider === 'openai',
|
|
211
134
|
};
|
|
212
135
|
}
|
|
213
136
|
if (answers.llmProviders.includes('claude')) {
|
|
214
137
|
llmProviders.claude = {
|
|
215
138
|
apiKey: makeAPIKey(answers.claudeApiKey || ''),
|
|
216
139
|
modelName: makeModelName(answers.claudeModel || ''),
|
|
217
|
-
default: answers.defaultProvider === 'claude'
|
|
140
|
+
default: answers.defaultProvider === 'claude',
|
|
218
141
|
};
|
|
219
142
|
}
|
|
220
143
|
if (answers.llmProviders.includes('ollama')) {
|
|
@@ -222,16 +145,112 @@ export async function promptInitOptions(defaults) {
|
|
|
222
145
|
modelName: answers.ollamaModelName
|
|
223
146
|
? makeModelName(answers.ollamaModelName)
|
|
224
147
|
: undefined,
|
|
225
|
-
default: answers.defaultProvider === 'ollama'
|
|
148
|
+
default: answers.defaultProvider === 'ollama',
|
|
226
149
|
};
|
|
227
150
|
}
|
|
151
|
+
return llmProviders;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Prompt user for project initialization details.
|
|
155
|
+
* @param defaults - Default values for non-interactive mode
|
|
156
|
+
* @returns User's answers
|
|
157
|
+
*/
|
|
158
|
+
export async function promptInitOptions(defaults) {
|
|
159
|
+
const currentDirName = path.basename(process.cwd());
|
|
160
|
+
const defaultProjectName = defaults?.projectName ||
|
|
161
|
+
currentDirName.replace(/[^a-z0-9-]/gi, '-').toLowerCase();
|
|
162
|
+
const projectPrompts = [
|
|
163
|
+
{
|
|
164
|
+
type: 'input',
|
|
165
|
+
name: 'projectName',
|
|
166
|
+
message: 'Project name:',
|
|
167
|
+
default: defaultProjectName,
|
|
168
|
+
validate: (input) => {
|
|
169
|
+
if (!input.trim()) {
|
|
170
|
+
return Messages.PROMPT_PROJECT_NAME_REQUIRED;
|
|
171
|
+
}
|
|
172
|
+
if (!/^[a-z0-9-]+$/i.test(input)) {
|
|
173
|
+
return Messages.PROMPT_PROJECT_NAME_INVALID;
|
|
174
|
+
}
|
|
175
|
+
return true;
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
type: 'input',
|
|
180
|
+
name: 'agentName',
|
|
181
|
+
message: 'Agent name:',
|
|
182
|
+
default: defaults?.agentName
|
|
183
|
+
? String(defaults.agentName)
|
|
184
|
+
: Defaults.AGENT_NAME,
|
|
185
|
+
validate: (input) => {
|
|
186
|
+
if (!input.trim()) {
|
|
187
|
+
return Messages.PROMPT_AGENT_NAME_REQUIRED;
|
|
188
|
+
}
|
|
189
|
+
return true;
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
type: 'list',
|
|
194
|
+
name: 'transport',
|
|
195
|
+
message: 'Transport type:',
|
|
196
|
+
choices: [
|
|
197
|
+
{
|
|
198
|
+
name: `${TransportTypes.STDIO} - Spawn MCP server as a subprocess`,
|
|
199
|
+
value: TransportTypes.STDIO,
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
name: `${TransportTypes.HTTP} - Connect to a running MCP server via HTTP`,
|
|
203
|
+
value: TransportTypes.HTTP,
|
|
204
|
+
},
|
|
205
|
+
],
|
|
206
|
+
default: defaults?.transport || Defaults.TRANSPORT,
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
type: 'input',
|
|
210
|
+
name: 'mcpUrl',
|
|
211
|
+
message: 'MCP server URL:',
|
|
212
|
+
default: defaults?.mcpUrl ? String(defaults.mcpUrl) : Defaults.MCP_URL,
|
|
213
|
+
when: (answers) => answers?.transport === TransportTypes.HTTP,
|
|
214
|
+
validate: (input, answers) => {
|
|
215
|
+
if (answers?.transport === TransportTypes.HTTP) {
|
|
216
|
+
if (!input.trim()) {
|
|
217
|
+
return Messages.PROMPT_MCP_URL_REQUIRED;
|
|
218
|
+
}
|
|
219
|
+
try {
|
|
220
|
+
new URL(input);
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
return Messages.PROMPT_URL_INVALID;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return true;
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
type: 'input',
|
|
232
|
+
name: 'script',
|
|
233
|
+
message: 'Script command to run MCP server:',
|
|
234
|
+
default: defaults?.script ? String(defaults.script) : 'python3 server.py',
|
|
235
|
+
validate: (input) => {
|
|
236
|
+
if (!input.trim()) {
|
|
237
|
+
return Messages.PROMPT_SCRIPT_REQUIRED;
|
|
238
|
+
}
|
|
239
|
+
return true;
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
];
|
|
243
|
+
// Combine project prompts with LLM provider prompts
|
|
244
|
+
const llmPrompts = getLLMProviderPrompts(defaults?.llmProviders ? Object.keys(defaults.llmProviders) : undefined);
|
|
245
|
+
const allPrompts = [...projectPrompts, ...llmPrompts];
|
|
246
|
+
const answers = await inquirer.prompt(allPrompts);
|
|
228
247
|
return {
|
|
229
248
|
projectName: makeProjectName(answers.projectName),
|
|
230
249
|
agentName: makeAgentName(answers.agentName),
|
|
231
250
|
transport: answers.transport,
|
|
232
251
|
mcpUrl: answers.mcpUrl ? makeMCPURL(answers.mcpUrl) : undefined,
|
|
233
252
|
script: makeScriptCommand(answers.script),
|
|
234
|
-
llmProviders,
|
|
253
|
+
llmProviders: buildLLMProvidersConfig(answers),
|
|
235
254
|
nonInteractive: false,
|
|
236
255
|
};
|
|
237
256
|
}
|
|
@@ -260,4 +279,45 @@ export function getDefaultInitOptions(projectRoot) {
|
|
|
260
279
|
nonInteractive: true,
|
|
261
280
|
};
|
|
262
281
|
}
|
|
282
|
+
/**
|
|
283
|
+
* Prompt user for global initialization details (LLM providers only).
|
|
284
|
+
* @returns User's answers for global config
|
|
285
|
+
*/
|
|
286
|
+
export async function promptGlobalInitOptions() {
|
|
287
|
+
const answers = await inquirer.prompt([
|
|
288
|
+
{
|
|
289
|
+
type: 'input',
|
|
290
|
+
name: 'agentName',
|
|
291
|
+
message: 'Agent name:',
|
|
292
|
+
default: Defaults.AGENT_NAME,
|
|
293
|
+
validate: (input) => {
|
|
294
|
+
if (!input.trim()) {
|
|
295
|
+
return Messages.PROMPT_AGENT_NAME_REQUIRED;
|
|
296
|
+
}
|
|
297
|
+
return true;
|
|
298
|
+
},
|
|
299
|
+
},
|
|
300
|
+
...getLLMProviderPrompts(),
|
|
301
|
+
]);
|
|
302
|
+
return {
|
|
303
|
+
agentName: makeAgentName(answers.agentName),
|
|
304
|
+
llmProviders: buildLLMProvidersConfig(answers),
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Create default global init options for non-interactive mode.
|
|
309
|
+
* @returns Default options for global config
|
|
310
|
+
*/
|
|
311
|
+
export function getDefaultGlobalInitOptions() {
|
|
312
|
+
return {
|
|
313
|
+
agentName: makeAgentName(Defaults.AGENT_NAME),
|
|
314
|
+
llmProviders: {
|
|
315
|
+
openai: {
|
|
316
|
+
apiKey: makeAPIKey(EnvVars.OPENAI_API_KEY),
|
|
317
|
+
modelName: makeModelName(EnvVars.OPENAI_MODEL_NAME),
|
|
318
|
+
default: true,
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
};
|
|
322
|
+
}
|
|
263
323
|
//# sourceMappingURL=init-prompt.js.map
|