@soleri/cli 0.0.1 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +98 -0
  2. package/dist/commands/add-domain.d.ts +2 -0
  3. package/dist/commands/add-domain.js +41 -0
  4. package/dist/commands/add-domain.js.map +1 -0
  5. package/dist/commands/create.d.ts +2 -0
  6. package/dist/commands/create.js +68 -0
  7. package/dist/commands/create.js.map +1 -0
  8. package/dist/commands/dev.d.ts +2 -0
  9. package/dist/commands/dev.js +34 -0
  10. package/dist/commands/dev.js.map +1 -0
  11. package/dist/commands/doctor.d.ts +2 -0
  12. package/dist/commands/doctor.js +31 -0
  13. package/dist/commands/doctor.js.map +1 -0
  14. package/dist/commands/hooks.d.ts +2 -0
  15. package/dist/commands/hooks.js +76 -0
  16. package/dist/commands/hooks.js.map +1 -0
  17. package/dist/commands/install-knowledge.d.ts +2 -0
  18. package/dist/commands/install-knowledge.js +43 -0
  19. package/dist/commands/install-knowledge.js.map +1 -0
  20. package/dist/commands/list.d.ts +2 -0
  21. package/dist/commands/list.js +33 -0
  22. package/dist/commands/list.js.map +1 -0
  23. package/dist/hooks/generator.d.ts +15 -0
  24. package/dist/hooks/generator.js +58 -0
  25. package/dist/hooks/generator.js.map +1 -0
  26. package/dist/hooks/templates.d.ts +3 -0
  27. package/dist/hooks/templates.js +156 -0
  28. package/dist/hooks/templates.js.map +1 -0
  29. package/dist/main.d.ts +2 -0
  30. package/dist/main.js +23 -0
  31. package/dist/main.js.map +1 -0
  32. package/dist/prompts/create-wizard.d.ts +6 -0
  33. package/dist/prompts/create-wizard.js +126 -0
  34. package/dist/prompts/create-wizard.js.map +1 -0
  35. package/dist/utils/agent-context.d.ts +12 -0
  36. package/dist/utils/agent-context.js +31 -0
  37. package/dist/utils/agent-context.js.map +1 -0
  38. package/dist/utils/checks.d.ts +12 -0
  39. package/dist/utils/checks.js +138 -0
  40. package/dist/utils/checks.js.map +1 -0
  41. package/dist/utils/logger.d.ts +10 -0
  42. package/dist/utils/logger.js +33 -0
  43. package/dist/utils/logger.js.map +1 -0
  44. package/package.json +40 -4
  45. package/src/__tests__/add-domain.test.ts +117 -0
  46. package/src/__tests__/create.test.ts +92 -0
  47. package/src/__tests__/dev.test.ts +62 -0
  48. package/src/__tests__/doctor.test.ts +121 -0
  49. package/src/__tests__/hooks.test.ts +133 -0
  50. package/src/__tests__/install-knowledge.test.ts +117 -0
  51. package/src/__tests__/list.test.ts +80 -0
  52. package/src/commands/add-domain.ts +46 -0
  53. package/src/commands/create.ts +73 -0
  54. package/src/commands/dev.ts +39 -0
  55. package/src/commands/doctor.ts +33 -0
  56. package/src/commands/hooks.ts +86 -0
  57. package/src/commands/install-knowledge.ts +49 -0
  58. package/src/commands/list.ts +42 -0
  59. package/src/hooks/generator.ts +65 -0
  60. package/src/hooks/templates.ts +185 -0
  61. package/src/main.ts +27 -0
  62. package/src/prompts/create-wizard.ts +129 -0
  63. package/src/utils/agent-context.ts +38 -0
  64. package/src/utils/checks.ts +148 -0
  65. package/src/utils/logger.ts +39 -0
  66. package/tsconfig.json +21 -0
  67. package/vitest.config.ts +8 -0
