@ghl-ai/aw 0.1.50-beta.1 → 0.1.50
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/c4/templates/scripts/aw-c4-bootstrap.sh +4 -5
- package/cli.mjs +9 -21
- package/commands/c4.mjs +9 -17
- package/commands/doctor.mjs +5 -2
- package/commands/init.mjs +54 -125
- package/commands/integration.mjs +111 -0
- package/commands/nuke.mjs +3 -1
- package/commands/pull.mjs +2 -3
- package/commands/push.mjs +29 -715
- package/commands/startup.mjs +3 -22
- package/constants.mjs +0 -23
- package/ecc.mjs +1 -1
- package/git.mjs +4 -19
- package/integrate.mjs +21 -94
- package/integrations/context-mode.mjs +514 -0
- package/integrations/index.mjs +31 -0
- package/link.mjs +33 -159
- package/mcp.mjs +16 -132
- package/package.json +4 -4
- package/render-rules.mjs +1 -25
- package/startup.mjs +8 -52
- package/commands/integrations.mjs +0 -254
- package/commands/mcp.mjs +0 -90
- package/integrations.mjs +0 -971
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
// commands/integrations.mjs — CLI command: aw integrations add/remove/list/bundle
|
|
2
|
-
|
|
3
|
-
import * as p from '@clack/prompts';
|
|
4
|
-
import * as fmt from '../fmt.mjs';
|
|
5
|
-
import { chalk } from '../fmt.mjs';
|
|
6
|
-
import {
|
|
7
|
-
INTEGRATIONS,
|
|
8
|
-
BUNDLES,
|
|
9
|
-
installIntegration,
|
|
10
|
-
removeIntegration,
|
|
11
|
-
getInstalledList,
|
|
12
|
-
} from '../integrations.mjs';
|
|
13
|
-
|
|
14
|
-
export async function integrationsCommand(args) {
|
|
15
|
-
const subcommand = args._positional[0];
|
|
16
|
-
|
|
17
|
-
switch (subcommand) {
|
|
18
|
-
case 'add':
|
|
19
|
-
return cmdAdd(args);
|
|
20
|
-
case 'remove':
|
|
21
|
-
return cmdRemove(args);
|
|
22
|
-
case 'bundle':
|
|
23
|
-
return cmdBundle(args);
|
|
24
|
-
case 'list':
|
|
25
|
-
case undefined:
|
|
26
|
-
return cmdList();
|
|
27
|
-
default:
|
|
28
|
-
fmt.cancel(`Unknown subcommand: ${subcommand}`);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// ────────────────────────────────────────────────────────────────────────────────
|
|
33
|
-
// aw integrations list
|
|
34
|
-
// ────────────────────────────────────────────────────────────────────────────────
|
|
35
|
-
|
|
36
|
-
async function cmdList() {
|
|
37
|
-
fmt.banner('Integrations', {
|
|
38
|
-
icon: '🔗',
|
|
39
|
-
subtitle: ' Available tools and MCP servers',
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
const installed = getInstalledList();
|
|
43
|
-
|
|
44
|
-
// Group by type
|
|
45
|
-
const plugins = Object.entries(INTEGRATIONS).filter(
|
|
46
|
-
([, i]) => i.type === 'plugin'
|
|
47
|
-
);
|
|
48
|
-
const remoteRcps = Object.entries(INTEGRATIONS).filter(
|
|
49
|
-
([, i]) => i.type === 'remote-mcp'
|
|
50
|
-
);
|
|
51
|
-
const universalInstallers = Object.entries(INTEGRATIONS).filter(
|
|
52
|
-
([, i]) => i.type === 'universal-installer'
|
|
53
|
-
);
|
|
54
|
-
const pythonClis = Object.entries(INTEGRATIONS).filter(
|
|
55
|
-
([, i]) => i.type === 'python-cli'
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
const typeIcon = (type) =>
|
|
59
|
-
type === 'plugin' ? '🔌' : type === 'remote-mcp' ? '🌐' : type === 'universal-installer' ? '🪨' : '⚙️';
|
|
60
|
-
|
|
61
|
-
// Installed section
|
|
62
|
-
if (installed.length > 0) {
|
|
63
|
-
fmt.logMessage(`\n${chalk.bold.underline('Installed')}`);
|
|
64
|
-
for (const key of installed) {
|
|
65
|
-
const integration = INTEGRATIONS[key];
|
|
66
|
-
if (!integration) continue;
|
|
67
|
-
fmt.logSuccess(` ${typeIcon(integration.type)} ${integration.label}`);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Available Plugins
|
|
72
|
-
fmt.logMessage(`\n${chalk.bold.underline('Available Plugins')}`);
|
|
73
|
-
for (const [key, integration] of plugins) {
|
|
74
|
-
if (!installed.includes(key)) {
|
|
75
|
-
fmt.logMessage(
|
|
76
|
-
` 🔌 ${integration.label.padEnd(25)} — ${integration.description}`
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Available Remote MCPs
|
|
82
|
-
fmt.logMessage(`\n${chalk.bold.underline('Available Remote MCPs')}`);
|
|
83
|
-
for (const [key, integration] of remoteRcps) {
|
|
84
|
-
if (!installed.includes(key)) {
|
|
85
|
-
fmt.logMessage(
|
|
86
|
-
` 🌐 ${integration.label.padEnd(25)} — ${integration.description}`
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Universal Installers
|
|
92
|
-
if (universalInstallers.length > 0) {
|
|
93
|
-
fmt.logMessage(`\n${chalk.bold.underline('Universal Tools')}`);
|
|
94
|
-
for (const [key, integration] of universalInstallers) {
|
|
95
|
-
if (!installed.includes(key)) {
|
|
96
|
-
fmt.logMessage(
|
|
97
|
-
` 🪨 ${integration.label.padEnd(25)} — ${integration.description}`
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Python CLIs
|
|
104
|
-
if (pythonClis.length > 0) {
|
|
105
|
-
fmt.logMessage(`\n${chalk.bold.underline('Available Python Tools')}`);
|
|
106
|
-
for (const [key, integration] of pythonClis) {
|
|
107
|
-
if (!installed.includes(key)) {
|
|
108
|
-
fmt.logMessage(
|
|
109
|
-
` 🐍 ${integration.label.padEnd(25)} — ${integration.description}`
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Bundles
|
|
116
|
-
fmt.logMessage(`\n${chalk.bold.underline('Bundles')}`);
|
|
117
|
-
for (const [bundleKey, bundle] of Object.entries(BUNDLES)) {
|
|
118
|
-
fmt.logMessage(
|
|
119
|
-
` 📦 ${bundle.label.padEnd(25)} — ${bundle.description}`
|
|
120
|
-
);
|
|
121
|
-
fmt.logMessage(
|
|
122
|
-
` Includes: ${bundle.includes.map((k) => INTEGRATIONS[k].label).join(', ')}`
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
fmt.logMessage(`\n${chalk.dim('Commands:')}`);
|
|
127
|
-
fmt.logMessage(` aw integrations add <key> Install a specific tool`);
|
|
128
|
-
fmt.logMessage(` aw integrations remove <key> Remove a tool`);
|
|
129
|
-
fmt.logMessage(` aw integrations bundle <name> Install a preset bundle`);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// ────────────────────────────────────────────────────────────────────────────────
|
|
133
|
-
// aw integrations add <key>
|
|
134
|
-
// ────────────────────────────────────────────────────────────────────────────────
|
|
135
|
-
|
|
136
|
-
async function cmdAdd(args) {
|
|
137
|
-
const key = args._positional[1];
|
|
138
|
-
|
|
139
|
-
if (!key) {
|
|
140
|
-
fmt.cancel('Usage: aw integrations add <key>');
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (!INTEGRATIONS[key]) {
|
|
144
|
-
// Suggest similar keys
|
|
145
|
-
const available = Object.keys(INTEGRATIONS);
|
|
146
|
-
fmt.cancel(
|
|
147
|
-
[
|
|
148
|
-
`Unknown integration: ${chalk.red(key)}`,
|
|
149
|
-
'',
|
|
150
|
-
`Available: ${available.join(', ')}`,
|
|
151
|
-
].join('\n')
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const integration = INTEGRATIONS[key];
|
|
156
|
-
fmt.intro(`Installing ${integration.label}`);
|
|
157
|
-
|
|
158
|
-
const success = await installIntegration(key, { silent: false });
|
|
159
|
-
|
|
160
|
-
if (success) {
|
|
161
|
-
fmt.outro(`✓ ${integration.label} installed successfully`);
|
|
162
|
-
} else {
|
|
163
|
-
fmt.cancel(`Failed to install ${integration.label}`);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// ────────────────────────────────────────────────────────────────────────────────
|
|
168
|
-
// aw integrations remove <key>
|
|
169
|
-
// ────────────────────────────────────────────────────────────────────────────────
|
|
170
|
-
|
|
171
|
-
async function cmdRemove(args) {
|
|
172
|
-
const key = args._positional[1];
|
|
173
|
-
|
|
174
|
-
if (!key) {
|
|
175
|
-
fmt.cancel('Usage: aw integrations remove <key>');
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (!INTEGRATIONS[key]) {
|
|
179
|
-
const available = Object.keys(INTEGRATIONS);
|
|
180
|
-
fmt.cancel(
|
|
181
|
-
[
|
|
182
|
-
`Unknown integration: ${chalk.red(key)}`,
|
|
183
|
-
'',
|
|
184
|
-
`Available: ${available.join(', ')}`,
|
|
185
|
-
].join('\n')
|
|
186
|
-
);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
const integration = INTEGRATIONS[key];
|
|
190
|
-
fmt.intro(`Removing ${integration.label}`);
|
|
191
|
-
|
|
192
|
-
const success = await removeIntegration(key, { silent: false });
|
|
193
|
-
|
|
194
|
-
if (success) {
|
|
195
|
-
fmt.outro(`✓ ${integration.label} removed successfully`);
|
|
196
|
-
} else {
|
|
197
|
-
fmt.cancel(`Failed to remove ${integration.label}`);
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// ────────────────────────────────────────────────────────────────────────────────
|
|
202
|
-
// aw integrations bundle <bundleName>
|
|
203
|
-
// ────────────────────────────────────────────────────────────────────────────────
|
|
204
|
-
|
|
205
|
-
async function cmdBundle(args) {
|
|
206
|
-
const bundleName = args._positional[1];
|
|
207
|
-
|
|
208
|
-
if (!bundleName) {
|
|
209
|
-
fmt.cancel('Usage: aw integrations bundle <name>');
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (!BUNDLES[bundleName]) {
|
|
213
|
-
const available = Object.keys(BUNDLES);
|
|
214
|
-
fmt.cancel(
|
|
215
|
-
[
|
|
216
|
-
`Unknown bundle: ${chalk.red(bundleName)}`,
|
|
217
|
-
'',
|
|
218
|
-
`Available: ${available.join(', ')}`,
|
|
219
|
-
].join('\n')
|
|
220
|
-
);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
const bundle = BUNDLES[bundleName];
|
|
224
|
-
fmt.intro(`Installing bundle: ${bundle.label}`);
|
|
225
|
-
|
|
226
|
-
fmt.logMessage(`${bundle.description}\n`);
|
|
227
|
-
fmt.logMessage(`Includes:`);
|
|
228
|
-
for (const key of bundle.includes) {
|
|
229
|
-
const integration = INTEGRATIONS[key];
|
|
230
|
-
fmt.logMessage(` • ${integration.label}`);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
const confirm = await p.default.confirm({
|
|
234
|
-
message: `Continue installing ${bundle.includes.length} tool(s)?`,
|
|
235
|
-
initialValue: true,
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
if (p.default.isCancel(confirm) || !confirm) {
|
|
239
|
-
fmt.cancel('Cancelled');
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
fmt.logMessage('');
|
|
243
|
-
|
|
244
|
-
// Install all
|
|
245
|
-
let successCount = 0;
|
|
246
|
-
for (const key of bundle.includes) {
|
|
247
|
-
const success = await installIntegration(key, { silent: false });
|
|
248
|
-
if (success) successCount++;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
fmt.outro(
|
|
252
|
-
`✓ Bundle installation complete (${successCount}/${bundle.includes.length} installed)`
|
|
253
|
-
);
|
|
254
|
-
}
|
package/commands/mcp.mjs
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { homedir } from 'node:os';
|
|
2
|
-
|
|
3
|
-
import * as fmt from '../fmt.mjs';
|
|
4
|
-
import { chalk } from '../fmt.mjs';
|
|
5
|
-
import {
|
|
6
|
-
getMcpStatus,
|
|
7
|
-
removeMcpConfig,
|
|
8
|
-
saveMcpPreferences,
|
|
9
|
-
setupMcp,
|
|
10
|
-
} from '../mcp.mjs';
|
|
11
|
-
|
|
12
|
-
const HOME = homedir();
|
|
13
|
-
|
|
14
|
-
function isTruthyEnv(value) {
|
|
15
|
-
return ['1', 'true', 'yes', 'on'].includes(String(value || '').trim().toLowerCase());
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export async function mcpCommand(args) {
|
|
19
|
-
const action = String(args._positional?.[0] || 'status').toLowerCase();
|
|
20
|
-
|
|
21
|
-
if (!['status', 'enable', 'disable'].includes(action)) {
|
|
22
|
-
fmt.cancel(`Unknown MCP action: ${action}. Use: aw mcp status|enable|disable`);
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
fmt.intro(`aw mcp ${action}`);
|
|
27
|
-
|
|
28
|
-
if (action === 'status') {
|
|
29
|
-
return renderStatus();
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (action === 'disable') {
|
|
33
|
-
saveMcpPreferences('disabled', HOME);
|
|
34
|
-
const removed = removeMcpConfig();
|
|
35
|
-
const status = getMcpStatus(HOME);
|
|
36
|
-
fmt.outro([
|
|
37
|
-
'⟁ MCP disabled',
|
|
38
|
-
'',
|
|
39
|
-
` ${chalk.green('✓')} Preference saved: ${chalk.dim(status.preferencesPath.replace(`${HOME}/`, '~/'))}`,
|
|
40
|
-
` ${chalk.green('✓')} Removed AW-managed MCP server from ${removed} config file${removed === 1 ? '' : 's'}`,
|
|
41
|
-
].join('\n'));
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
saveMcpPreferences('enabled', HOME);
|
|
46
|
-
const silent = !!args['--silent'] || isTruthyEnv(process.env.CI);
|
|
47
|
-
const updatedFiles = await setupMcp(HOME, null, { silent });
|
|
48
|
-
const status = getMcpStatus(HOME);
|
|
49
|
-
if (status.effectiveMode === 'disabled') {
|
|
50
|
-
fmt.outro([
|
|
51
|
-
'⟁ MCP preference enabled',
|
|
52
|
-
'',
|
|
53
|
-
` ${chalk.green('✓')} Preference saved: ${chalk.dim(status.preferencesPath.replace(`${HOME}/`, '~/'))}`,
|
|
54
|
-
` ${chalk.yellow('!')} ${status.envDisableMcpName}=1 override is still active`,
|
|
55
|
-
].join('\n'));
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
fmt.outro([
|
|
59
|
-
'⟁ MCP enabled',
|
|
60
|
-
'',
|
|
61
|
-
` ${chalk.green('✓')} Preference saved: ${chalk.dim(status.preferencesPath.replace(`${HOME}/`, '~/'))}`,
|
|
62
|
-
updatedFiles.length > 0
|
|
63
|
-
? ` ${chalk.green('✓')} Updated ${updatedFiles.length} MCP config file${updatedFiles.length === 1 ? '' : 's'}`
|
|
64
|
-
: ` ${chalk.dim('Note:')} MCP config files already up to date`,
|
|
65
|
-
].join('\n'));
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function renderStatus() {
|
|
69
|
-
const status = getMcpStatus(HOME);
|
|
70
|
-
const modeLabel = status.envDisableMcp
|
|
71
|
-
? `${status.effectiveMode} (${status.envDisableMcpName}=1 override; saved preference: ${status.mode})`
|
|
72
|
-
: status.mode;
|
|
73
|
-
|
|
74
|
-
fmt.note([
|
|
75
|
-
`${chalk.dim('mode:')} ${modeLabel}`,
|
|
76
|
-
`${chalk.dim('prefs:')} ${status.preferencesPath.replace(`${HOME}/`, '~/')}`,
|
|
77
|
-
`${chalk.dim('claude MCP:')} ${formatHealth(status.claude)}`,
|
|
78
|
-
`${chalk.dim('cursor MCP:')} ${formatHealth(status.cursor)}`,
|
|
79
|
-
`${chalk.dim('codex MCP:')} ${formatHealth(status.codex)}`,
|
|
80
|
-
`${chalk.dim('aw-ecc Codex MCP source:')} ${formatHealth(status.eccCodex)}`,
|
|
81
|
-
].join('\n'), 'MCP');
|
|
82
|
-
|
|
83
|
-
fmt.outro('⟁ MCP status complete');
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function formatHealth(health) {
|
|
87
|
-
if (!health.present) return 'disabled';
|
|
88
|
-
if (health.url && health.authorization) return 'enabled';
|
|
89
|
-
return `incomplete (url=${health.url}, authorization=${health.authorization})`;
|
|
90
|
-
}
|