cli4ai 1.2.0 → 1.2.2
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 +39 -0
- package/dist/bin.d.ts +6 -0
- package/dist/bin.js +105 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.js +335 -0
- package/dist/commands/add.d.ts +11 -0
- package/dist/commands/add.js +464 -0
- package/dist/commands/browse.d.ts +4 -0
- package/dist/commands/browse.js +382 -0
- package/dist/commands/config.d.ts +10 -0
- package/dist/commands/config.js +121 -0
- package/dist/commands/info.d.ts +9 -0
- package/dist/commands/info.js +125 -0
- package/dist/commands/init.d.ts +10 -0
- package/dist/commands/init.js +458 -0
- package/dist/commands/list.d.ts +10 -0
- package/dist/commands/list.js +76 -0
- package/dist/commands/mcp-config.d.ts +10 -0
- package/dist/commands/mcp-config.js +49 -0
- package/dist/commands/remotes.d.ts +22 -0
- package/dist/commands/remotes.js +196 -0
- package/dist/commands/remove.d.ts +8 -0
- package/dist/commands/remove.js +61 -0
- package/dist/commands/routines.d.ts +29 -0
- package/dist/commands/routines.js +363 -0
- package/dist/commands/run.d.ts +12 -0
- package/dist/commands/run.js +104 -0
- package/dist/commands/scheduler.d.ts +27 -0
- package/dist/commands/scheduler.js +350 -0
- package/dist/commands/search.d.ts +9 -0
- package/dist/commands/search.js +162 -0
- package/dist/commands/secrets.d.ts +28 -0
- package/dist/commands/secrets.js +236 -0
- package/dist/commands/serve.d.ts +13 -0
- package/dist/commands/serve.js +49 -0
- package/dist/commands/start.d.ts +8 -0
- package/dist/commands/start.js +27 -0
- package/dist/commands/update.d.ts +17 -0
- package/dist/commands/update.js +210 -0
- package/dist/core/config.d.ts +91 -0
- package/dist/core/config.js +738 -0
- package/dist/core/execute.d.ts +51 -0
- package/dist/core/execute.js +475 -0
- package/dist/core/link.d.ts +39 -0
- package/dist/core/link.js +214 -0
- package/dist/core/lockfile.d.ts +63 -0
- package/dist/core/lockfile.js +140 -0
- package/dist/core/manifest.d.ts +96 -0
- package/dist/core/manifest.js +224 -0
- package/dist/core/registry.d.ts +74 -0
- package/dist/core/registry.js +116 -0
- package/dist/core/remote-client.d.ts +98 -0
- package/dist/core/remote-client.js +252 -0
- package/dist/core/remotes.d.ts +88 -0
- package/dist/core/remotes.js +206 -0
- package/dist/core/routine-engine.d.ts +124 -0
- package/dist/core/routine-engine.js +699 -0
- package/dist/core/routines.d.ts +36 -0
- package/dist/core/routines.js +132 -0
- package/dist/core/scheduler-daemon.d.ts +10 -0
- package/dist/core/scheduler-daemon.js +77 -0
- package/dist/core/scheduler.d.ts +131 -0
- package/dist/core/scheduler.js +492 -0
- package/dist/core/secrets.d.ts +48 -0
- package/dist/core/secrets.js +384 -0
- package/dist/lib/cli.d.ts +84 -0
- package/dist/lib/cli.js +216 -0
- package/dist/mcp/adapter.d.ts +35 -0
- package/dist/mcp/adapter.js +94 -0
- package/dist/mcp/config-gen.d.ts +31 -0
- package/dist/mcp/config-gen.js +75 -0
- package/dist/mcp/server.d.ts +41 -0
- package/dist/mcp/server.js +296 -0
- package/dist/server/service.d.ts +85 -0
- package/dist/server/service.js +304 -0
- package/package.json +6 -3
- package/src/bin.ts +0 -118
- package/src/cli.ts +0 -412
- package/src/commands/add.ts +0 -562
- package/src/commands/browse.ts +0 -449
- package/src/commands/config.ts +0 -154
- package/src/commands/info.ts +0 -133
- package/src/commands/init.ts +0 -514
- package/src/commands/list.ts +0 -95
- package/src/commands/mcp-config.ts +0 -69
- package/src/commands/remotes.ts +0 -253
- package/src/commands/remove.ts +0 -78
- package/src/commands/routines.ts +0 -427
- package/src/commands/run.ts +0 -127
- package/src/commands/scheduler.ts +0 -438
- package/src/commands/search.ts +0 -185
- package/src/commands/secrets.ts +0 -292
- package/src/commands/serve.ts +0 -66
- package/src/commands/start.ts +0 -40
- package/src/commands/update.ts +0 -252
- package/src/core/config.ts +0 -845
- package/src/core/execute.ts +0 -569
- package/src/core/link.ts +0 -246
- package/src/core/lockfile.ts +0 -187
- package/src/core/manifest.ts +0 -327
- package/src/core/registry.ts +0 -165
- package/src/core/remote-client.ts +0 -419
- package/src/core/remotes.ts +0 -268
- package/src/core/routine-engine.ts +0 -895
- package/src/core/routines.ts +0 -171
- package/src/core/scheduler-daemon.ts +0 -94
- package/src/core/scheduler.ts +0 -606
- package/src/core/secrets.ts +0 -430
- package/src/lib/cli.ts +0 -261
- package/src/mcp/adapter.ts +0 -131
- package/src/mcp/config-gen.ts +0 -106
- package/src/mcp/server.ts +0 -365
- package/src/server/service.ts +0 -434
package/src/commands/list.ts
DELETED
|
@@ -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
|
-
}
|
package/src/commands/remotes.ts
DELETED
|
@@ -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
|
-
}
|
package/src/commands/remove.ts
DELETED
|
@@ -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
|
-
}
|