package/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # @soleri/cli
2
+
3
+ Developer CLI for creating and managing Soleri AI agents.
4
+
5
+ Part of the [Soleri](https://soleri.dev) framework — building AI assistants that learn, remember, and grow with you.
6
+
7
+ ## Quick Start
8
+
9
+ ```bash
10
+ npx @soleri/cli create my-agent
11
+ ```
12
+
13
+ The interactive wizard walks you through agent configuration: name, role, domains, principles, and greeting. When you're done, it scaffolds a complete agent project ready to build and run.
14
+
15
+ ## Commands
16
+
17
+ | Command | Description |
18
+ | --------------------------------- | ------------------------------------------------------ |
19
+ | `soleri create [name]` | Interactive wizard to scaffold a new agent |
20
+ | `soleri list [dir]` | Show agents in a directory |
21
+ | `soleri add-domain <domain>` | Add a knowledge domain to the agent in cwd |
22
+ | `soleri install-knowledge <pack>` | Install knowledge packs from a local path |
23
+ | `soleri dev` | Run agent in development mode (stdio MCP server) |
24
+ | `soleri doctor` | Health check — Node, npm, tsx, agent, deps, build, MCP |
25
+ | `soleri hooks add <editor>` | Generate editor hooks/config files |
26
+ | `soleri hooks remove <editor>` | Remove editor hooks/config files |
27
+ | `soleri hooks list` | Show installed editor hooks |
28
+
29
+ ### Create
30
+
31
+ ```bash
32
+ # Interactive wizard
33
+ soleri create my-agent
34
+
35
+ # Non-interactive with config file
36
+ soleri create --config agent.json
37
+ ```
38
+
39
+ The config file follows the same schema as the wizard output:
40
+
41
+ ```json
42
+ {
43
+ "id": "my-agent",
44
+ "name": "My Agent",
45
+ "role": "Code Review Advisor",
46
+ "description": "Reviews code for quality and security issues.",
47
+ "domains": ["security", "code-quality"],
48
+ "principles": ["Security is not optional"],
49
+ "greeting": "Ready to review.",
50
+ "outputDir": "."
51
+ }
52
+ ```
53
+
54
+ ### Editor Hooks
55
+
56
+ Generate editor-specific configuration files for your agent:
57
+
58
+ ```bash
59
+ soleri hooks add claude-code # .claude/settings.json with lifecycle hooks
60
+ soleri hooks add cursor # .cursorrules
61
+ soleri hooks add windsurf # .windsurfrules
62
+ soleri hooks add copilot # .github/copilot-instructions.md
63
+ ```
64
+
65
+ ### Development Workflow
66
+
67
+ ```bash
68
+ soleri create my-agent # Scaffold
69
+ cd my-agent
70
+ npm install # Install dependencies
71
+ npm run build # Build
72
+ soleri dev # Run locally
73
+ soleri doctor # Verify everything works
74
+ soleri hooks add claude-code # Add editor hooks
75
+ soleri add-domain security # Add a domain later
76
+ ```
77
+
78
+ ## How It Works
79
+
80
+ The CLI wraps [`@soleri/forge`](../forge) — the same scaffolding engine that powers AI-driven agent creation via MCP. The CLI provides a terminal-first interface for the same operations.
81
+
82
+ ## Development
83
+
84
+ ```bash
85
+ # From monorepo root
86
+ npm install
87
+ npm run build --workspace=@soleri/cli
88
+ npm run test --workspace=@soleri/cli
89
+ ```
90
+
91
+ ## Requirements
92
+
93
+ - Node.js 18+
94
+ - npm 8+
95
+
96
+ ## License
97
+
98
+ Apache-2.0
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerAddDomain(program: Command): void;
@@ -0,0 +1,41 @@
1
+ import * as p from '@clack/prompts';
2
+ import { addDomain } from '@soleri/forge/lib';
3
+ import { detectAgent } from '../utils/agent-context.js';
4
+ export function registerAddDomain(program) {
5
+ program
6
+ .command('add-domain')
7
+ .argument('<domain>', 'Domain name in kebab-case (e.g., "security")')
8
+ .option('--no-build', 'Skip the build step after adding the domain')
9
+ .description('Add a new knowledge domain to the agent in the current directory')
10
+ .action(async (domain, opts) => {
11
+ const ctx = detectAgent();
12
+ if (!ctx) {
13
+ p.log.error('No agent project detected in current directory. Run this from an agent root.');
14
+ process.exit(1);
15
+ }
16
+ const s = p.spinner();
17
+ s.start(`Adding domain "${domain}" to ${ctx.agentId}...`);
18
+ try {
19
+ const result = await addDomain({
20
+ agentPath: ctx.agentPath,
21
+ domain,
22
+ noBuild: !opts.build,
23
+ });
24
+ s.stop(result.success ? result.summary : 'Failed');
25
+ if (result.warnings.length > 0) {
26
+ for (const w of result.warnings) {
27
+ p.log.warn(w);
28
+ }
29
+ }
30
+ if (!result.success) {
31
+ process.exit(1);
32
+ }
33
+ }
34
+ catch (err) {
35
+ s.stop('Failed');
36
+ p.log.error(err instanceof Error ? err.message : String(err));
37
+ process.exit(1);
38
+ }
39
+ });
40
+ }
41
+ //# sourceMappingURL=add-domain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add-domain.js","sourceRoot":"","sources":["../../src/commands/add-domain.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAExD,MAAM,UAAU,iBAAiB,CAAC,OAAgB;IAChD,OAAO;SACJ,OAAO,CAAC,YAAY,CAAC;SACrB,QAAQ,CAAC,UAAU,EAAE,8CAA8C,CAAC;SACpE,MAAM,CAAC,YAAY,EAAE,6CAA6C,CAAC;SACnE,WAAW,CAAC,kEAAkE,CAAC;SAC/E,MAAM,CAAC,KAAK,EAAE,MAAc,EAAE,IAAwB,EAAE,EAAE;QACzD,MAAM,GAAG,GAAG,WAAW,EAAE,CAAC;QAC1B,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,8EAA8E,CAAC,CAAC;YAC5F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;QACtB,CAAC,CAAC,KAAK,CAAC,kBAAkB,MAAM,QAAQ,GAAG,CAAC,OAAO,KAAK,CAAC,CAAC;QAE1D,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC;gBAC7B,SAAS,EAAE,GAAG,CAAC,SAAS;gBACxB,MAAM;gBACN,OAAO,EAAE,CAAC,IAAI,CAAC,KAAK;aACrB,CAAC,CAAC;YAEH,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;YAEnD,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC/B,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;oBAChC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAChB,CAAC;YACH,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACjB,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerCreate(program: Command): void;
@@ -0,0 +1,68 @@
1
+ import { readFileSync, existsSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+ import * as p from '@clack/prompts';
4
+ import { previewScaffold, scaffold, AgentConfigSchema } from '@soleri/forge/lib';
5
+ import { runCreateWizard } from '../prompts/create-wizard.js';
6
+ export function registerCreate(program) {
7
+ program
8
+ .command('create')
9
+ .argument('[name]', 'Agent ID (kebab-case)')
10
+ .option('-c, --config <path>', 'Path to JSON config file (skip interactive prompts)')
11
+ .description('Create a new Soleri agent')
12
+ .action(async (name, opts) => {
13
+ try {
14
+ let config;
15
+ if (opts?.config) {
16
+ // Non-interactive: read from config file
17
+ const configPath = resolve(opts.config);
18
+ if (!existsSync(configPath)) {
19
+ p.log.error(`Config file not found: ${configPath}`);
20
+ process.exit(1);
21
+ }
22
+ const raw = JSON.parse(readFileSync(configPath, 'utf-8'));
23
+ const parsed = AgentConfigSchema.safeParse(raw);
24
+ if (!parsed.success) {
25
+ p.log.error(`Invalid config: ${parsed.error.message}`);
26
+ process.exit(1);
27
+ }
28
+ config = parsed.data;
29
+ }
30
+ else {
31
+ // Interactive wizard
32
+ config = await runCreateWizard(name);
33
+ if (!config) {
34
+ p.outro('Cancelled.');
35
+ return;
36
+ }
37
+ }
38
+ // Preview
39
+ const preview = previewScaffold(config);
40
+ p.log.info(`Will create ${preview.files.length} files in ${preview.agentDir}`);
41
+ p.log.info(`Facades: ${preview.facades.map((f) => f.name).join(', ')}`);
42
+ p.log.info(`Domains: ${preview.domains.join(', ')}`);
43
+ const confirmed = await p.confirm({ message: 'Create agent?' });
44
+ if (p.isCancel(confirmed) || !confirmed) {
45
+ p.outro('Cancelled.');
46
+ return;
47
+ }
48
+ // Scaffold
49
+ const s = p.spinner();
50
+ s.start('Scaffolding agent...');
51
+ const result = scaffold(config);
52
+ s.stop(result.success ? 'Agent created!' : 'Scaffolding failed');
53
+ if (result.success) {
54
+ p.note(result.summary, 'Next steps');
55
+ }
56
+ else {
57
+ p.log.error(result.summary);
58
+ process.exit(1);
59
+ }
60
+ p.outro('Done!');
61
+ }
62
+ catch (err) {
63
+ p.log.error(err instanceof Error ? err.message : String(err));
64
+ process.exit(1);
65
+ }
66
+ });
67
+ }
68
+ //# sourceMappingURL=create.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.js","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerDev(program: Command): void;
@@ -0,0 +1,34 @@
1
+ import { spawn } from 'node:child_process';
2
+ import * as p from '@clack/prompts';
3
+ import { detectAgent } from '../utils/agent-context.js';
4
+ export function registerDev(program) {
5
+ program
6
+ .command('dev')
7
+ .description('Run the agent in development mode (stdio MCP server)')
8
+ .action(() => {
9
+ const ctx = detectAgent();
10
+ if (!ctx) {
11
+ p.log.error('No agent project detected in current directory. Run this from an agent root.');
12
+ process.exit(1);
13
+ }
14
+ p.log.info(`Starting ${ctx.agentId} in dev mode...`);
15
+ const child = spawn('npx', ['tsx', 'src/index.ts'], {
16
+ cwd: ctx.agentPath,
17
+ stdio: 'inherit',
18
+ env: { ...process.env },
19
+ });
20
+ child.on('error', (err) => {
21
+ p.log.error(`Failed to start: ${err.message}`);
22
+ p.log.info('Make sure tsx is available: npm install -g tsx');
23
+ process.exit(1);
24
+ });
25
+ child.on('exit', (code, signal) => {
26
+ if (signal) {
27
+ p.log.warn(`Process terminated by signal ${signal}`);
28
+ process.exit(1);
29
+ }
30
+ process.exit(code ?? 0);
31
+ });
32
+ });
33
+ }
34
+ //# sourceMappingURL=dev.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAExD,MAAM,UAAU,WAAW,CAAC,OAAgB;IAC1C,OAAO;SACJ,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CAAC,sDAAsD,CAAC;SACnE,MAAM,CAAC,GAAG,EAAE;QACX,MAAM,GAAG,GAAG,WAAW,EAAE,CAAC;QAC1B,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,8EAA8E,CAAC,CAAC;YAC5F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC;QAErD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC,EAAE;YAClD,GAAG,EAAE,GAAG,CAAC,SAAS;YAClB,KAAK,EAAE,SAAS;YAChB,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE;SACxB,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACxB,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,oBAAoB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YAC/C,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;YAC7D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE;YAChC,IAAI,MAAM,EAAE,CAAC;gBACX,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,gCAAgC,MAAM,EAAE,CAAC,CAAC;gBACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerDoctor(program: Command): void;
@@ -0,0 +1,31 @@
1
+ import { runAllChecks } from '../utils/checks.js';
2
+ import * as log from '../utils/logger.js';
3
+ export function registerDoctor(program) {
4
+ program
5
+ .command('doctor')
6
+ .description('Check system health and agent project status')
7
+ .action(() => {
8
+ log.heading('Soleri Doctor');
9
+ const results = runAllChecks();
10
+ let hasFailures = false;
11
+ for (const r of results) {
12
+ if (r.status === 'pass')
13
+ log.pass(r.label, r.detail);
14
+ else if (r.status === 'warn')
15
+ log.warn(r.label, r.detail);
16
+ else {
17
+ log.fail(r.label, r.detail);
18
+ hasFailures = true;
19
+ }
20
+ }
21
+ console.log();
22
+ if (hasFailures) {
23
+ log.info('Some checks failed. Fix the issues above and run soleri doctor again.');
24
+ process.exit(1);
25
+ }
26
+ else {
27
+ log.info('All checks passed!');
28
+ }
29
+ });
30
+ }
31
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,KAAK,GAAG,MAAM,oBAAoB,CAAC;AAE1C,MAAM,UAAU,cAAc,CAAC,OAAgB;IAC7C,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,8CAA8C,CAAC;SAC3D,MAAM,CAAC,GAAG,EAAE;QACX,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QAE7B,MAAM,OAAO,GAAG,YAAY,EAAE,CAAC;QAC/B,IAAI,WAAW,GAAG,KAAK,CAAC;QAExB,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM;gBAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;iBAChD,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM;gBAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;iBACrD,CAAC;gBACJ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;gBAC5B,WAAW,GAAG,IAAI,CAAC;YACrB,CAAC;QACH,CAAC;QAED,OAAO,CAAC,GAAG,EAAE,CAAC;QAEd,IAAI,WAAW,EAAE,CAAC;YAChB,GAAG,CAAC,IAAI,CAAC,uEAAuE,CAAC,CAAC;YAClF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QACjC,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerHooks(program: Command): void;
@@ -0,0 +1,76 @@
1
+ import { SUPPORTED_EDITORS } from '../hooks/templates.js';
2
+ import { installHooks, removeHooks, detectInstalledHooks } from '../hooks/generator.js';
3
+ import { detectAgent } from '../utils/agent-context.js';
4
+ import * as log from '../utils/logger.js';
5
+ export function registerHooks(program) {
6
+ const hooks = program.command('hooks').description('Manage editor hooks for this agent');
7
+ hooks
8
+ .command('add')
9
+ .argument('<editor>', `Editor: ${SUPPORTED_EDITORS.join(', ')}`)
10
+ .description('Generate editor hooks/config files')
11
+ .action((editor) => {
12
+ if (!isValidEditor(editor)) {
13
+ log.fail(`Unknown editor "${editor}". Supported: ${SUPPORTED_EDITORS.join(', ')}`);
14
+ process.exit(1);
15
+ }
16
+ const ctx = detectAgent();
17
+ if (!ctx) {
18
+ log.fail('No agent project detected in current directory.');
19
+ process.exit(1);
20
+ }
21
+ const files = installHooks(editor, ctx.agentPath);
22
+ for (const f of files) {
23
+ log.pass(`Created ${f}`);
24
+ }
25
+ log.info(`${editor} hooks installed for ${ctx.agentId}`);
26
+ });
27
+ hooks
28
+ .command('remove')
29
+ .argument('<editor>', `Editor: ${SUPPORTED_EDITORS.join(', ')}`)
30
+ .description('Remove editor hooks/config files')
31
+ .action((editor) => {
32
+ if (!isValidEditor(editor)) {
33
+ log.fail(`Unknown editor "${editor}". Supported: ${SUPPORTED_EDITORS.join(', ')}`);
34
+ process.exit(1);
35
+ }
36
+ const ctx = detectAgent();
37
+ if (!ctx) {
38
+ log.fail('No agent project detected in current directory.');
39
+ process.exit(1);
40
+ }
41
+ const removed = removeHooks(editor, ctx.agentPath);
42
+ if (removed.length === 0) {
43
+ log.info(`No ${editor} hooks found to remove.`);
44
+ }
45
+ else {
46
+ for (const f of removed) {
47
+ log.warn(`Removed ${f}`);
48
+ }
49
+ log.info(`${editor} hooks removed from ${ctx.agentId}`);
50
+ }
51
+ });
52
+ hooks
53
+ .command('list')
54
+ .description('Show which editor hooks are installed')
55
+ .action(() => {
56
+ const ctx = detectAgent();
57
+ if (!ctx) {
58
+ log.fail('No agent project detected in current directory.');
59
+ process.exit(1);
60
+ }
61
+ const installed = detectInstalledHooks(ctx.agentPath);
62
+ log.heading(`Editor hooks for ${ctx.agentId}`);
63
+ for (const editor of SUPPORTED_EDITORS) {
64
+ if (installed.includes(editor)) {
65
+ log.pass(editor, 'installed');
66
+ }
67
+ else {
68
+ log.dim(` ${editor} — not installed`);
69
+ }
70
+ }
71
+ });
72
+ }
73
+ function isValidEditor(editor) {
74
+ return SUPPORTED_EDITORS.includes(editor);
75
+ }
76
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/commands/hooks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerInstallKnowledge(program: Command): void;
@@ -0,0 +1,43 @@
1
+ import { resolve } from 'node:path';
2
+ import * as p from '@clack/prompts';
3
+ import { installKnowledge } from '@soleri/forge/lib';
4
+ import { detectAgent } from '../utils/agent-context.js';
5
+ export function registerInstallKnowledge(program) {
6
+ program
7
+ .command('install-knowledge')
8
+ .argument('<pack>', 'Path to knowledge bundle file or directory')
9
+ .option('--no-facades', 'Skip facade generation for new domains')
10
+ .description('Install knowledge packs into the agent in the current directory')
11
+ .action(async (pack, opts) => {
12
+ const ctx = detectAgent();
13
+ if (!ctx) {
14
+ p.log.error('No agent project detected in current directory. Run this from an agent root.');
15
+ process.exit(1);
16
+ }
17
+ const bundlePath = resolve(pack);
18
+ const s = p.spinner();
19
+ s.start(`Installing knowledge from ${bundlePath}...`);
20
+ try {
21
+ const result = await installKnowledge({
22
+ agentPath: ctx.agentPath,
23
+ bundlePath,
24
+ generateFacades: opts.facades,
25
+ });
26
+ s.stop(result.success ? result.summary : 'Installation failed');
27
+ if (result.warnings.length > 0) {
28
+ for (const w of result.warnings) {
29
+ p.log.warn(w);
30
+ }
31
+ }
32
+ if (!result.success) {
33
+ process.exit(1);
34
+ }
35
+ }
36
+ catch (err) {
37
+ s.stop('Installation failed');
38
+ p.log.error(err instanceof Error ? err.message : String(err));
39
+ process.exit(1);
40
+ }
41
+ });
42
+ }
43
+ //# sourceMappingURL=install-knowledge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-knowledge.js","sourceRoot":"","sources":["../../src/commands/install-knowledge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAExD,MAAM,UAAU,wBAAwB,CAAC,OAAgB;IACvD,OAAO;SACJ,OAAO,CAAC,mBAAmB,CAAC;SAC5B,QAAQ,CAAC,QAAQ,EAAE,4CAA4C,CAAC;SAChE,MAAM,CAAC,cAAc,EAAE,wCAAwC,CAAC;SAChE,WAAW,CAAC,iEAAiE,CAAC;SAC9E,MAAM,CAAC,KAAK,EAAE,IAAY,EAAE,IAA0B,EAAE,EAAE;QACzD,MAAM,GAAG,GAAG,WAAW,EAAE,CAAC;QAC1B,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,8EAA8E,CAAC,CAAC;YAC5F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAEjC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;QACtB,CAAC,CAAC,KAAK,CAAC,6BAA6B,UAAU,KAAK,CAAC,CAAC;QAEtD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC;gBACpC,SAAS,EAAE,GAAG,CAAC,SAAS;gBACxB,UAAU;gBACV,eAAe,EAAE,IAAI,CAAC,OAAO;aAC9B,CAAC,CAAC;YAEH,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC;YAEhE,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC/B,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;oBAChC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAChB,CAAC;YACH,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;YAC9B,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerList(program: Command): void;
@@ -0,0 +1,33 @@
1
+ import { resolve } from 'node:path';
2
+ import { listAgents } from '@soleri/forge/lib';
3
+ import * as log from '../utils/logger.js';
4
+ function pad(s, len) {
5
+ return s.length >= len ? s.slice(0, len) : s + ' '.repeat(len - s.length);
6
+ }
7
+ export function registerList(program) {
8
+ program
9
+ .command('list')
10
+ .argument('[dir]', 'Directory to scan for agents', process.cwd())
11
+ .description('List all Soleri agents in a directory')
12
+ .action((dir) => {
13
+ const targetDir = resolve(dir);
14
+ const agents = listAgents(targetDir);
15
+ if (agents.length === 0) {
16
+ log.info(`No agents found in ${targetDir}`);
17
+ return;
18
+ }
19
+ log.heading(`Agents in ${targetDir}`);
20
+ // Table header
21
+ console.log(` ${pad('ID', 16)}${pad('Domains', 26)}${pad('Built', 8)}${pad('Deps', 8)}Path`);
22
+ console.log(' ' + '-'.repeat(80));
23
+ for (const agent of agents) {
24
+ const built = agent.hasDistDir ? '✓' : '✗';
25
+ const deps = agent.hasNodeModules ? '✓' : '✗';
26
+ const domains = agent.domains.join(', ') || '(none)';
27
+ const truncDomains = domains.length > 25 ? domains.slice(0, 22) + '...' : domains;
28
+ console.log(` ${pad(agent.id, 16)}${pad(truncDomains, 26)}${pad(built, 8)}${pad(deps, 8)}${agent.path}`);
29
+ }
30
+ console.log(`\n ${agents.length} agent(s) found`);
31
+ });
32
+ }
33
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,KAAK,GAAG,MAAM,oBAAoB,CAAC;AAE1C,SAAS,GAAG,CAAC,CAAS,EAAE,GAAW;IACjC,OAAO,CAAC,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAgB;IAC3C,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,QAAQ,CAAC,OAAO,EAAE,8BAA8B,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;SAChE,WAAW,CAAC,uCAAuC,CAAC;SACpD,MAAM,CAAC,CAAC,GAAW,EAAE,EAAE;QACtB,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC/B,MAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;QAErC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,GAAG,CAAC,IAAI,CAAC,sBAAsB,SAAS,EAAE,CAAC,CAAC;YAC5C,OAAO;QACT,CAAC;QAED,GAAG,CAAC,OAAO,CAAC,aAAa,SAAS,EAAE,CAAC,CAAC;QAEtC,eAAe;QACf,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;QAC9F,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;QAEnC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;YAC3C,MAAM,IAAI,GAAG,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;YAC9C,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC;YACrD,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;YAClF,OAAO,CAAC,GAAG,CACT,KAAK,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,YAAY,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAC7F,CAAC;QACJ,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,OAAO,MAAM,CAAC,MAAM,iBAAiB,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { type EditorId } from './templates.js';
2
+ /**
3
+ * Install editor hooks for the given editor.
4
+ * Returns list of files written.
5
+ */
6
+ export declare function installHooks(editor: EditorId, agentPath: string): string[];
7
+ /**
8
+ * Remove editor hooks for the given editor.
9
+ * Returns list of files removed.
10
+ */
11
+ export declare function removeHooks(editor: EditorId, agentPath: string): string[];
12
+ /**
13
+ * Detect which editors have hooks installed.
14
+ */
15
+ export declare function detectInstalledHooks(agentPath: string): EditorId[];
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Hook file generator — writes and removes editor hook files.
3
+ */
4
+ import { existsSync, writeFileSync, unlinkSync, mkdirSync } from 'node:fs';
5
+ import { join, dirname } from 'node:path';
6
+ import { getEditorFiles, SUPPORTED_EDITORS } from './templates.js';
7
+ /**
8
+ * Install editor hooks for the given editor.
9
+ * Returns list of files written.
10
+ */
11
+ export function installHooks(editor, agentPath) {
12
+ const files = getEditorFiles(editor, agentPath);
13
+ const written = [];
14
+ const overwritten = [];
15
+ for (const [relPath, content] of Object.entries(files)) {
16
+ const absPath = join(agentPath, relPath);
17
+ if (existsSync(absPath))
18
+ overwritten.push(relPath);
19
+ mkdirSync(dirname(absPath), { recursive: true });
20
+ writeFileSync(absPath, content, 'utf-8');
21
+ written.push(relPath);
22
+ }
23
+ if (overwritten.length > 0) {
24
+ console.warn(`Warning: overwritten existing file(s): ${overwritten.join(', ')}`);
25
+ }
26
+ return written;
27
+ }
28
+ /**
29
+ * Remove editor hooks for the given editor.
30
+ * Returns list of files removed.
31
+ */
32
+ export function removeHooks(editor, agentPath) {
33
+ const files = getEditorFiles(editor, agentPath);
34
+ const removed = [];
35
+ for (const relPath of Object.keys(files)) {
36
+ const absPath = join(agentPath, relPath);
37
+ if (existsSync(absPath)) {
38
+ unlinkSync(absPath);
39
+ removed.push(relPath);
40
+ }
41
+ }
42
+ return removed;
43
+ }
44
+ /**
45
+ * Detect which editors have hooks installed.
46
+ */
47
+ export function detectInstalledHooks(agentPath) {
48
+ const installed = [];
49
+ for (const editor of SUPPORTED_EDITORS) {
50
+ const files = getEditorFiles(editor, agentPath);
51
+ const allExist = Object.keys(files).every((relPath) => existsSync(join(agentPath, relPath)));
52
+ if (allExist) {
53
+ installed.push(editor);
54
+ }
55
+ }
56
+ return installed;
57
+ }
58
+ //# sourceMappingURL=generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.js","sourceRoot":"","sources":["../../src/hooks/generator.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC3E,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAiB,MAAM,gBAAgB,CAAC;AAElF;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,MAAgB,EAAE,SAAiB;IAC9D,MAAM,KAAK,GAAG,cAAc,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAChD,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,KAAK,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACvD,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACzC,IAAI,UAAU,CAAC,OAAO,CAAC;YAAE,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACnD,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACjD,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACzC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;IACD,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,IAAI,CAAC,0CAA0C,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACnF,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,MAAgB,EAAE,SAAiB;IAC7D,MAAM,KAAK,GAAG,cAAc,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAChD,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACzC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACzC,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YACxB,UAAU,CAAC,OAAO,CAAC,CAAC;YACpB,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,SAAiB;IACpD,MAAM,SAAS,GAAe,EAAE,CAAC;IAEjC,KAAK,MAAM,MAAM,IAAI,iBAAiB,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,cAAc,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QAChD,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;QAC7F,IAAI,QAAQ,EAAE,CAAC;YACb,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export type EditorId = 'claude-code' | 'cursor' | 'windsurf' | 'copilot';
2
+ export declare const SUPPORTED_EDITORS: EditorId[];
3
+ export declare function getEditorFiles(editor: EditorId, dir?: string): Record<string, string>;