agent-switchboard 0.4.2 → 0.4.4
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 +45 -0
- package/dist/agents/codex.d.ts +2 -2
- package/dist/agents/codex.js +13 -7
- package/dist/agents/codex.js.map +1 -1
- package/dist/agents/cursor.js +5 -17
- package/dist/agents/cursor.js.map +1 -1
- package/dist/agents/gemini.js +10 -50
- package/dist/agents/gemini.js.map +1 -1
- package/dist/agents/json-utils.d.ts +12 -0
- package/dist/agents/json-utils.js +27 -1
- package/dist/agents/json-utils.js.map +1 -1
- package/dist/agents/opencode.js +3 -3
- package/dist/agents/opencode.js.map +1 -1
- package/dist/agents/trae.js +5 -17
- package/dist/agents/trae.js.map +1 -1
- package/dist/commands/distribution.js +6 -1
- package/dist/commands/distribution.js.map +1 -1
- package/dist/config/application-config.d.ts +1 -0
- package/dist/config/application-config.js +36 -4
- package/dist/config/application-config.js.map +1 -1
- package/dist/config/layered-config.js +1 -5
- package/dist/config/layered-config.js.map +1 -1
- package/dist/config/mcp-config.d.ts +2 -3
- package/dist/config/mcp-config.js +2 -7
- package/dist/config/mcp-config.js.map +1 -1
- package/dist/config/schemas.js +1 -1
- package/dist/config/schemas.js.map +1 -1
- package/dist/extensions/api.d.ts +9 -0
- package/dist/extensions/api.js +40 -16
- package/dist/extensions/api.js.map +1 -1
- package/dist/extensions/loader.d.ts +2 -0
- package/dist/extensions/loader.js +9 -5
- package/dist/extensions/loader.js.map +1 -1
- package/dist/hooks/distribution.d.ts +3 -1
- package/dist/hooks/distribution.js +32 -13
- package/dist/hooks/distribution.js.map +1 -1
- package/dist/index.js +150 -37
- package/dist/index.js.map +1 -1
- package/dist/library/distribute-bundle.js +89 -28
- package/dist/library/distribute-bundle.js.map +1 -1
- package/dist/library/distribute.d.ts +2 -2
- package/dist/library/distribute.js +40 -16
- package/dist/library/distribute.js.map +1 -1
- package/dist/library/state.js +12 -4
- package/dist/library/state.js.map +1 -1
- package/dist/manifest/store.d.ts +12 -1
- package/dist/manifest/store.js +63 -8
- package/dist/manifest/store.js.map +1 -1
- package/dist/marketplace/plugin-loader.d.ts +2 -2
- package/dist/marketplace/plugin-loader.js +8 -6
- package/dist/marketplace/plugin-loader.js.map +1 -1
- package/dist/marketplace/source-loader.js +3 -1
- package/dist/marketplace/source-loader.js.map +1 -1
- package/dist/mcp/distribution.js +109 -41
- package/dist/mcp/distribution.js.map +1 -1
- package/dist/plugins/identity.d.ts +8 -0
- package/dist/plugins/identity.js +22 -0
- package/dist/plugins/identity.js.map +1 -0
- package/dist/plugins/index.d.ts +4 -0
- package/dist/plugins/index.js +59 -35
- package/dist/plugins/index.js.map +1 -1
- package/dist/rules/block-merge.d.ts +0 -7
- package/dist/rules/block-merge.js +2 -1
- package/dist/rules/block-merge.js.map +1 -1
- package/dist/rules/distribution.js +18 -5
- package/dist/rules/distribution.js.map +1 -1
- package/dist/rules/state.js +11 -2
- package/dist/rules/state.js.map +1 -1
- package/dist/skills/distribution.js +39 -9
- package/dist/skills/distribution.js.map +1 -1
- package/dist/subagents/distribution.js +6 -1
- package/dist/subagents/distribution.js.map +1 -1
- package/dist/subagents/inventory.js +3 -3
- package/dist/subagents/inventory.js.map +1 -1
- package/dist/sync/command.js +23 -5
- package/dist/sync/command.js.map +1 -1
- package/dist/targets/builtin/claude-code.js +3 -1
- package/dist/targets/builtin/claude-code.js.map +1 -1
- package/dist/targets/builtin/common.d.ts +4 -1
- package/dist/targets/builtin/common.js +11 -1
- package/dist/targets/builtin/common.js.map +1 -1
- package/dist/targets/builtin/cursor.js +2 -7
- package/dist/targets/builtin/cursor.js.map +1 -1
- package/dist/targets/builtin/opencode.js +3 -1
- package/dist/targets/builtin/opencode.js.map +1 -1
- package/dist/targets/dsl/compiler.js +60 -26
- package/dist/targets/dsl/compiler.js.map +1 -1
- package/dist/targets/init.d.ts +1 -1
- package/dist/targets/init.js +3 -2
- package/dist/targets/init.js.map +1 -1
- package/dist/ui/fuzzy-multi-select.js +2 -1
- package/dist/ui/fuzzy-multi-select.js.map +1 -1
- package/dist/ui/library-selector.js +8 -9
- package/dist/ui/library-selector.js.map +1 -1
- package/dist/ui/mcp-ui.d.ts +2 -0
- package/dist/ui/mcp-ui.js +4 -4
- package/dist/ui/mcp-ui.js.map +1 -1
- package/dist/ui/plugin-ui.js +2 -2
- package/dist/ui/plugin-ui.js.map +1 -1
- package/dist/ui/rule-ui.js +4 -5
- package/dist/ui/rule-ui.js.map +1 -1
- package/dist/ui/selection-state.d.ts +0 -1
- package/dist/ui/selection-state.js +2 -5
- package/dist/ui/selection-state.js.map +1 -1
- package/dist/ui/subagent-ui.js +2 -16
- package/dist/ui/subagent-ui.js.map +1 -1
- package/dist/util/cli.d.ts +1 -0
- package/dist/util/cli.js +14 -3
- package/dist/util/cli.js.map +1 -1
- package/dist/util/extras.d.ts +2 -0
- package/dist/util/extras.js +3 -1
- package/dist/util/extras.js.map +1 -1
- package/dist/util/markdown.js +8 -2
- package/dist/util/markdown.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -13,8 +13,8 @@ import ora from 'ora';
|
|
|
13
13
|
import { distributeCommands } from './commands/distribution.js';
|
|
14
14
|
import { importCommandFromFile } from './commands/importer.js';
|
|
15
15
|
import { buildCommandInventory } from './commands/inventory.js';
|
|
16
|
-
import { updateConfigLayer } from './config/layered-config.js';
|
|
17
|
-
import { loadMcpConfig, stripLegacyEnabledFlagsFromMcpJson } from './config/mcp-config.js';
|
|
16
|
+
import { loadWritableConfigLayer, updateConfigLayer } from './config/layered-config.js';
|
|
17
|
+
import { loadMcpConfig, loadMcpConfigWithPlugins, stripLegacyEnabledFlagsFromMcpJson, } from './config/mcp-config.js';
|
|
18
18
|
import { getAgentsDir, getAgentsHome, getClaudeDir, getCodexDir, getCommandsDir, getCursorDir, getGeminiDir, getHooksDir, getOpencodePath, getSkillsDir, getSourceCacheDir, } from './config/paths.js';
|
|
19
19
|
import { scopeToLayerOptions } from './config/scope.js';
|
|
20
20
|
import { loadSwitchboardConfig, loadSwitchboardConfigWithLayers, } from './config/switchboard-config.js';
|
|
@@ -23,6 +23,7 @@ import { loadHookLibrary } from './hooks/library.js';
|
|
|
23
23
|
import { copyDirRecursive, ensureLibraryDirectories, isDir, isFile, listFilesRecursively, writeFileSecure, } from './library/fs.js';
|
|
24
24
|
import { addLocalSource, addRemoteSource, getSources, inferSourceName, isGitUrl, parseGitUrl, removeSource, updateRemoteSources, validateSourcePath, } from './library/sources.js';
|
|
25
25
|
import { loadLibraryStateSection, saveMcpEnabledState } from './library/state.js';
|
|
26
|
+
import { loadManifest, saveManifest } from './manifest/store.js';
|
|
26
27
|
import { readMarketplace } from './marketplace/reader.js';
|
|
27
28
|
import { distributeMcp } from './mcp/distribution.js';
|
|
28
29
|
import { buildPluginIndex } from './plugins/index.js';
|
|
@@ -106,6 +107,29 @@ function resolveScope(input) {
|
|
|
106
107
|
project: project,
|
|
107
108
|
};
|
|
108
109
|
}
|
|
110
|
+
function getScopedProjectMode(scope, config) {
|
|
111
|
+
return scope?.project ? config.distribution.project.mode : undefined;
|
|
112
|
+
}
|
|
113
|
+
function shouldSkipProjectDistribution(scope, config) {
|
|
114
|
+
return getScopedProjectMode(scope, config) === 'none';
|
|
115
|
+
}
|
|
116
|
+
function printProjectDistributionDisabledMessage() {
|
|
117
|
+
console.log(chalk.gray('Project distribution is disabled by `[distribution.project].mode = "none"`.'));
|
|
118
|
+
}
|
|
119
|
+
function loadManagedProjectManifest(scope, projectMode) {
|
|
120
|
+
if (!scope?.project || projectMode !== 'managed')
|
|
121
|
+
return undefined;
|
|
122
|
+
const result = loadManifest(scope.project);
|
|
123
|
+
if (result.corrupt) {
|
|
124
|
+
throw new Error(`Corrupt managed manifest in ${scope.project}. Fix or remove it before retrying.`);
|
|
125
|
+
}
|
|
126
|
+
return result.manifest;
|
|
127
|
+
}
|
|
128
|
+
function saveManagedProjectManifest(scope, projectMode, manifest) {
|
|
129
|
+
if (!scope?.project || projectMode !== 'managed' || !manifest)
|
|
130
|
+
return;
|
|
131
|
+
saveManifest(scope.project, manifest);
|
|
132
|
+
}
|
|
109
133
|
function defaultCommandSourceDir(platform) {
|
|
110
134
|
switch (platform) {
|
|
111
135
|
case 'claude-code':
|
|
@@ -280,6 +304,7 @@ program
|
|
|
280
304
|
const scope = resolveScope(options);
|
|
281
305
|
const { config, layers } = loadSwitchboardConfigWithLayers(scopeToLayerOptions(scope));
|
|
282
306
|
const mcpConfig = loadMcpConfig();
|
|
307
|
+
const pluginIndex = buildPluginIndex(scope);
|
|
283
308
|
// Determine initial selection:
|
|
284
309
|
// - If writing to project/profile scope, only use that layer's explicit [mcp].enabled (no fallback).
|
|
285
310
|
// - If writing to user scope and [mcp].enabled is missing, fall back to legacy mcp.json enabled flags.
|
|
@@ -304,10 +329,22 @@ program
|
|
|
304
329
|
.map(([name]) => name);
|
|
305
330
|
}
|
|
306
331
|
}
|
|
332
|
+
const scopedPluginRefs = scope?.project
|
|
333
|
+
? (layers.project?.config?.plugins?.enabled ?? [])
|
|
334
|
+
: scope?.profile
|
|
335
|
+
? (layers.profile?.config?.plugins?.enabled ?? [])
|
|
336
|
+
: (layers.user.config?.plugins?.enabled ?? []);
|
|
337
|
+
const pluginMcpServers = pluginIndex.expand(scopedPluginRefs).mcp;
|
|
338
|
+
const currentActiveSet = new Set(currentActive);
|
|
339
|
+
for (const serverName of pluginMcpServers) {
|
|
340
|
+
currentActiveSet.add(serverName);
|
|
341
|
+
}
|
|
342
|
+
currentActive = [...currentActiveSet];
|
|
307
343
|
// Step 1: Show UI and get selected servers
|
|
308
344
|
const selectedServers = await showMcpServerUI({
|
|
309
345
|
pageSize: config.ui.page_size,
|
|
310
346
|
enabled: currentActive,
|
|
347
|
+
scope,
|
|
311
348
|
});
|
|
312
349
|
// Step 2: Save active state to config.toml (appropriate layer based on scope)
|
|
313
350
|
const spinner = ora('Updating MCP configuration...').start();
|
|
@@ -326,7 +363,18 @@ program
|
|
|
326
363
|
}
|
|
327
364
|
}
|
|
328
365
|
// Step 3: Apply to registered agents
|
|
329
|
-
|
|
366
|
+
const projectMode = getScopedProjectMode(scope, config);
|
|
367
|
+
const manifest = loadManagedProjectManifest(scope, projectMode);
|
|
368
|
+
try {
|
|
369
|
+
await distributeMcp(scope, selectedServers, { manifest, projectMode });
|
|
370
|
+
}
|
|
371
|
+
finally {
|
|
372
|
+
saveManagedProjectManifest(scope, projectMode, manifest);
|
|
373
|
+
}
|
|
374
|
+
if (shouldSkipProjectDistribution(scope, config)) {
|
|
375
|
+
console.log();
|
|
376
|
+
printProjectDistributionDisabledMessage();
|
|
377
|
+
}
|
|
330
378
|
// Step 4: Show summary
|
|
331
379
|
showSummary(selectedServers, scope);
|
|
332
380
|
}
|
|
@@ -425,13 +473,12 @@ ruleCommand.action(async (options) => {
|
|
|
425
473
|
if (!selection) {
|
|
426
474
|
return;
|
|
427
475
|
}
|
|
428
|
-
const { rules, writableState: previousState,
|
|
476
|
+
const { rules, writableState: previousState, activeState } = loadRuleRuntimeContext(scope);
|
|
429
477
|
const ruleMap = new Map(rules.map((rule) => [rule.id, rule]));
|
|
430
478
|
const desiredEnabled = selection.enabled;
|
|
431
479
|
const selectionChanged = selection.explicitEmpty ||
|
|
432
480
|
shouldPersistSelection({
|
|
433
|
-
|
|
434
|
-
effectiveEnabled: effectiveState.enabled,
|
|
481
|
+
effectiveEnabled: activeState.enabled,
|
|
435
482
|
selectedEnabled: desiredEnabled,
|
|
436
483
|
});
|
|
437
484
|
const updatedState = selectionChanged
|
|
@@ -460,11 +507,21 @@ ruleCommand.action(async (options) => {
|
|
|
460
507
|
}
|
|
461
508
|
}
|
|
462
509
|
}
|
|
463
|
-
const
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
510
|
+
const projectMode = getScopedProjectMode(scope, config);
|
|
511
|
+
const manifest = loadManagedProjectManifest(scope, projectMode);
|
|
512
|
+
let distribution;
|
|
513
|
+
try {
|
|
514
|
+
distribution = distributeRules({
|
|
515
|
+
force: !selectionChanged,
|
|
516
|
+
activeAppIds: config.applications.enabled,
|
|
517
|
+
assumeInstalled: new Set(config.applications.assume_installed),
|
|
518
|
+
manifest,
|
|
519
|
+
projectMode,
|
|
520
|
+
}, scope);
|
|
521
|
+
}
|
|
522
|
+
finally {
|
|
523
|
+
saveManagedProjectManifest(scope, projectMode, manifest);
|
|
524
|
+
}
|
|
468
525
|
if (distribution.results.length > 0) {
|
|
469
526
|
console.log();
|
|
470
527
|
printDistributionResults({
|
|
@@ -474,6 +531,10 @@ ruleCommand.action(async (options) => {
|
|
|
474
531
|
getPath: (result) => result.filePath,
|
|
475
532
|
});
|
|
476
533
|
}
|
|
534
|
+
if (shouldSkipProjectDistribution(scope, config)) {
|
|
535
|
+
console.log();
|
|
536
|
+
printProjectDistributionDisabledMessage();
|
|
537
|
+
}
|
|
477
538
|
const distributionErrors = distribution.results.filter((r) => r.status === 'error');
|
|
478
539
|
if (distributionErrors.length > 0) {
|
|
479
540
|
process.exit(1);
|
|
@@ -515,7 +576,18 @@ commandRoot.action(async (options) => {
|
|
|
515
576
|
return;
|
|
516
577
|
console.log();
|
|
517
578
|
printActiveSelection('commands', selection.enabled);
|
|
518
|
-
const
|
|
579
|
+
const projectMode = getScopedProjectMode(scope, config);
|
|
580
|
+
const manifest = loadManagedProjectManifest(scope, projectMode);
|
|
581
|
+
let out;
|
|
582
|
+
try {
|
|
583
|
+
out = distributeCommands(scope, config.applications.enabled, new Set(config.applications.assume_installed), {
|
|
584
|
+
manifest,
|
|
585
|
+
projectMode,
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
finally {
|
|
589
|
+
saveManagedProjectManifest(scope, projectMode, manifest);
|
|
590
|
+
}
|
|
519
591
|
if (out.results.length > 0) {
|
|
520
592
|
console.log();
|
|
521
593
|
printDistributionResults({
|
|
@@ -525,6 +597,10 @@ commandRoot.action(async (options) => {
|
|
|
525
597
|
getPath: (result) => result.filePath,
|
|
526
598
|
});
|
|
527
599
|
}
|
|
600
|
+
if (shouldSkipProjectDistribution(scope, config)) {
|
|
601
|
+
console.log();
|
|
602
|
+
printProjectDistributionDisabledMessage();
|
|
603
|
+
}
|
|
528
604
|
// Guidance: unsupported platforms for commands
|
|
529
605
|
console.log();
|
|
530
606
|
console.log(chalk.gray('Unsupported platforms (manual steps required): Claude Desktop'));
|
|
@@ -665,7 +741,18 @@ agentRoot.action(async (options) => {
|
|
|
665
741
|
return;
|
|
666
742
|
console.log();
|
|
667
743
|
printActiveSelection('agents', selection.enabled);
|
|
668
|
-
const
|
|
744
|
+
const projectMode = getScopedProjectMode(scope, config);
|
|
745
|
+
const manifest = loadManagedProjectManifest(scope, projectMode);
|
|
746
|
+
let out;
|
|
747
|
+
try {
|
|
748
|
+
out = distributeSubagents(scope, config.applications.enabled, new Set(config.applications.assume_installed), {
|
|
749
|
+
manifest,
|
|
750
|
+
projectMode,
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
finally {
|
|
754
|
+
saveManagedProjectManifest(scope, projectMode, manifest);
|
|
755
|
+
}
|
|
669
756
|
if (out.results.length > 0) {
|
|
670
757
|
console.log();
|
|
671
758
|
printDistributionResults({
|
|
@@ -675,6 +762,10 @@ agentRoot.action(async (options) => {
|
|
|
675
762
|
getPath: (result) => result.filePath,
|
|
676
763
|
});
|
|
677
764
|
}
|
|
765
|
+
if (shouldSkipProjectDistribution(scope, config)) {
|
|
766
|
+
console.log();
|
|
767
|
+
printProjectDistributionDisabledMessage();
|
|
768
|
+
}
|
|
678
769
|
console.log();
|
|
679
770
|
console.log(chalk.gray('Unsupported platforms (manual steps required): Codex, Gemini'));
|
|
680
771
|
}
|
|
@@ -813,11 +904,21 @@ skillRoot.action(async (options) => {
|
|
|
813
904
|
return;
|
|
814
905
|
console.log();
|
|
815
906
|
printActiveSelection('skills', selection.enabled);
|
|
816
|
-
const
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
907
|
+
const projectMode = getScopedProjectMode(scope, config);
|
|
908
|
+
const manifest = loadManagedProjectManifest(scope, projectMode);
|
|
909
|
+
let out;
|
|
910
|
+
try {
|
|
911
|
+
out = distributeSkills(scope, {
|
|
912
|
+
useAgentsDir: config.distribution.use_agents_dir,
|
|
913
|
+
activeAppIds: config.applications.enabled,
|
|
914
|
+
assumeInstalled: new Set(config.applications.assume_installed),
|
|
915
|
+
manifest,
|
|
916
|
+
projectMode,
|
|
917
|
+
});
|
|
918
|
+
}
|
|
919
|
+
finally {
|
|
920
|
+
saveManagedProjectManifest(scope, projectMode, manifest);
|
|
921
|
+
}
|
|
821
922
|
if (out.results.length > 0) {
|
|
822
923
|
console.log();
|
|
823
924
|
printDistributionResults({
|
|
@@ -833,6 +934,10 @@ skillRoot.action(async (options) => {
|
|
|
833
934
|
getPath: (result) => result.targetDir,
|
|
834
935
|
});
|
|
835
936
|
}
|
|
937
|
+
if (shouldSkipProjectDistribution(scope, config)) {
|
|
938
|
+
console.log();
|
|
939
|
+
printProjectDistributionDisabledMessage();
|
|
940
|
+
}
|
|
836
941
|
}
|
|
837
942
|
catch (error) {
|
|
838
943
|
if (error instanceof Error) {
|
|
@@ -962,7 +1067,9 @@ hookRoot.action(async (options) => {
|
|
|
962
1067
|
return;
|
|
963
1068
|
console.log();
|
|
964
1069
|
printActiveSelection('hooks', selection.enabled);
|
|
965
|
-
const out = distributeHooks(scope, config.applications.enabled, new Set(config.applications.assume_installed)
|
|
1070
|
+
const out = distributeHooks(scope, config.applications.enabled, new Set(config.applications.assume_installed), {
|
|
1071
|
+
projectMode: getScopedProjectMode(scope, config),
|
|
1072
|
+
});
|
|
966
1073
|
if (out.results.length > 0) {
|
|
967
1074
|
console.log();
|
|
968
1075
|
printDistributionResults({
|
|
@@ -972,6 +1079,10 @@ hookRoot.action(async (options) => {
|
|
|
972
1079
|
getPath: (result) => 'filePath' in result ? result.filePath : result.targetDir,
|
|
973
1080
|
});
|
|
974
1081
|
}
|
|
1082
|
+
if (shouldSkipProjectDistribution(scope, config)) {
|
|
1083
|
+
console.log();
|
|
1084
|
+
printProjectDistributionDisabledMessage();
|
|
1085
|
+
}
|
|
975
1086
|
}
|
|
976
1087
|
catch (error) {
|
|
977
1088
|
if (error instanceof Error) {
|
|
@@ -1118,7 +1229,7 @@ hookRoot
|
|
|
1118
1229
|
* Show summary of enabled/disabled servers and applied agents
|
|
1119
1230
|
*/
|
|
1120
1231
|
function showSummary(selectedServers, scope) {
|
|
1121
|
-
const mcpConfig =
|
|
1232
|
+
const mcpConfig = loadMcpConfigWithPlugins(scope);
|
|
1122
1233
|
const allServers = Object.keys(mcpConfig.mcpServers);
|
|
1123
1234
|
const enabledServers = selectedServers;
|
|
1124
1235
|
const disabledServers = allServers.filter((s) => !selectedServers.includes(s));
|
|
@@ -1235,9 +1346,10 @@ pluginRoot
|
|
|
1235
1346
|
function pluginEnableAction(id, options) {
|
|
1236
1347
|
try {
|
|
1237
1348
|
const scope = resolveScope(options);
|
|
1238
|
-
const
|
|
1239
|
-
|
|
1240
|
-
|
|
1349
|
+
const layerOpts = scopeToLayerOptions(scope);
|
|
1350
|
+
const layer = loadWritableConfigLayer(layerOpts);
|
|
1351
|
+
if (layer.config.plugins?.enabled?.includes(id)) {
|
|
1352
|
+
console.log(chalk.yellow(`⚠ Plugin "${id}" is already enabled in this config layer.`));
|
|
1241
1353
|
return;
|
|
1242
1354
|
}
|
|
1243
1355
|
const index = buildPluginIndex(scope);
|
|
@@ -1246,13 +1358,13 @@ function pluginEnableAction(id, options) {
|
|
|
1246
1358
|
console.log(chalk.dim(' Run `asb plugin list` to see available plugins.'));
|
|
1247
1359
|
process.exit(1);
|
|
1248
1360
|
}
|
|
1249
|
-
updateConfigLayer((
|
|
1250
|
-
...
|
|
1361
|
+
updateConfigLayer((l) => ({
|
|
1362
|
+
...l,
|
|
1251
1363
|
plugins: {
|
|
1252
|
-
...(
|
|
1253
|
-
enabled: [...(
|
|
1364
|
+
...(l.plugins ?? {}),
|
|
1365
|
+
enabled: [...(l.plugins?.enabled ?? []), id],
|
|
1254
1366
|
},
|
|
1255
|
-
}),
|
|
1367
|
+
}), layerOpts);
|
|
1256
1368
|
console.log(chalk.green(`✓ Plugin "${id}" enabled.`));
|
|
1257
1369
|
}
|
|
1258
1370
|
catch (error) {
|
|
@@ -1265,18 +1377,19 @@ function pluginEnableAction(id, options) {
|
|
|
1265
1377
|
function pluginRemoveAction(id, options, verb) {
|
|
1266
1378
|
try {
|
|
1267
1379
|
const scope = resolveScope(options);
|
|
1268
|
-
const
|
|
1269
|
-
|
|
1270
|
-
|
|
1380
|
+
const layerOpts = scopeToLayerOptions(scope);
|
|
1381
|
+
const layer = loadWritableConfigLayer(layerOpts);
|
|
1382
|
+
if (!layer.config.plugins?.enabled?.includes(id)) {
|
|
1383
|
+
console.log(chalk.yellow(`⚠ Plugin "${id}" is not enabled in this config layer.`));
|
|
1271
1384
|
return;
|
|
1272
1385
|
}
|
|
1273
|
-
updateConfigLayer((
|
|
1274
|
-
...
|
|
1386
|
+
updateConfigLayer((l) => ({
|
|
1387
|
+
...l,
|
|
1275
1388
|
plugins: {
|
|
1276
|
-
...(
|
|
1277
|
-
enabled: (
|
|
1389
|
+
...(l.plugins ?? {}),
|
|
1390
|
+
enabled: (l.plugins?.enabled ?? []).filter((x) => x !== id),
|
|
1278
1391
|
},
|
|
1279
|
-
}),
|
|
1392
|
+
}), layerOpts);
|
|
1280
1393
|
console.log(chalk.green(`✓ Plugin "${id}" ${verb}.`));
|
|
1281
1394
|
}
|
|
1282
1395
|
catch (error) {
|
|
@@ -1532,7 +1645,7 @@ mktRoot
|
|
|
1532
1645
|
}
|
|
1533
1646
|
});
|
|
1534
1647
|
mktRoot.action(() => {
|
|
1535
|
-
mktRoot.
|
|
1648
|
+
mktRoot.outputHelp();
|
|
1536
1649
|
});
|
|
1537
1650
|
// ── Removed: `asb source` ──────────────────────────────────────────
|
|
1538
1651
|
program
|