cli4ai 1.2.0 → 1.2.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 (113) hide show
  1. package/README.md +39 -0
  2. package/dist/bin.d.ts +6 -0
  3. package/dist/bin.js +105 -0
  4. package/dist/cli.d.ts +5 -0
  5. package/dist/cli.js +335 -0
  6. package/dist/commands/add.d.ts +11 -0
  7. package/dist/commands/add.js +459 -0
  8. package/dist/commands/browse.d.ts +4 -0
  9. package/dist/commands/browse.js +379 -0
  10. package/dist/commands/config.d.ts +10 -0
  11. package/dist/commands/config.js +121 -0
  12. package/dist/commands/info.d.ts +9 -0
  13. package/dist/commands/info.js +122 -0
  14. package/dist/commands/init.d.ts +10 -0
  15. package/dist/commands/init.js +458 -0
  16. package/dist/commands/list.d.ts +10 -0
  17. package/dist/commands/list.js +76 -0
  18. package/dist/commands/mcp-config.d.ts +10 -0
  19. package/dist/commands/mcp-config.js +49 -0
  20. package/dist/commands/remotes.d.ts +22 -0
  21. package/dist/commands/remotes.js +196 -0
  22. package/dist/commands/remove.d.ts +8 -0
  23. package/dist/commands/remove.js +61 -0
  24. package/dist/commands/routines.d.ts +29 -0
  25. package/dist/commands/routines.js +363 -0
  26. package/dist/commands/run.d.ts +12 -0
  27. package/dist/commands/run.js +104 -0
  28. package/dist/commands/scheduler.d.ts +27 -0
  29. package/dist/commands/scheduler.js +350 -0
  30. package/dist/commands/search.d.ts +9 -0
  31. package/dist/commands/search.js +159 -0
  32. package/dist/commands/secrets.d.ts +28 -0
  33. package/dist/commands/secrets.js +236 -0
  34. package/dist/commands/serve.d.ts +13 -0
  35. package/dist/commands/serve.js +49 -0
  36. package/dist/commands/start.d.ts +8 -0
  37. package/dist/commands/start.js +27 -0
  38. package/dist/commands/update.d.ts +17 -0
  39. package/dist/commands/update.js +210 -0
  40. package/dist/core/config.d.ts +91 -0
  41. package/dist/core/config.js +738 -0
  42. package/dist/core/execute.d.ts +51 -0
  43. package/dist/core/execute.js +475 -0
  44. package/dist/core/link.d.ts +39 -0
  45. package/dist/core/link.js +214 -0
  46. package/dist/core/lockfile.d.ts +63 -0
  47. package/dist/core/lockfile.js +140 -0
  48. package/dist/core/manifest.d.ts +96 -0
  49. package/dist/core/manifest.js +224 -0
  50. package/dist/core/registry.d.ts +74 -0
  51. package/dist/core/registry.js +116 -0
  52. package/dist/core/remote-client.d.ts +98 -0
  53. package/dist/core/remote-client.js +252 -0
  54. package/dist/core/remotes.d.ts +88 -0
  55. package/dist/core/remotes.js +206 -0
  56. package/dist/core/routine-engine.d.ts +124 -0
  57. package/dist/core/routine-engine.js +699 -0
  58. package/dist/core/routines.d.ts +36 -0
  59. package/dist/core/routines.js +132 -0
  60. package/dist/core/scheduler-daemon.d.ts +10 -0
  61. package/dist/core/scheduler-daemon.js +77 -0
  62. package/dist/core/scheduler.d.ts +131 -0
  63. package/dist/core/scheduler.js +492 -0
  64. package/dist/core/secrets.d.ts +48 -0
  65. package/dist/core/secrets.js +384 -0
  66. package/dist/lib/cli.d.ts +84 -0
  67. package/dist/lib/cli.js +216 -0
  68. package/dist/mcp/adapter.d.ts +35 -0
  69. package/dist/mcp/adapter.js +94 -0
  70. package/dist/mcp/config-gen.d.ts +31 -0
  71. package/dist/mcp/config-gen.js +75 -0
  72. package/dist/mcp/server.d.ts +41 -0
  73. package/dist/mcp/server.js +296 -0
  74. package/dist/server/service.d.ts +85 -0
  75. package/dist/server/service.js +304 -0
  76. package/package.json +6 -3
  77. package/src/bin.ts +0 -118
  78. package/src/cli.ts +0 -412
  79. package/src/commands/add.ts +0 -562
  80. package/src/commands/browse.ts +0 -449
  81. package/src/commands/config.ts +0 -154
  82. package/src/commands/info.ts +0 -133
  83. package/src/commands/init.ts +0 -514
  84. package/src/commands/list.ts +0 -95
  85. package/src/commands/mcp-config.ts +0 -69
  86. package/src/commands/remotes.ts +0 -253
  87. package/src/commands/remove.ts +0 -78
  88. package/src/commands/routines.ts +0 -427
  89. package/src/commands/run.ts +0 -127
  90. package/src/commands/scheduler.ts +0 -438
  91. package/src/commands/search.ts +0 -185
  92. package/src/commands/secrets.ts +0 -292
  93. package/src/commands/serve.ts +0 -66
  94. package/src/commands/start.ts +0 -40
  95. package/src/commands/update.ts +0 -252
  96. package/src/core/config.ts +0 -845
  97. package/src/core/execute.ts +0 -569
  98. package/src/core/link.ts +0 -246
  99. package/src/core/lockfile.ts +0 -187
  100. package/src/core/manifest.ts +0 -327
  101. package/src/core/registry.ts +0 -165
  102. package/src/core/remote-client.ts +0 -419
  103. package/src/core/remotes.ts +0 -268
  104. package/src/core/routine-engine.ts +0 -895
  105. package/src/core/routines.ts +0 -171
  106. package/src/core/scheduler-daemon.ts +0 -94
  107. package/src/core/scheduler.ts +0 -606
  108. package/src/core/secrets.ts +0 -430
  109. package/src/lib/cli.ts +0 -261
  110. package/src/mcp/adapter.ts +0 -131
  111. package/src/mcp/config-gen.ts +0 -106
  112. package/src/mcp/server.ts +0 -365
  113. package/src/server/service.ts +0 -434
