@x-code-cli/core 0.2.9 → 0.3.0
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/dist/agent/compression.d.ts +12 -2
- package/dist/agent/compression.d.ts.map +1 -1
- package/dist/agent/compression.js +51 -2
- package/dist/agent/compression.js.map +1 -1
- package/dist/agent/file-ingest.js +2 -2
- package/dist/agent/file-ingest.js.map +1 -1
- package/dist/agent/loop-state.d.ts +3 -2
- package/dist/agent/loop-state.d.ts.map +1 -1
- package/dist/agent/loop-state.js.map +1 -1
- package/dist/agent/loop.d.ts.map +1 -1
- package/dist/agent/loop.js +140 -9
- package/dist/agent/loop.js.map +1 -1
- package/dist/agent/memory-extractor.js +5 -5
- package/dist/agent/memory-extractor.js.map +1 -1
- package/dist/agent/plan-storage.js +1 -1
- package/dist/agent/plan-storage.js.map +1 -1
- package/dist/agent/sub-agents/index.d.ts +2 -1
- package/dist/agent/sub-agents/index.d.ts.map +1 -1
- package/dist/agent/sub-agents/index.js +1 -1
- package/dist/agent/sub-agents/index.js.map +1 -1
- package/dist/agent/sub-agents/loader.d.ts +13 -3
- package/dist/agent/sub-agents/loader.d.ts.map +1 -1
- package/dist/agent/sub-agents/loader.js +36 -9
- package/dist/agent/sub-agents/loader.js.map +1 -1
- package/dist/agent/sub-agents/registry.d.ts +18 -1
- package/dist/agent/sub-agents/registry.d.ts.map +1 -1
- package/dist/agent/sub-agents/registry.js +38 -5
- package/dist/agent/sub-agents/registry.js.map +1 -1
- package/dist/agent/sub-agents/runner.d.ts.map +1 -1
- package/dist/agent/sub-agents/runner.js +45 -1
- package/dist/agent/sub-agents/runner.js.map +1 -1
- package/dist/agent/sub-agents/types.d.ts +4 -1
- package/dist/agent/sub-agents/types.d.ts.map +1 -1
- package/dist/agent/system-prompt.d.ts +21 -0
- package/dist/agent/system-prompt.d.ts.map +1 -1
- package/dist/agent/system-prompt.js +68 -2
- package/dist/agent/system-prompt.js.map +1 -1
- package/dist/agent/tool-execution.d.ts.map +1 -1
- package/dist/agent/tool-execution.js +220 -1
- package/dist/agent/tool-execution.js.map +1 -1
- package/dist/commands/index.d.ts +6 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +3 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/loader.d.ts +13 -0
- package/dist/commands/loader.d.ts.map +1 -0
- package/dist/commands/loader.js +93 -0
- package/dist/commands/loader.js.map +1 -0
- package/dist/commands/registry.d.ts +44 -0
- package/dist/commands/registry.d.ts.map +1 -0
- package/dist/commands/registry.js +102 -0
- package/dist/commands/registry.js.map +1 -0
- package/dist/commands/types.d.ts +23 -0
- package/dist/commands/types.d.ts.map +1 -0
- package/dist/commands/types.js +26 -0
- package/dist/commands/types.js.map +1 -0
- package/dist/config/index.d.ts +9 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +12 -10
- package/dist/config/index.js.map +1 -1
- package/dist/hooks/bus.d.ts +54 -0
- package/dist/hooks/bus.d.ts.map +1 -0
- package/dist/hooks/bus.js +165 -0
- package/dist/hooks/bus.js.map +1 -0
- package/dist/hooks/config-schema.d.ts +854 -0
- package/dist/hooks/config-schema.d.ts.map +1 -0
- package/dist/hooks/config-schema.js +79 -0
- package/dist/hooks/config-schema.js.map +1 -0
- package/dist/hooks/executor.d.ts +16 -0
- package/dist/hooks/executor.d.ts.map +1 -0
- package/dist/hooks/executor.js +183 -0
- package/dist/hooks/executor.js.map +1 -0
- package/dist/hooks/index.d.ts +10 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +6 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/registry.d.ts +23 -0
- package/dist/hooks/registry.d.ts.map +1 -0
- package/dist/hooks/registry.js +49 -0
- package/dist/hooks/registry.js.map +1 -0
- package/dist/hooks/types.d.ts +165 -0
- package/dist/hooks/types.d.ts.map +1 -0
- package/dist/hooks/types.js +25 -0
- package/dist/hooks/types.js.map +1 -0
- package/dist/hooks/variables.d.ts +22 -0
- package/dist/hooks/variables.d.ts.map +1 -0
- package/dist/hooks/variables.js +80 -0
- package/dist/hooks/variables.js.map +1 -0
- package/dist/index.d.ts +56 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +37 -1
- package/dist/index.js.map +1 -1
- package/dist/knowledge/auto-memory.d.ts +1 -1
- package/dist/knowledge/auto-memory.d.ts.map +1 -1
- package/dist/knowledge/auto-memory.js +10 -10
- package/dist/knowledge/auto-memory.js.map +1 -1
- package/dist/knowledge/loader.js +12 -12
- package/dist/knowledge/loader.js.map +1 -1
- package/dist/mcp/arg-parser.d.ts +49 -0
- package/dist/mcp/arg-parser.d.ts.map +1 -0
- package/dist/mcp/arg-parser.js +357 -0
- package/dist/mcp/arg-parser.js.map +1 -0
- package/dist/mcp/client.d.ts +73 -0
- package/dist/mcp/client.d.ts.map +1 -0
- package/dist/mcp/client.js +376 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/mcp/config-schema.d.ts +64 -0
- package/dist/mcp/config-schema.d.ts.map +1 -0
- package/dist/mcp/config-schema.js +86 -0
- package/dist/mcp/config-schema.js.map +1 -0
- package/dist/mcp/config-writer.d.ts +41 -0
- package/dist/mcp/config-writer.d.ts.map +1 -0
- package/dist/mcp/config-writer.js +138 -0
- package/dist/mcp/config-writer.js.map +1 -0
- package/dist/mcp/env-safety.d.ts +12 -0
- package/dist/mcp/env-safety.d.ts.map +1 -0
- package/dist/mcp/env-safety.js +80 -0
- package/dist/mcp/env-safety.js.map +1 -0
- package/dist/mcp/expand-env.d.ts +14 -0
- package/dist/mcp/expand-env.d.ts.map +1 -0
- package/dist/mcp/expand-env.js +52 -0
- package/dist/mcp/expand-env.js.map +1 -0
- package/dist/mcp/loader.d.ts +81 -0
- package/dist/mcp/loader.d.ts.map +1 -0
- package/dist/mcp/loader.js +223 -0
- package/dist/mcp/loader.js.map +1 -0
- package/dist/mcp/name-mangling.d.ts +11 -0
- package/dist/mcp/name-mangling.d.ts.map +1 -0
- package/dist/mcp/name-mangling.js +82 -0
- package/dist/mcp/name-mangling.js.map +1 -0
- package/dist/mcp/oauth/callback-server.d.ts +25 -0
- package/dist/mcp/oauth/callback-server.d.ts.map +1 -0
- package/dist/mcp/oauth/callback-server.js +118 -0
- package/dist/mcp/oauth/callback-server.js.map +1 -0
- package/dist/mcp/oauth/provider.d.ts +80 -0
- package/dist/mcp/oauth/provider.d.ts.map +1 -0
- package/dist/mcp/oauth/provider.js +292 -0
- package/dist/mcp/oauth/provider.js.map +1 -0
- package/dist/mcp/oauth/token-storage.d.ts +42 -0
- package/dist/mcp/oauth/token-storage.d.ts.map +1 -0
- package/dist/mcp/oauth/token-storage.js +121 -0
- package/dist/mcp/oauth/token-storage.js.map +1 -0
- package/dist/mcp/permissions.d.ts +28 -0
- package/dist/mcp/permissions.d.ts.map +1 -0
- package/dist/mcp/permissions.js +105 -0
- package/dist/mcp/permissions.js.map +1 -0
- package/dist/mcp/registry.d.ts +150 -0
- package/dist/mcp/registry.d.ts.map +1 -0
- package/dist/mcp/registry.js +334 -0
- package/dist/mcp/registry.js.map +1 -0
- package/dist/mcp/resources.d.ts +7 -0
- package/dist/mcp/resources.d.ts.map +1 -0
- package/dist/mcp/resources.js +40 -0
- package/dist/mcp/resources.js.map +1 -0
- package/dist/mcp/tool-bridge.d.ts +16 -0
- package/dist/mcp/tool-bridge.d.ts.map +1 -0
- package/dist/mcp/tool-bridge.js +56 -0
- package/dist/mcp/tool-bridge.js.map +1 -0
- package/dist/mcp/trust.d.ts +31 -0
- package/dist/mcp/trust.d.ts.map +1 -0
- package/dist/mcp/trust.js +103 -0
- package/dist/mcp/trust.js.map +1 -0
- package/dist/mcp/types.d.ts +73 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +13 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/permissions/session-store.d.ts +13 -2
- package/dist/permissions/session-store.d.ts.map +1 -1
- package/dist/permissions/session-store.js +264 -62
- package/dist/permissions/session-store.js.map +1 -1
- package/dist/plugins/consent.d.ts +87 -0
- package/dist/plugins/consent.d.ts.map +1 -0
- package/dist/plugins/consent.js +181 -0
- package/dist/plugins/consent.js.map +1 -0
- package/dist/plugins/enable-state.d.ts +34 -0
- package/dist/plugins/enable-state.d.ts.map +1 -0
- package/dist/plugins/enable-state.js +159 -0
- package/dist/plugins/enable-state.js.map +1 -0
- package/dist/plugins/installer.d.ts +64 -0
- package/dist/plugins/installer.d.ts.map +1 -0
- package/dist/plugins/installer.js +416 -0
- package/dist/plugins/installer.js.map +1 -0
- package/dist/plugins/integration.d.ts +91 -0
- package/dist/plugins/integration.d.ts.map +1 -0
- package/dist/plugins/integration.js +233 -0
- package/dist/plugins/integration.js.map +1 -0
- package/dist/plugins/loader.d.ts +69 -0
- package/dist/plugins/loader.d.ts.map +1 -0
- package/dist/plugins/loader.js +243 -0
- package/dist/plugins/loader.js.map +1 -0
- package/dist/plugins/manifest.d.ts +23 -0
- package/dist/plugins/manifest.d.ts.map +1 -0
- package/dist/plugins/manifest.js +143 -0
- package/dist/plugins/manifest.js.map +1 -0
- package/dist/plugins/marketplace.d.ts +100 -0
- package/dist/plugins/marketplace.d.ts.map +1 -0
- package/dist/plugins/marketplace.js +529 -0
- package/dist/plugins/marketplace.js.map +1 -0
- package/dist/plugins/paths.d.ts +44 -0
- package/dist/plugins/paths.d.ts.map +1 -0
- package/dist/plugins/paths.js +89 -0
- package/dist/plugins/paths.js.map +1 -0
- package/dist/plugins/refresh.d.ts +61 -0
- package/dist/plugins/refresh.d.ts.map +1 -0
- package/dist/plugins/refresh.js +98 -0
- package/dist/plugins/refresh.js.map +1 -0
- package/dist/plugins/registry.d.ts +40 -0
- package/dist/plugins/registry.d.ts.map +1 -0
- package/dist/plugins/registry.js +80 -0
- package/dist/plugins/registry.js.map +1 -0
- package/dist/plugins/types.d.ts +225 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/plugins/types.js +16 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/plugins/user-config.d.ts +22 -0
- package/dist/plugins/user-config.d.ts.map +1 -0
- package/dist/plugins/user-config.js +96 -0
- package/dist/plugins/user-config.js.map +1 -0
- package/dist/providers/cache-control.d.ts +9 -0
- package/dist/providers/cache-control.d.ts.map +1 -1
- package/dist/providers/cache-control.js +31 -4
- package/dist/providers/cache-control.js.map +1 -1
- package/dist/skills/loader.d.ts +19 -0
- package/dist/skills/loader.d.ts.map +1 -0
- package/dist/skills/loader.js +197 -0
- package/dist/skills/loader.js.map +1 -0
- package/dist/skills/registry.d.ts +74 -0
- package/dist/skills/registry.d.ts.map +1 -0
- package/dist/skills/registry.js +136 -0
- package/dist/skills/registry.js.map +1 -0
- package/dist/skills/settings.d.ts +13 -0
- package/dist/skills/settings.d.ts.map +1 -0
- package/dist/skills/settings.js +100 -0
- package/dist/skills/settings.js.map +1 -0
- package/dist/tools/activate-skill.d.ts +5 -0
- package/dist/tools/activate-skill.d.ts.map +1 -0
- package/dist/tools/activate-skill.js +33 -0
- package/dist/tools/activate-skill.js.map +1 -0
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/todo-write.d.ts +1 -1
- package/dist/tools/web-fetch.d.ts.map +1 -1
- package/dist/tools/web-fetch.js +2 -1
- package/dist/tools/web-fetch.js.map +1 -1
- package/dist/types/index.d.ts +46 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utils.d.ts +23 -2
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +76 -20
- package/dist/utils.js.map +1 -1
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +47 -0
- package/dist/version.js.map +1 -0
- package/package.json +2 -1
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
// @x-code-cli/core — Plugin contributions → existing loaders integration
|
|
2
|
+
//
|
|
3
|
+
// Takes the output of [[loader]].loadAllPlugins and converts it into the
|
|
4
|
+
// shapes that the pre-existing skill / sub-agent / MCP loaders consume,
|
|
5
|
+
// so a CLI startup call sequence looks like:
|
|
6
|
+
//
|
|
7
|
+
// const pluginLoad = await loadAllPlugins({ cwd })
|
|
8
|
+
// const integration = await buildPluginIntegration(pluginLoad)
|
|
9
|
+
// const skillRegistry = await createSkillRegistry({ extraDirs: integration.skillsDirs })
|
|
10
|
+
// const agentRegistry = await createSubAgentRegistry({ extraDirs: integration.agentsDirs })
|
|
11
|
+
// const mcpRegistry = await loadMcpFromDisk({ ..., extraServers: integration.mcpServers })
|
|
12
|
+
//
|
|
13
|
+
// Three concerns this module owns and the others don't:
|
|
14
|
+
//
|
|
15
|
+
// 1. Resolving plugin `mcpServers` from the manifest (a path or an
|
|
16
|
+
// inline object) into a typed `Record<string, McpServerConfig>`.
|
|
17
|
+
// The path form is a JSON file shaped `{ mcpServers: {...} }`
|
|
18
|
+
// (same as ~/.x-code/config.json). The inline form is the raw
|
|
19
|
+
// record itself.
|
|
20
|
+
//
|
|
21
|
+
// 2. Detecting name collisions across plugins. We deduplicate by
|
|
22
|
+
// server name — first plugin in iteration order wins, the second's
|
|
23
|
+
// entry is dropped with a warning. A future improvement: namespace
|
|
24
|
+
// server names with the plugin id.
|
|
25
|
+
//
|
|
26
|
+
// 3. Logging plugin contributions we don't (yet) support: `commands`
|
|
27
|
+
// (we lack a file-based slash command loader) and `hooks` (Task 9
|
|
28
|
+
// will add the hook subsystem; until then, declared hooks are
|
|
29
|
+
// noted but not executed).
|
|
30
|
+
//
|
|
31
|
+
// Plugin order is deterministic — driven by the iteration order of
|
|
32
|
+
// `loadAllPlugins`'s `contributions` Map, which itself reflects the
|
|
33
|
+
// order of installed_plugins.json + project-local discovery. Stable
|
|
34
|
+
// across boots when the same plugins are installed.
|
|
35
|
+
import fs from 'node:fs/promises';
|
|
36
|
+
import { HookBus } from '../hooks/bus.js';
|
|
37
|
+
import { HookConfigParseError, parseHookConfig } from '../hooks/config-schema.js';
|
|
38
|
+
import { HookRegistry, buildHookRegistry } from '../hooks/registry.js';
|
|
39
|
+
import { parseServersBlock } from '../mcp/config-schema.js';
|
|
40
|
+
import { isStdioConfig } from '../mcp/types.js';
|
|
41
|
+
import { debugLog } from '../utils.js';
|
|
42
|
+
import { loadAllPlugins } from './loader.js';
|
|
43
|
+
import { getPluginUserConfigEnv } from './user-config.js';
|
|
44
|
+
export async function buildPluginIntegration(load) {
|
|
45
|
+
// Hook registry is built last so we can collect the per-plugin configs
|
|
46
|
+
// along the way (we don't know all plugins' rootDirs in advance — they
|
|
47
|
+
// come from LoadedPlugin).
|
|
48
|
+
const hookInputs = [];
|
|
49
|
+
const out = {
|
|
50
|
+
skillsDirs: [],
|
|
51
|
+
agentsDirs: [],
|
|
52
|
+
commandsDirs: [],
|
|
53
|
+
mcpServers: {},
|
|
54
|
+
hookRegistry: new HookRegistry(),
|
|
55
|
+
hookBus: new HookBus(new HookRegistry()),
|
|
56
|
+
pluginHooks: [],
|
|
57
|
+
mcpCollisions: [],
|
|
58
|
+
mcpErrors: [],
|
|
59
|
+
hookErrors: [],
|
|
60
|
+
};
|
|
61
|
+
const mcpOwners = new Map();
|
|
62
|
+
for (const plugin of load.registry.list()) {
|
|
63
|
+
const contrib = load.contributions.get(plugin.id);
|
|
64
|
+
if (!contrib)
|
|
65
|
+
continue;
|
|
66
|
+
if (contrib.skillsDir)
|
|
67
|
+
out.skillsDirs.push({ dir: contrib.skillsDir, pluginId: plugin.id });
|
|
68
|
+
if (contrib.agentsDir)
|
|
69
|
+
out.agentsDirs.push({ dir: contrib.agentsDir, pluginId: plugin.id });
|
|
70
|
+
if (contrib.commandsDir) {
|
|
71
|
+
out.commandsDirs.push({ dir: contrib.commandsDir, pluginId: plugin.id, pluginRoot: plugin.rootDir });
|
|
72
|
+
}
|
|
73
|
+
if (contrib.hooks) {
|
|
74
|
+
const config = await resolvePluginHooks(plugin, contrib.hooks, out);
|
|
75
|
+
if (config) {
|
|
76
|
+
hookInputs.push({ pluginId: plugin.id, pluginDir: plugin.rootDir, config });
|
|
77
|
+
out.pluginHooks.push({ pluginId: plugin.id, events: Object.keys(config) });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (contrib.mcpServers) {
|
|
81
|
+
const servers = await resolvePluginMcpServers(plugin, contrib.mcpServers, out);
|
|
82
|
+
for (const [name, cfg] of Object.entries(servers)) {
|
|
83
|
+
const prevOwner = mcpOwners.get(name);
|
|
84
|
+
if (prevOwner !== undefined) {
|
|
85
|
+
out.mcpCollisions.push({ name, droppedFrom: plugin.id, keptFrom: prevOwner });
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
out.mcpServers[name] = cfg;
|
|
89
|
+
mcpOwners.set(name, plugin.id);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
out.hookRegistry = buildHookRegistry(hookInputs);
|
|
94
|
+
out.hookBus = new HookBus(out.hookRegistry);
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
97
|
+
async function resolvePluginHooks(plugin, contrib, out) {
|
|
98
|
+
let raw;
|
|
99
|
+
if (contrib.kind === 'inline') {
|
|
100
|
+
raw = contrib.data;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
try {
|
|
104
|
+
const text = await fs.readFile(contrib.path, 'utf-8');
|
|
105
|
+
raw = JSON.parse(text);
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
out.hookErrors.push({
|
|
109
|
+
pluginId: plugin.id,
|
|
110
|
+
message: `failed to read hooks file ${contrib.path}: ${err instanceof Error ? err.message : String(err)}`,
|
|
111
|
+
});
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
return parseHookConfig(raw, plugin.id);
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
out.hookErrors.push({
|
|
120
|
+
pluginId: plugin.id,
|
|
121
|
+
message: err instanceof HookConfigParseError ? err.message : String(err),
|
|
122
|
+
});
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/** Extract the `name → cfg` block from the contents of a `.mcp.json`
|
|
127
|
+
* file. Two shapes are accepted:
|
|
128
|
+
*
|
|
129
|
+
* - Wrapped: `{ "mcpServers": { "name": cfg, ... } }`
|
|
130
|
+
* - Flat: `{ "name": cfg, ... }` (no wrapper key)
|
|
131
|
+
*
|
|
132
|
+
* Claude Code's official plugins (e.g. linear@anthropic-marketplace)
|
|
133
|
+
* ship the flat form; the wrapped form matches our own config.json
|
|
134
|
+
* layout. The detection rule is: if the parsed object has a
|
|
135
|
+
* `mcpServers` key at all, treat it as wrapped (and pass through the
|
|
136
|
+
* value as-is so the schema parser produces a clean error on
|
|
137
|
+
* misshape). Otherwise treat the whole object as the flat block. */
|
|
138
|
+
export function extractMcpServersBlock(parsed) {
|
|
139
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
140
|
+
return {};
|
|
141
|
+
const obj = parsed;
|
|
142
|
+
if ('mcpServers' in obj)
|
|
143
|
+
return obj.mcpServers;
|
|
144
|
+
return obj;
|
|
145
|
+
}
|
|
146
|
+
async function resolvePluginMcpServers(plugin, contrib, out) {
|
|
147
|
+
let rawBlock;
|
|
148
|
+
if (contrib.kind === 'inline') {
|
|
149
|
+
rawBlock = contrib.data;
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
try {
|
|
153
|
+
const raw = await fs.readFile(contrib.path, 'utf-8');
|
|
154
|
+
const parsed = JSON.parse(raw);
|
|
155
|
+
rawBlock = extractMcpServersBlock(parsed);
|
|
156
|
+
}
|
|
157
|
+
catch (err) {
|
|
158
|
+
out.mcpErrors.push({
|
|
159
|
+
pluginId: plugin.id,
|
|
160
|
+
message: `failed to read mcpServers file ${contrib.path}: ${err instanceof Error ? err.message : String(err)}`,
|
|
161
|
+
});
|
|
162
|
+
return {};
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const { servers, errors } = parseServersBlock(rawBlock);
|
|
166
|
+
for (const e of errors) {
|
|
167
|
+
out.mcpErrors.push({ pluginId: plugin.id, message: `mcpServers.${e.name}: ${e.message}` });
|
|
168
|
+
}
|
|
169
|
+
// Merge the owning plugin's userConfig values into each server's env
|
|
170
|
+
// map. Authors who want an API key from a userConfig field declared
|
|
171
|
+
// in the manifest just reference it as a normal env var inside the
|
|
172
|
+
// mcpServers entry (or skip the explicit reference and rely on the
|
|
173
|
+
// child process's inherited env). Pre-existing server env entries win
|
|
174
|
+
// so an author can override a userConfig value per-server if needed.
|
|
175
|
+
try {
|
|
176
|
+
const pluginEnv = await getPluginUserConfigEnv(plugin.id);
|
|
177
|
+
if (Object.keys(pluginEnv).length > 0) {
|
|
178
|
+
for (const name of Object.keys(servers)) {
|
|
179
|
+
const cfg = servers[name];
|
|
180
|
+
// Only stdio servers spawn a child process and accept env vars —
|
|
181
|
+
// HTTP servers are remote endpoints, env merging is meaningless.
|
|
182
|
+
if (isStdioConfig(cfg)) {
|
|
183
|
+
servers[name] = { ...cfg, env: { ...pluginEnv, ...(cfg.env ?? {}) } };
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
catch (err) {
|
|
189
|
+
out.mcpErrors.push({ pluginId: plugin.id, message: `userConfig env merge: ${String(err)}` });
|
|
190
|
+
}
|
|
191
|
+
return servers;
|
|
192
|
+
}
|
|
193
|
+
/** Convenience: log non-fatal integration diagnostics to debug.log so
|
|
194
|
+
* `/plugin doctor` and ad-hoc support can find them. CLI startup calls
|
|
195
|
+
* this after `buildPluginIntegration` returns. */
|
|
196
|
+
export function debugLogIntegrationDiagnostics(integration) {
|
|
197
|
+
for (const c of integration.commandsDirs) {
|
|
198
|
+
debugLog('plugins.commands-loaded', `${c.pluginId} commands dir: ${c.dir}`);
|
|
199
|
+
}
|
|
200
|
+
for (const h of integration.pluginHooks) {
|
|
201
|
+
debugLog('plugins.hooks-registered', `${h.pluginId} hooks: [${h.events.join(', ')}]`);
|
|
202
|
+
}
|
|
203
|
+
for (const e of integration.hookErrors) {
|
|
204
|
+
debugLog('plugins.hook-error', `${e.pluginId}: ${e.message}`);
|
|
205
|
+
}
|
|
206
|
+
for (const c of integration.mcpCollisions) {
|
|
207
|
+
debugLog('plugins.mcp-collision', `mcpServer "${c.name}" from ${c.droppedFrom} dropped (kept ${c.keptFrom})`);
|
|
208
|
+
}
|
|
209
|
+
for (const e of integration.mcpErrors) {
|
|
210
|
+
debugLog('plugins.mcp-error', `${e.pluginId}: ${e.message}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
/** Re-scan plugins from disk and return just the merged plugin-contributed
|
|
214
|
+
* mcpServers block. Used by `/mcp refresh` to include plugin servers in
|
|
215
|
+
* the merged map (so they aren't silently dropped on standalone MCP
|
|
216
|
+
* refresh) and by `/plugin refresh` indirectly via buildPluginIntegration.
|
|
217
|
+
*
|
|
218
|
+
* Returns `{}` (not undefined) so callers can spread it unconditionally.
|
|
219
|
+
* Scan failures degrade to `{}` + debug log — callers shouldn't have an
|
|
220
|
+
* MCP-only refresh fail because of a plugin-system hiccup. */
|
|
221
|
+
export async function getPluginMcpServersFromDisk(cwd) {
|
|
222
|
+
try {
|
|
223
|
+
const load = await loadAllPlugins({ cwd });
|
|
224
|
+
const integration = await buildPluginIntegration(load);
|
|
225
|
+
return integration.mcpServers;
|
|
226
|
+
}
|
|
227
|
+
catch (err) {
|
|
228
|
+
debugLog('plugins.mcp-scan-failed', `getPluginMcpServersFromDisk: ${String(err)}`);
|
|
229
|
+
return {};
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
export { loadAllPlugins };
|
|
233
|
+
//# sourceMappingURL=integration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integration.js","sourceRoot":"","sources":["../../src/plugins/integration.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { PluginRegistry } from './registry.js';
|
|
2
|
+
import type { InlineHookConfig, InlineMcpServers, LoadedPlugin } from './types.js';
|
|
3
|
+
export interface LoadOptions {
|
|
4
|
+
/** Current working directory. Used to find project-local plugins. */
|
|
5
|
+
cwd: string;
|
|
6
|
+
/** Skip plugin loading entirely. Wired to the `--no-plugins` startup
|
|
7
|
+
* flag. Returns an empty registry. */
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface LoadResult {
|
|
11
|
+
registry: PluginRegistry;
|
|
12
|
+
/** Per-plugin resolved contribution paths. Workflow B (skill / agent /
|
|
13
|
+
* mcp loader integration) reads from here to merge in plugin-provided
|
|
14
|
+
* content. Keyed by plugin id. */
|
|
15
|
+
contributions: Map<string, ResolvedContributions>;
|
|
16
|
+
}
|
|
17
|
+
/** A plugin's manifest contributions, with relative paths resolved
|
|
18
|
+
* against `rootDir`. The `path` / `inline` discriminator on `mcpServers`
|
|
19
|
+
* and `hooks` reflects the manifest's union — authors can either point
|
|
20
|
+
* at a file or inline the config. */
|
|
21
|
+
export interface ResolvedContributions {
|
|
22
|
+
/** Absolute path to the plugin's skills directory, if any. Each
|
|
23
|
+
* subdir under here is expected to follow the existing
|
|
24
|
+
* `<name>/SKILL.md` layout (so the skill loader can scan it
|
|
25
|
+
* without changes). */
|
|
26
|
+
skillsDir?: string;
|
|
27
|
+
/** Absolute path to the plugin's sub-agent .md files dir. */
|
|
28
|
+
agentsDir?: string;
|
|
29
|
+
/** Absolute path to the plugin's slash-command .md files dir. */
|
|
30
|
+
commandsDir?: string;
|
|
31
|
+
/** mcpServers contribution — either a path to a JSON file shaped like
|
|
32
|
+
* `{ mcpServers: { ... } }` or the inline record (matches the
|
|
33
|
+
* ~/.x-code/config.json `mcpServers` shape). */
|
|
34
|
+
mcpServers?: {
|
|
35
|
+
kind: 'path';
|
|
36
|
+
path: string;
|
|
37
|
+
} | {
|
|
38
|
+
kind: 'inline';
|
|
39
|
+
data: InlineMcpServers;
|
|
40
|
+
};
|
|
41
|
+
/** hooks contribution — path to hooks.json or inline object. Schema
|
|
42
|
+
* validation lives in packages/core/src/hooks (workflow C). */
|
|
43
|
+
hooks?: {
|
|
44
|
+
kind: 'path';
|
|
45
|
+
path: string;
|
|
46
|
+
} | {
|
|
47
|
+
kind: 'inline';
|
|
48
|
+
data: InlineHookConfig;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export declare function loadAllPlugins(opts: LoadOptions): Promise<LoadResult>;
|
|
52
|
+
/** Resolve a plugin's manifest contribution fields into absolute paths
|
|
53
|
+
* (or inline objects). Exported because individual callers occasionally
|
|
54
|
+
* need to recompute this (e.g. `/plugin info` for a single plugin).
|
|
55
|
+
*
|
|
56
|
+
* **Two discovery passes per contribution kind:**
|
|
57
|
+
*
|
|
58
|
+
* 1. **Manifest-declared** — if the manifest names a path (e.g.
|
|
59
|
+
* `"skills": "./my-skills"`), use that.
|
|
60
|
+
* 2. **Convention-based fallback** — if not declared, probe the
|
|
61
|
+
* conventional directory (`skills/`, `agents/`, `commands/`) and
|
|
62
|
+
* the conventional file (`hooks/hooks.json`, `.mcp.json`,
|
|
63
|
+
* `mcp.json`). This is how real Claude Code plugins work — their
|
|
64
|
+
* manifests typically only carry `name`/`version`/`description` and
|
|
65
|
+
* drop the contributions next to it.
|
|
66
|
+
*
|
|
67
|
+
* Async because the convention probe has to stat directories. */
|
|
68
|
+
export declare function resolveContributions(plugin: LoadedPlugin): Promise<ResolvedContributions>;
|
|
69
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/plugins/loader.ts"],"names":[],"mappings":"AAkCA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAC9C,OAAO,KAAK,EACV,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EAKb,MAAM,YAAY,CAAA;AAEnB,MAAM,WAAW,WAAW;IAC1B,qEAAqE;IACrE,GAAG,EAAE,MAAM,CAAA;IACX;2CACuC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,cAAc,CAAA;IACxB;;uCAEmC;IACnC,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAA;CAClD;AAED;;;sCAGsC;AACtC,MAAM,WAAW,qBAAqB;IACpC;;;4BAGwB;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,6DAA6D;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;qDAEiD;IACjD,UAAU,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,IAAI,EAAE,gBAAgB,CAAA;KAAE,CAAA;IACxF;oEACgE;IAChE,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,IAAI,EAAE,gBAAgB,CAAA;KAAE,CAAA;CACpF;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAsD3E;AA4ED;;;;;;;;;;;;;;;kEAekE;AAClE,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,qBAAqB,CAAC,CA0D/F"}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
// @x-code-cli/core — Plugin startup loader
|
|
2
|
+
//
|
|
3
|
+
// One-shot orchestration called from the CLI entry. Two passes:
|
|
4
|
+
//
|
|
5
|
+
// Pass 1 — user-scope installs from installed_plugins.json. Each
|
|
6
|
+
// record points at a versioned cache dir; we load whichever
|
|
7
|
+
// version the record names. Orphan records (record present but
|
|
8
|
+
// cache dir missing) surface as PluginLoadError.
|
|
9
|
+
//
|
|
10
|
+
// Pass 2 — project-local plugins under <cwd>/.x-code/plugins/<name>/.
|
|
11
|
+
// These aren't tracked in installed_plugins.json — they're
|
|
12
|
+
// committed to the repo as in-tree plugins. Marketplace name
|
|
13
|
+
// is always "local" for these.
|
|
14
|
+
//
|
|
15
|
+
// `installed_plugins.json` is the source of truth for user-scope installs.
|
|
16
|
+
// Orphan cache dirs (no record) are silently ignored — they'll be cleaned
|
|
17
|
+
// up next time the user runs `/plugin uninstall`.
|
|
18
|
+
//
|
|
19
|
+
// One broken plugin (bad JSON, missing manifest, schema violation) never
|
|
20
|
+
// aborts the boot — errors collect into a `PluginLoadError[]` for
|
|
21
|
+
// `/plugin doctor` to surface.
|
|
22
|
+
//
|
|
23
|
+
// The returned `PluginRegistry` is meant to be frozen for the session
|
|
24
|
+
// (same byte-stability constraint as MCP / skills — see CLAUDE.md). The
|
|
25
|
+
// CLI calls `loadAllPlugins()` once at startup and stashes the result on
|
|
26
|
+
// `AgentOptions`. `/plugin refresh` swaps the in-memory state via
|
|
27
|
+
// `registry.reload(...)` and invalidates `systemPromptCache`.
|
|
28
|
+
import fs from 'node:fs/promises';
|
|
29
|
+
import path from 'node:path';
|
|
30
|
+
import { EnableState } from './enable-state.js';
|
|
31
|
+
import { listInstalledPlugins } from './installer.js';
|
|
32
|
+
import { ManifestParseError, discoverManifest, parseManifest } from './manifest.js';
|
|
33
|
+
import { pluginCacheDir, projectPluginsDir } from './paths.js';
|
|
34
|
+
import { PluginRegistry } from './registry.js';
|
|
35
|
+
export async function loadAllPlugins(opts) {
|
|
36
|
+
if (opts.disabled) {
|
|
37
|
+
return { registry: new PluginRegistry([], []), contributions: new Map() };
|
|
38
|
+
}
|
|
39
|
+
const enableState = await EnableState.load(opts.cwd);
|
|
40
|
+
const plugins = [];
|
|
41
|
+
const errors = [];
|
|
42
|
+
const contributions = new Map();
|
|
43
|
+
// ── Pass 1: user-scope installs ────────────────────────────────────────
|
|
44
|
+
const installed = await listInstalledPlugins();
|
|
45
|
+
for (const record of installed) {
|
|
46
|
+
const rootDir = pluginCacheDir(record.marketplace, record.name, record.version);
|
|
47
|
+
await loadOnePlugin({
|
|
48
|
+
rootDir,
|
|
49
|
+
fallbackId: record.id,
|
|
50
|
+
marketplace: record.marketplace,
|
|
51
|
+
scope: record.installScope,
|
|
52
|
+
source: record.source,
|
|
53
|
+
enableState,
|
|
54
|
+
plugins,
|
|
55
|
+
errors,
|
|
56
|
+
contributions,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
// ── Pass 2: project-local plugins ──────────────────────────────────────
|
|
60
|
+
const projectRoot = projectPluginsDir(opts.cwd);
|
|
61
|
+
let projectEntries = [];
|
|
62
|
+
try {
|
|
63
|
+
projectEntries = await fs.readdir(projectRoot, { withFileTypes: true });
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
/* no project plugins dir — common case */
|
|
67
|
+
}
|
|
68
|
+
for (const entry of projectEntries) {
|
|
69
|
+
if (!entry.isDirectory())
|
|
70
|
+
continue;
|
|
71
|
+
const pluginRoot = path.join(projectRoot, entry.name);
|
|
72
|
+
await loadOnePlugin({
|
|
73
|
+
rootDir: pluginRoot,
|
|
74
|
+
// Provisional id from dirname; overridden by manifest.name when we
|
|
75
|
+
// parse it.
|
|
76
|
+
fallbackId: `${entry.name}@local`,
|
|
77
|
+
marketplace: 'local',
|
|
78
|
+
scope: 'project',
|
|
79
|
+
source: undefined,
|
|
80
|
+
enableState,
|
|
81
|
+
plugins,
|
|
82
|
+
errors,
|
|
83
|
+
contributions,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
return { registry: new PluginRegistry(plugins, errors), contributions };
|
|
87
|
+
}
|
|
88
|
+
async function loadOnePlugin(args) {
|
|
89
|
+
try {
|
|
90
|
+
const discovery = await discoverManifest(args.rootDir);
|
|
91
|
+
if (!discovery) {
|
|
92
|
+
args.errors.push({
|
|
93
|
+
id: args.fallbackId,
|
|
94
|
+
path: args.rootDir,
|
|
95
|
+
message: 'no plugin manifest found (looked for .x-code-plugin/plugin.json, .claude-plugin/plugin.json, plugin.json)',
|
|
96
|
+
});
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (discovery.format === 'gemini') {
|
|
100
|
+
args.errors.push({
|
|
101
|
+
id: args.fallbackId,
|
|
102
|
+
path: args.rootDir,
|
|
103
|
+
message: 'Gemini extensions are not supported (gemini-extension.json detected); see docs/plugins.md',
|
|
104
|
+
});
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
let manifest;
|
|
108
|
+
try {
|
|
109
|
+
manifest = await parseManifest(discovery.manifestPath);
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
args.errors.push({
|
|
113
|
+
id: args.fallbackId,
|
|
114
|
+
path: args.rootDir,
|
|
115
|
+
message: err instanceof ManifestParseError ? err.message : String(err),
|
|
116
|
+
});
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
// Canonical id always comes from the manifest, never from the cache
|
|
120
|
+
// dir name. For installed plugins this matches the recorded id; for
|
|
121
|
+
// project-local plugins it may differ from the dirname and the
|
|
122
|
+
// manifest wins.
|
|
123
|
+
const id = `${manifest.name}@${args.marketplace}`;
|
|
124
|
+
const enableResolution = args.enableState.resolve(id);
|
|
125
|
+
const plugin = {
|
|
126
|
+
id,
|
|
127
|
+
manifest,
|
|
128
|
+
rootDir: args.rootDir,
|
|
129
|
+
manifestPath: discovery.manifestPath,
|
|
130
|
+
manifestFormat: discovery.format,
|
|
131
|
+
source: args.source,
|
|
132
|
+
marketplace: args.marketplace,
|
|
133
|
+
scope: args.scope,
|
|
134
|
+
enabled: enableResolution.enabled,
|
|
135
|
+
};
|
|
136
|
+
args.plugins.push(plugin);
|
|
137
|
+
args.contributions.set(id, await resolveContributions(plugin));
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
args.errors.push({
|
|
141
|
+
id: args.fallbackId,
|
|
142
|
+
path: args.rootDir,
|
|
143
|
+
message: err instanceof Error ? err.message : String(err),
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/** Resolve a plugin's manifest contribution fields into absolute paths
|
|
148
|
+
* (or inline objects). Exported because individual callers occasionally
|
|
149
|
+
* need to recompute this (e.g. `/plugin info` for a single plugin).
|
|
150
|
+
*
|
|
151
|
+
* **Two discovery passes per contribution kind:**
|
|
152
|
+
*
|
|
153
|
+
* 1. **Manifest-declared** — if the manifest names a path (e.g.
|
|
154
|
+
* `"skills": "./my-skills"`), use that.
|
|
155
|
+
* 2. **Convention-based fallback** — if not declared, probe the
|
|
156
|
+
* conventional directory (`skills/`, `agents/`, `commands/`) and
|
|
157
|
+
* the conventional file (`hooks/hooks.json`, `.mcp.json`,
|
|
158
|
+
* `mcp.json`). This is how real Claude Code plugins work — their
|
|
159
|
+
* manifests typically only carry `name`/`version`/`description` and
|
|
160
|
+
* drop the contributions next to it.
|
|
161
|
+
*
|
|
162
|
+
* Async because the convention probe has to stat directories. */
|
|
163
|
+
export async function resolveContributions(plugin) {
|
|
164
|
+
const m = plugin.manifest;
|
|
165
|
+
const root = plugin.rootDir;
|
|
166
|
+
const result = {};
|
|
167
|
+
// skills / agents / commands — directory contributions
|
|
168
|
+
if (m.skills) {
|
|
169
|
+
result.skillsDir = path.resolve(root, m.skills);
|
|
170
|
+
}
|
|
171
|
+
else if (await isDir(path.join(root, 'skills'))) {
|
|
172
|
+
result.skillsDir = path.join(root, 'skills');
|
|
173
|
+
}
|
|
174
|
+
if (m.agents) {
|
|
175
|
+
result.agentsDir = path.resolve(root, m.agents);
|
|
176
|
+
}
|
|
177
|
+
else if (await isDir(path.join(root, 'agents'))) {
|
|
178
|
+
result.agentsDir = path.join(root, 'agents');
|
|
179
|
+
}
|
|
180
|
+
if (m.commands) {
|
|
181
|
+
result.commandsDir = path.resolve(root, m.commands);
|
|
182
|
+
}
|
|
183
|
+
else if (await isDir(path.join(root, 'commands'))) {
|
|
184
|
+
result.commandsDir = path.join(root, 'commands');
|
|
185
|
+
}
|
|
186
|
+
// mcpServers — either declared (path / inline) or auto-discovered
|
|
187
|
+
// from a conventional file
|
|
188
|
+
if (m.mcpServers !== undefined) {
|
|
189
|
+
if (typeof m.mcpServers === 'string') {
|
|
190
|
+
result.mcpServers = { kind: 'path', path: path.resolve(root, m.mcpServers) };
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
result.mcpServers = { kind: 'inline', data: m.mcpServers };
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
// Claude Code convention: `.mcp.json` at plugin root. We also
|
|
198
|
+
// accept `mcp.json` (without dot) as a pragmatic fallback —
|
|
199
|
+
// some authors use the visible form.
|
|
200
|
+
for (const conv of ['.mcp.json', 'mcp.json']) {
|
|
201
|
+
const p = path.join(root, conv);
|
|
202
|
+
if (await isFile(p)) {
|
|
203
|
+
result.mcpServers = { kind: 'path', path: p };
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// hooks — same pattern, conventional file `hooks/hooks.json`
|
|
209
|
+
if (m.hooks !== undefined) {
|
|
210
|
+
if (typeof m.hooks === 'string') {
|
|
211
|
+
result.hooks = { kind: 'path', path: path.resolve(root, m.hooks) };
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
result.hooks = { kind: 'inline', data: m.hooks };
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
const conv = path.join(root, 'hooks', 'hooks.json');
|
|
219
|
+
if (await isFile(conv)) {
|
|
220
|
+
result.hooks = { kind: 'path', path: conv };
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return result;
|
|
224
|
+
}
|
|
225
|
+
async function isDir(p) {
|
|
226
|
+
try {
|
|
227
|
+
const s = await fs.stat(p);
|
|
228
|
+
return s.isDirectory();
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
async function isFile(p) {
|
|
235
|
+
try {
|
|
236
|
+
const s = await fs.stat(p);
|
|
237
|
+
return s.isFile();
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/plugins/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ManifestFormat, PluginManifest } from './types.js';
|
|
2
|
+
export interface ManifestDiscovery {
|
|
3
|
+
/** Absolute path to the manifest file. */
|
|
4
|
+
manifestPath: string;
|
|
5
|
+
format: ManifestFormat;
|
|
6
|
+
}
|
|
7
|
+
/** Probe a plugin root for a manifest. Returns the highest-priority
|
|
8
|
+
* match. Returns `{ format: 'gemini', ... }` when ONLY a Gemini manifest
|
|
9
|
+
* exists — the installer uses this to produce a friendly "we don't
|
|
10
|
+
* support Gemini extensions" error rather than a confusing
|
|
11
|
+
* "no manifest found". */
|
|
12
|
+
export declare function discoverManifest(rootDir: string): Promise<ManifestDiscovery | null>;
|
|
13
|
+
export declare class ManifestParseError extends Error {
|
|
14
|
+
readonly manifestPath: string;
|
|
15
|
+
constructor(message: string, manifestPath: string);
|
|
16
|
+
}
|
|
17
|
+
/** Parse + validate a manifest JSON file. Fills in `schemaVersion: "1"`
|
|
18
|
+
* when absent (the implicit default — most existing Claude Code plugins
|
|
19
|
+
* don't set this field). Throws `ManifestParseError` with a path-tagged
|
|
20
|
+
* message on failure so the loader can collect it as a doctor entry
|
|
21
|
+
* without aborting the whole boot. */
|
|
22
|
+
export declare function parseManifest(manifestPath: string): Promise<PluginManifest>;
|
|
23
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/plugins/manifest.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAiEhE,MAAM,WAAW,iBAAiB;IAChC,0CAA0C;IAC1C,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,cAAc,CAAA;CACvB;AAED;;;;2BAI2B;AAC3B,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAYzF;AAID,qBAAa,kBAAmB,SAAQ,KAAK;aAGzB,YAAY,EAAE,MAAM;gBADpC,OAAO,EAAE,MAAM,EACC,YAAY,EAAE,MAAM;CAKvC;AAED;;;;uCAIuC;AACvC,wBAAsB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAoCjF"}
|