@ghl-ai/aw 0.1.44 → 0.1.46
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 +19 -4
- package/cli.mjs +7 -1
- package/commands/init.mjs +17 -0
- package/commands/integrations.mjs +254 -0
- package/integrations.mjs +954 -0
- package/package.json +4 -3
- package/update.mjs +8 -1
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
# @ghl-ai/aw@0.1.x for reproducible CI runs.
|
|
18
18
|
set -Eeuo pipefail
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
# GitHub auth is resolved inside `aw c4` so GITHUB_PAT, GITHUB_TOKEN, and
|
|
21
|
+
# no-token diagnostics stay centralized in the CLI preflight.
|
|
21
22
|
|
|
22
23
|
# Ensure npm is on PATH. Cursor Cloud's install shell is non-interactive — nvm
|
|
23
24
|
# is not auto-sourced, and Node may not be pre-installed at all. Walk common
|
|
@@ -30,6 +31,7 @@ set -Eeuo pipefail
|
|
|
30
31
|
# /usr/local/ or /opt/.
|
|
31
32
|
# - DEBIAN_FRONTEND=noninteractive prevents debconf prompts from hanging
|
|
32
33
|
# the apt configure step on a non-TTY shell.
|
|
34
|
+
# - Run apt-get directly when already root; use sudo only for non-root shells.
|
|
33
35
|
# - Drop the >/dev/null on apt + NodeSource setup so progress is visible.
|
|
34
36
|
# The previous "silent + interactive" combination produced the canonical
|
|
35
37
|
# "looks frozen" symptom in pilot use after Cursor Cloud stopped shipping
|
|
@@ -57,15 +59,28 @@ ensure_npm() {
|
|
|
57
59
|
fi
|
|
58
60
|
done
|
|
59
61
|
|
|
60
|
-
if command -v
|
|
62
|
+
if command -v apt-get >/dev/null 2>&1; then
|
|
61
63
|
echo "[aw-c4-bootstrap] npm not found; installing Node 20 via NodeSource (1-2 min over corporate proxy)"
|
|
62
64
|
export DEBIAN_FRONTEND=noninteractive
|
|
63
|
-
|
|
65
|
+
node_setup_command='curl -fsSL https://deb.nodesource.com/setup_20.x | bash -'
|
|
66
|
+
apt_install_command=(apt-get install -y nodejs)
|
|
67
|
+
current_uid="$(id -u 2>/dev/null || printf '1')"
|
|
68
|
+
if [ "$current_uid" != "0" ]; then
|
|
69
|
+
if command -v sudo >/dev/null 2>&1; then
|
|
70
|
+
node_setup_command='curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -'
|
|
71
|
+
apt_install_command=(sudo -E apt-get install -y nodejs)
|
|
72
|
+
else
|
|
73
|
+
echo "[aw-c4-bootstrap] FATAL: apt-get is available, but sudo is not, and the current user is not root" >&2
|
|
74
|
+
echo "[aw-c4-bootstrap] Run as root, install sudo, or preinstall Node 20+ in the harness snapshot." >&2
|
|
75
|
+
exit 1
|
|
76
|
+
fi
|
|
77
|
+
fi
|
|
78
|
+
if ! timeout 180 bash -c "$node_setup_command"; then
|
|
64
79
|
echo "[aw-c4-bootstrap] FATAL: NodeSource setup script timed out or failed after 180s" >&2
|
|
65
80
|
echo "[aw-c4-bootstrap] Preinstall Node 20+ in the agent snapshot, or check proxy reachability." >&2
|
|
66
81
|
exit 1
|
|
67
82
|
fi
|
|
68
|
-
if ! timeout 180
|
|
83
|
+
if ! timeout 180 "${apt_install_command[@]}"; then
|
|
69
84
|
echo "[aw-c4-bootstrap] FATAL: apt-get install nodejs timed out or failed after 180s" >&2
|
|
70
85
|
exit 1
|
|
71
86
|
fi
|
package/cli.mjs
CHANGED
|
@@ -26,6 +26,7 @@ const COMMANDS = {
|
|
|
26
26
|
nuke: () => import('./commands/nuke.mjs').then(m => m.nukeCommand),
|
|
27
27
|
daemon: () => import('./commands/daemon.mjs').then(m => m.daemonCommand),
|
|
28
28
|
telemetry: () => import('./commands/telemetry.mjs').then(m => m.telemetryCommand),
|
|
29
|
+
integrations: () => import('./commands/integrations.mjs').then(m => m.integrationsCommand),
|
|
29
30
|
'slack-sim': () => import('./commands/slack-sim.mjs').then(m => m.slackSimCommand),
|
|
30
31
|
c4: () => import('./commands/c4.mjs').then(m => m.c4Command),
|
|
31
32
|
'init-repo': () => import('./commands/init-repo.mjs').then(m => m.initRepoCommand),
|
|
@@ -82,8 +83,9 @@ function printHelp() {
|
|
|
82
83
|
const sec = (title) => `\n ${chalk.bold.underline(title)}`;
|
|
83
84
|
const help = [
|
|
84
85
|
sec('Setup'),
|
|
85
|
-
cmd('aw init', 'Initialize workspace (
|
|
86
|
+
cmd('aw init', 'Initialize workspace (auto-installs suggested integrations)'),
|
|
86
87
|
cmd('aw init --namespace <team/sub-team>', 'Add a team namespace (optional)'),
|
|
88
|
+
cmd('aw init --no-integrations', 'Skip integration setup (Codex, Caveman, Graphify, etc)'),
|
|
87
89
|
` ${chalk.dim('Teams: platform, revex, mobile, commerce, leadgen, crm, marketplace, ai')}`,
|
|
88
90
|
` ${chalk.dim('Example: aw init --namespace revex/courses')}`,
|
|
89
91
|
cmd('aw init-repo', 'Scaffold cloud-bootstrap files (idempotent, --dry-run/--force/--diff)'),
|
|
@@ -109,6 +111,10 @@ function printHelp() {
|
|
|
109
111
|
cmd('aw routing status', 'Show global AW session-routing mode for Claude/Cursor/Codex'),
|
|
110
112
|
cmd('aw routing disable', 'Disable automatic AW session routing globally'),
|
|
111
113
|
cmd('aw routing enable', 'Re-enable automatic AW session routing globally'),
|
|
114
|
+
cmd('aw integrations', 'Manage third-party integrations (Codex, Caveman, etc)'),
|
|
115
|
+
cmd('aw integrations add <key>', 'Install a specific tool (e.g. codex, caveman)'),
|
|
116
|
+
cmd('aw integrations remove <key>', 'Remove a tool'),
|
|
117
|
+
cmd('aw integrations bundle <name>', 'Install a preset bundle'),
|
|
112
118
|
cmd('aw drop <path>', 'Stop syncing or delete local content'),
|
|
113
119
|
cmd('aw nuke', 'Remove entire .aw_registry/ & start fresh'),
|
|
114
120
|
cmd('aw daemon install', 'Auto-pull on a schedule (macOS launchd / Linux cron)'),
|
package/commands/init.mjs
CHANGED
|
@@ -34,6 +34,7 @@ import { loadConfig as ensureTelemetryConfig } from '../telemetry.mjs';
|
|
|
34
34
|
import { installAwEcc, AW_ECC_TAG } from '../ecc.mjs';
|
|
35
35
|
import { removeWorkspaceHookDefaults } from '../codex.mjs';
|
|
36
36
|
import { readHookManifest, pruneStaleHooks, writeHookManifest } from '../hook-cleanup.mjs';
|
|
37
|
+
import { promptAndInstall, autoInstallIntegrations } from '../integrations.mjs';
|
|
37
38
|
import {
|
|
38
39
|
initPersistentClone,
|
|
39
40
|
isValidClone,
|
|
@@ -212,6 +213,7 @@ export async function initCommand(args) {
|
|
|
212
213
|
let namespace = args['--namespace'] || null;
|
|
213
214
|
let user = args['--user'] || '';
|
|
214
215
|
const silent = args['--silent'] === true;
|
|
216
|
+
const skipIntegrations = args['--no-integrations'] === true;
|
|
215
217
|
|
|
216
218
|
// In silent mode, suppress ALL fmt output and show a single spinner.
|
|
217
219
|
// setSilent(true) makes every fmt.* call a no-op — internal functions
|
|
@@ -414,6 +416,12 @@ export async function initCommand(args) {
|
|
|
414
416
|
// Write hook manifest after all hook installation is complete
|
|
415
417
|
try { writeHookManifest({ eccVersion: AW_ECC_TAG, awVersion: VERSION }); } catch { /* best effort */ }
|
|
416
418
|
|
|
419
|
+
// Auto-install suggested integrations (Codex, Caveman, Graphify, etc) - unless --no-integrations
|
|
420
|
+
let installedIntegrations = [];
|
|
421
|
+
if (!silent && !skipIntegrations && !isNewSubTeam) {
|
|
422
|
+
installedIntegrations = await autoInstallIntegrations(freshCfg?.namespace || team, { silent });
|
|
423
|
+
}
|
|
424
|
+
|
|
417
425
|
if (silent) {
|
|
418
426
|
if (silentSpinner) { silentSpinner.stop('Done'); setSilent(false); }
|
|
419
427
|
autoUpdate(await args._updateCheck);
|
|
@@ -427,6 +435,7 @@ export async function initCommand(args) {
|
|
|
427
435
|
? ` ${chalk.green('✓')} Removed ${removedLegacyStartupFiles.length} legacy repo startup file${removedLegacyStartupFiles.length > 1 ? 's' : ''}`
|
|
428
436
|
: null,
|
|
429
437
|
cwd !== HOME && isWorktree(join(cwd, '.aw')) ? ` ${chalk.green('✓')} Project linked` : null,
|
|
438
|
+
installedIntegrations.length > 0 ? ` ${chalk.green('✓')} Integrations: ${installedIntegrations.join(', ')}` : null,
|
|
430
439
|
].filter(Boolean).join('\n'));
|
|
431
440
|
}
|
|
432
441
|
return;
|
|
@@ -574,6 +583,12 @@ export async function initCommand(args) {
|
|
|
574
583
|
// Ensure telemetry config exists (generates machine_id on first run)
|
|
575
584
|
ensureTelemetryConfig();
|
|
576
585
|
|
|
586
|
+
// Auto-install suggested integrations (Codex, Caveman, Graphify, etc) - unless --no-integrations
|
|
587
|
+
let installedIntegrations = [];
|
|
588
|
+
if (!silent && !skipIntegrations) {
|
|
589
|
+
installedIntegrations = await autoInstallIntegrations(team, { silent });
|
|
590
|
+
}
|
|
591
|
+
|
|
577
592
|
// Offer to update if a newer version is available
|
|
578
593
|
if (!silent) await promptUpdate(await args._updateCheck);
|
|
579
594
|
|
|
@@ -593,10 +608,12 @@ export async function initCommand(args) {
|
|
|
593
608
|
hooksInstalled ? ` ${chalk.green('✓')} Git hooks: auto-sync on pull/clone (core.hooksPath)` : null,
|
|
594
609
|
` ${chalk.green('✓')} IDE task: auto-sync on workspace open`,
|
|
595
610
|
cwd !== HOME && isWorktree(join(cwd, '.aw')) ? ` ${chalk.green('✓')} Linked in current project` : null,
|
|
611
|
+
installedIntegrations.length > 0 ? ` ${chalk.green('✓')} Integrations: ${installedIntegrations.join(', ')}` : null,
|
|
596
612
|
'',
|
|
597
613
|
` ${chalk.dim('Existing repos:')} ${chalk.bold('cd <project> && aw link')}`,
|
|
598
614
|
` ${chalk.dim('New clones:')} auto-linked via git hook`,
|
|
599
615
|
` ${chalk.dim('Update:')} ${chalk.bold('aw init')} ${chalk.dim('(or auto on pull/IDE open)')}`,
|
|
616
|
+
` ${chalk.dim('Integrations:')} ${chalk.bold('aw integrations')} ${chalk.dim('(manage Codex, Caveman, etc)')}`,
|
|
600
617
|
` ${chalk.dim('Uninstall:')} ${chalk.bold('aw nuke')}`,
|
|
601
618
|
].filter(Boolean).join('\n'));
|
|
602
619
|
}
|
|
@@ -0,0 +1,254 @@
|
|
|
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
|
+
}
|