@@ -1,95 +0,0 @@
1
- /**
2
- * cli4ai list - Show installed packages
3
- */
4
-
5
- import { output, outputError } from '../lib/cli.js';
6
- import {
7
- getGlobalPackages,
8
- getLocalPackages,
9
- getNpmGlobalPackages,
10
- type InstalledPackage
11
- } from '../core/config.js';
12
- import { remoteListPackages, RemoteConnectionError, RemoteApiError } from '../core/remote-client.js';
13
-
14
- interface ListOptions {
15
- global?: boolean;
16
- json?: boolean;
17
- remote?: string;
18
- }
19
-
20
- type PackageWithScope = InstalledPackage & { scope: 'local' | 'cli4ai' | 'npm' };
21
-
22
- export async function listCommand(options: ListOptions): Promise<void> {
23
- // Handle remote listing
24
- if (options.remote) {
25
- try {
26
- const result = await remoteListPackages(options.remote);
27
- output({
28
- remote: options.remote,
29
- packages: result.packages,
30
- count: result.packages.length
31
- });
32
- } catch (err) {
33
- if (err instanceof RemoteConnectionError) {
34
- outputError('NETWORK_ERROR', err.message, { remote: err.remoteName, url: err.url });
35
- } else if (err instanceof RemoteApiError) {
36
- outputError(err.code, err.message, { remote: err.remoteName, details: err.details });
37
- } else {
38
- throw err;
39
- }
40
- }
41
- return;
42
- }
43
-
44
- let packages: PackageWithScope[];
45
-
46
- // Get all package sources
47
- const local = getLocalPackages(process.cwd());
48
- const cli4aiGlobal = getGlobalPackages();
49
- const npmGlobal = getNpmGlobalPackages();
50
-
51
- if (options.global) {
52
- // Only global packages (cli4ai + npm)
53
- const cli4aiNames = new Set(cli4aiGlobal.map(p => p.name));
54
- packages = [
55
- ...cli4aiGlobal.map(p => ({ ...p, scope: 'cli4ai' as const })),
56
- ...npmGlobal.filter(p => !cli4aiNames.has(p.name)).map(p => ({ ...p, scope: 'npm' as const }))
57
- ];
58
- } else {
59
- // All packages: local > cli4ai global > npm global
60
- const seenNames = new Set<string>();
61
-
62
- packages = [];
63
-
64
- for (const pkg of local) {
65
- packages.push({ ...pkg, scope: 'local' as const });
66
- seenNames.add(pkg.name);
67
- }
68
-
69
- for (const pkg of cli4aiGlobal) {
70
- if (!seenNames.has(pkg.name)) {
71
- packages.push({ ...pkg, scope: 'cli4ai' as const });
72
- seenNames.add(pkg.name);
73
- }
74
- }
75
-
76
- for (const pkg of npmGlobal) {
77
- if (!seenNames.has(pkg.name)) {
78
- packages.push({ ...pkg, scope: 'npm' as const });
79
- seenNames.add(pkg.name);
80
- }
81
- }
82
- }
83
-
84
- output({
85
- packages: packages.map(p => ({
86
- name: p.name,
87
- version: p.version,
88
- path: p.path,
89
- source: p.source,
90
- scope: p.scope
91
- })),
92
- count: packages.length,
93
- location: options.global ? 'global' : 'all'
94
- });
95
- }
@@ -1,69 +0,0 @@
1
- /**
2
- * cli4ai mcp-config - Generate MCP configuration for Claude Code
3
- */
4
-
5
- import { output, outputError } from '../lib/cli.js';
6
- import {
7
- generateClaudeCodeConfig,
8
- formatClaudeCodeConfig,
9
- generateConfigSnippet,
10
- generateServerConfig
11
- } from '../mcp/config-gen.js';
12
- import { findPackage } from '../core/config.js';
13
- import { tryLoadManifest } from '../core/manifest.js';
14
-
15
- interface McpConfigOptions {
16
- global?: boolean;
17
- package?: string;
18
- snippet?: boolean;
19
- }
20
-
21
- export async function mcpConfigCommand(options: McpConfigOptions): Promise<void> {
22
- const cwd = process.cwd();
23
-
24
- // Single package snippet mode
25
- if (options.snippet && options.package) {
26
- const pkg = findPackage(options.package, cwd);
27
- if (!pkg) {
28
- outputError('NOT_FOUND', `Package not found: ${options.package}`);
29
- }
30
-
31
- const manifest = tryLoadManifest(pkg!.path);
32
- if (!manifest) {
33
- outputError('MANIFEST_ERROR', `Could not load manifest for ${options.package}`);
34
- }
35
-
36
- if (!manifest!.mcp?.enabled) {
37
- outputError('INVALID_INPUT', `Package ${options.package} does not have MCP enabled`);
38
- }
39
-
40
- const serverName = `cli4ai-${manifest!.name}`;
41
- const serverConfig = generateServerConfig(manifest!, pkg!.path);
42
- const snippet = generateConfigSnippet(manifest!, pkg!.path);
43
- output({
44
- serverName,
45
- serverConfig,
46
- snippet
47
- });
48
- return;
49
- }
50
-
51
- // Generate full config
52
- const packages = options.package ? [options.package] : undefined;
53
- const config = generateClaudeCodeConfig(cwd, {
54
- global: options.global,
55
- packages
56
- });
57
-
58
- if (Object.keys(config.mcpServers).length === 0) {
59
- outputError('NOT_FOUND', 'No MCP-enabled packages found', {
60
- hint: 'Install packages with "cli4ai add <package>" first'
61
- });
62
- }
63
-
64
- // Output formatted config
65
- output({
66
- config,
67
- formatted: formatClaudeCodeConfig(config)
68
- });
69
- }
@@ -1,253 +0,0 @@
1
- /**
2
- * Remote hosts management command.
3
- *
4
- * Manage connections to remote cli4ai instances for distributed execution.
5
- */
6
-
7
- import { output, outputError, log } from '../lib/cli.js';
8
- import {
9
- getRemotes,
10
- getRemote,
11
- addRemote,
12
- updateRemote,
13
- removeRemote,
14
- RemoteNotFoundError,
15
- RemoteAlreadyExistsError,
16
- InvalidRemoteUrlError
17
- } from '../core/remotes.js';
18
- import { testRemoteConnection, remoteListPackages } from '../core/remote-client.js';
19
-
20
- // ═══════════════════════════════════════════════════════════════════════════
21
- // LIST REMOTES
22
- // ═══════════════════════════════════════════════════════════════════════════
23
-
24
- export async function remotesListCommand(): Promise<void> {
25
- const remotes = getRemotes();
26
-
27
- if (remotes.length === 0) {
28
- output({ remotes: [], message: 'No remotes configured. Use "cli4ai remotes add <name> <url>" to add one.' });
29
- return;
30
- }
31
-
32
- output({
33
- remotes: remotes.map(r => ({
34
- name: r.name,
35
- url: r.url,
36
- description: r.description,
37
- hasApiKey: !!r.apiKey,
38
- addedAt: r.addedAt,
39
- lastConnected: r.lastConnected
40
- }))
41
- });
42
- }
43
-
44
- // ═══════════════════════════════════════════════════════════════════════════
45
- // ADD REMOTE
46
- // ═══════════════════════════════════════════════════════════════════════════
47
-
48
- export interface AddRemoteOptions {
49
- apiKey?: string;
50
- description?: string;
51
- test?: boolean;
52
- }
53
-
54
- export async function remotesAddCommand(
55
- name: string,
56
- url: string,
57
- options: AddRemoteOptions
58
- ): Promise<void> {
59
- try {
60
- const remote = addRemote(name, url, {
61
- apiKey: options.apiKey,
62
- description: options.description
63
- });
64
-
65
- log(`Added remote: ${remote.name} -> ${remote.url}`);
66
-
67
- // Test connection if requested
68
- if (options.test !== false) {
69
- log('Testing connection...');
70
- const result = await testRemoteConnection(name);
71
-
72
- if (result.success) {
73
- log(`Connection successful: ${result.message}`);
74
- output({
75
- remote: {
76
- name: remote.name,
77
- url: remote.url,
78
- description: remote.description,
79
- hasApiKey: !!remote.apiKey
80
- },
81
- connectionTest: result
82
- });
83
- } else {
84
- log(`Warning: Connection failed - ${result.message}`);
85
- log('The remote was added but could not be reached. Check the URL and try again.');
86
- output({
87
- remote: {
88
- name: remote.name,
89
- url: remote.url,
90
- description: remote.description,
91
- hasApiKey: !!remote.apiKey
92
- },
93
- connectionTest: result
94
- });
95
- }
96
- } else {
97
- output({
98
- remote: {
99
- name: remote.name,
100
- url: remote.url,
101
- description: remote.description,
102
- hasApiKey: !!remote.apiKey
103
- }
104
- });
105
- }
106
- } catch (err) {
107
- if (err instanceof RemoteAlreadyExistsError) {
108
- outputError('ALREADY_EXISTS', `Remote "${err.remoteName}" already exists. Use "cli4ai remotes update" to modify it.`);
109
- }
110
- if (err instanceof InvalidRemoteUrlError) {
111
- outputError('INVALID_INPUT', `Invalid URL "${err.url}": ${err.reason}`);
112
- }
113
- throw err;
114
- }
115
- }
116
-
117
- // ═══════════════════════════════════════════════════════════════════════════
118
- // UPDATE REMOTE
119
- // ═══════════════════════════════════════════════════════════════════════════
120
-
121
- export interface UpdateRemoteOptions {
122
- url?: string;
123
- apiKey?: string;
124
- description?: string;
125
- }
126
-
127
- export async function remotesUpdateCommand(
128
- name: string,
129
- options: UpdateRemoteOptions
130
- ): Promise<void> {
131
- try {
132
- // Check if any update provided
133
- if (!options.url && !options.apiKey && !options.description) {
134
- outputError('INVALID_INPUT', 'No updates provided. Use --url, --api-key, or --description.');
135
- }
136
-
137
- const remote = updateRemote(name, options);
138
-
139
- output({
140
- updated: true,
141
- remote: {
142
- name: remote.name,
143
- url: remote.url,
144
- description: remote.description,
145
- hasApiKey: !!remote.apiKey
146
- }
147
- });
148
- } catch (err) {
149
- if (err instanceof RemoteNotFoundError) {
150
- outputError('NOT_FOUND', `Remote "${err.remoteName}" not found`);
151
- }
152
- if (err instanceof InvalidRemoteUrlError) {
153
- outputError('INVALID_INPUT', `Invalid URL "${err.url}": ${err.reason}`);
154
- }
155
- throw err;
156
- }
157
- }
158
-
159
- // ═══════════════════════════════════════════════════════════════════════════
160
- // REMOVE REMOTE
161
- // ═══════════════════════════════════════════════════════════════════════════
162
-
163
- export async function remotesRemoveCommand(name: string): Promise<void> {
164
- try {
165
- removeRemote(name);
166
- output({ removed: true, name });
167
- } catch (err) {
168
- if (err instanceof RemoteNotFoundError) {
169
- outputError('NOT_FOUND', `Remote "${err.remoteName}" not found`);
170
- }
171
- throw err;
172
- }
173
- }
174
-
175
- // ═══════════════════════════════════════════════════════════════════════════
176
- // SHOW REMOTE
177
- // ═══════════════════════════════════════════════════════════════════════════
178
-
179
- export async function remotesShowCommand(name: string): Promise<void> {
180
- const remote = getRemote(name);
181
-
182
- if (!remote) {
183
- outputError('NOT_FOUND', `Remote "${name}" not found`);
184
- }
185
-
186
- output({
187
- name: remote.name,
188
- url: remote.url,
189
- description: remote.description,
190
- hasApiKey: !!remote.apiKey,
191
- addedAt: remote.addedAt,
192
- lastConnected: remote.lastConnected
193
- });
194
- }
195
-
196
- // ═══════════════════════════════════════════════════════════════════════════
197
- // TEST REMOTE
198
- // ═══════════════════════════════════════════════════════════════════════════
199
-
200
- export async function remotesTestCommand(name: string): Promise<void> {
201
- const remote = getRemote(name);
202
-
203
- if (!remote) {
204
- outputError('NOT_FOUND', `Remote "${name}" not found`);
205
- }
206
-
207
- log(`Testing connection to ${remote.name} (${remote.url})...`);
208
-
209
- const result = await testRemoteConnection(name);
210
-
211
- if (result.success) {
212
- log(`Connection successful!`);
213
- output({
214
- name,
215
- url: remote.url,
216
- connected: true,
217
- ...result.details
218
- });
219
- } else {
220
- log(`Connection failed: ${result.message}`);
221
- output({
222
- name,
223
- url: remote.url,
224
- connected: false,
225
- error: result.message
226
- });
227
- }
228
- }
229
-
230
- // ═══════════════════════════════════════════════════════════════════════════
231
- // LIST PACKAGES ON REMOTE
232
- // ═══════════════════════════════════════════════════════════════════════════
233
-
234
- export async function remotesPackagesCommand(name: string): Promise<void> {
235
- const remote = getRemote(name);
236
-
237
- if (!remote) {
238
- outputError('NOT_FOUND', `Remote "${name}" not found`);
239
- }
240
-
241
- try {
242
- const result = await remoteListPackages(name);
243
- output({
244
- remote: name,
245
- packages: result.packages
246
- });
247
- } catch (err) {
248
- if (err instanceof Error) {
249
- outputError('API_ERROR', `Failed to list packages on remote "${name}": ${err.message}`);
250
- }
251
- throw err;
252
- }
253
- }
@@ -1,78 +0,0 @@
1
- /**
2
- * cli4ai remove - Uninstall packages
3
- */
4
-
5
- import { existsSync, rmSync, lstatSync, unlinkSync } from 'fs';
6
- import { resolve } from 'path';
7
- import { output, outputError, log } from '../lib/cli.js';
8
- import { PACKAGES_DIR, LOCAL_PACKAGES_DIR } from '../core/config.js';
9
- import { unlockPackage } from '../core/lockfile.js';
10
- import { unlinkPackage as unlinkFromPath } from '../core/link.js';
11
-
12
- interface RemoveOptions {
13
- global?: boolean;
14
- }
15
-
16
- interface RemoveResult {
17
- name: string;
18
- path: string;
19
- }
20
-
21
- const PKG_NAME_PATTERN = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/;
22
-
23
- export async function removeCommand(packages: string[], options: RemoveOptions): Promise<void> {
24
- const results: RemoveResult[] = [];
25
- const errors: { package: string; error: string }[] = [];
26
-
27
- const targetDir = options.global ? PACKAGES_DIR : resolve(process.cwd(), LOCAL_PACKAGES_DIR);
28
- const projectDir = process.cwd();
29
-
30
- for (const pkg of packages) {
31
- if (!PKG_NAME_PATTERN.test(pkg)) {
32
- errors.push({ package: pkg, error: 'Invalid package name' });
33
- continue;
34
- }
35
- const pkgPath = resolve(targetDir, pkg);
36
-
37
- if (!existsSync(pkgPath)) {
38
- errors.push({ package: pkg, error: 'Not installed' });
39
- continue;
40
- }
41
-
42
- try {
43
- const stat = lstatSync(pkgPath);
44
- if (stat.isSymbolicLink()) {
45
- unlinkSync(pkgPath);
46
- } else {
47
- rmSync(pkgPath, { recursive: true });
48
- }
49
-
50
- results.push({ name: pkg, path: pkgPath });
51
-
52
- if (options.global) {
53
- // Remove from PATH
54
- unlinkFromPath(pkg);
55
- log(`- ${pkg} (unlinked from PATH)`);
56
- } else {
57
- log(`- ${pkg}`);
58
- // Update lockfile (only for local/project installs)
59
- unlockPackage(projectDir, pkg);
60
- }
61
- } catch (err) {
62
- errors.push({
63
- package: pkg,
64
- error: err instanceof Error ? err.message : String(err)
65
- });
66
- }
67
- }
68
-
69
- if (errors.length > 0 && results.length === 0) {
70
- outputError('INSTALL_ERROR', 'Failed to remove packages', { errors });
71
- }
72
-
73
- output({
74
- removed: results,
75
- errors: errors.length > 0 ? errors : undefined,
76
- location: options.global ? 'global' : 'local'
77
- });
78
- }