@x-code-cli/core 0.2.10 → 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 +134 -5
- 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 +4 -1
- package/dist/permissions/session-store.d.ts.map +1 -1
- package/dist/permissions/session-store.js +6 -1
- 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/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,416 @@
|
|
|
1
|
+
// @x-code-cli/core — Plugin installer
|
|
2
|
+
//
|
|
3
|
+
// Three supported source kinds:
|
|
4
|
+
//
|
|
5
|
+
// - 'local' filesystem directory → copied recursively into cache
|
|
6
|
+
// (skipping .git / node_modules / OS junk)
|
|
7
|
+
// - 'git' arbitrary git URL → shallow-cloned (depth 1, optional ref)
|
|
8
|
+
// - 'github' github:owner/repo → shallow-cloned via resolveCloneUrl
|
|
9
|
+
// Monorepo `subdir` supported: whole repo is shallow-cloned,
|
|
10
|
+
// the named subdir is copied into a fresh temp dir, the rest
|
|
11
|
+
// discarded.
|
|
12
|
+
//
|
|
13
|
+
// Install flow:
|
|
14
|
+
// 1. Fetch source into a temp dir
|
|
15
|
+
// 2. Discover + parse manifest (reject Gemini-only sources here)
|
|
16
|
+
// 3. Compute final cache path: cache/<marketplace>/<plugin>/<version>/
|
|
17
|
+
// 4. Wipe any existing install at that path (re-install / same-version upgrade)
|
|
18
|
+
// 5. Move temp → final (rename when possible, copy+rm fallback for EXDEV)
|
|
19
|
+
// 6. Append/update installed_plugins.json
|
|
20
|
+
//
|
|
21
|
+
// AbortSignal threads through git clone (via execa's `signal`) and the
|
|
22
|
+
// recursive copy (cooperative check between entries) so Esc during a long
|
|
23
|
+
// install cleanly cancels in-flight work.
|
|
24
|
+
//
|
|
25
|
+
// Cache layout is deliberately per-version so `/plugin update` can install
|
|
26
|
+
// a new version side-by-side and atomically switch (a later improvement);
|
|
27
|
+
// today we just overwrite same-version installs.
|
|
28
|
+
import { execa } from 'execa';
|
|
29
|
+
import fs from 'node:fs/promises';
|
|
30
|
+
import os from 'node:os';
|
|
31
|
+
import path from 'node:path';
|
|
32
|
+
import { debugLog } from '../utils.js';
|
|
33
|
+
import { buildConsentPreview, probePluginRoot } from './consent.js';
|
|
34
|
+
import { ManifestParseError, discoverManifest, parseManifest } from './manifest.js';
|
|
35
|
+
import { RESERVED_MARKETPLACE_NAMES, readKnownMarketplaces, resolveCloneUrl } from './marketplace.js';
|
|
36
|
+
import { installedPluginsPath, pluginCacheDir, pluginCacheParent } from './paths.js';
|
|
37
|
+
import { setPluginUserConfig } from './user-config.js';
|
|
38
|
+
export class InstallError extends Error {
|
|
39
|
+
constructor(message) {
|
|
40
|
+
super(message);
|
|
41
|
+
this.name = 'InstallError';
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export async function installPlugin(req) {
|
|
45
|
+
// ── Pre-flight policy checks (cheap, fail-fast) ──
|
|
46
|
+
// `strictKnownMarketplaces` and `blockedPlugins` come from
|
|
47
|
+
// ~/.x-code/plugins/known_marketplaces.json. When the admin
|
|
48
|
+
// (typically enterprise) has opted into strict mode, every install
|
|
49
|
+
// must come from a subscribed marketplace — direct git / github /
|
|
50
|
+
// local installs are denied. `blockedPlugins` is checked after the
|
|
51
|
+
// manifest is parsed (we need the canonical id).
|
|
52
|
+
const km = await readKnownMarketplaces();
|
|
53
|
+
if (km.strictKnownMarketplaces) {
|
|
54
|
+
const subscribed = km.marketplaces.some((m) => m.name === req.marketplace);
|
|
55
|
+
if (!subscribed) {
|
|
56
|
+
throw new InstallError(`strict marketplace mode is enabled (known_marketplaces.json:strictKnownMarketplaces=true) — ` +
|
|
57
|
+
`plugins can only be installed from a subscribed marketplace, but "${req.marketplace}" is not one. ` +
|
|
58
|
+
`Either subscribe it first (\`xc plugin marketplace add\`) or turn strict mode off.`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const tempDir = await fetchToTemp(req.source, req.signal);
|
|
62
|
+
try {
|
|
63
|
+
const discovery = await discoverManifest(tempDir);
|
|
64
|
+
if (!discovery) {
|
|
65
|
+
throw new InstallError('no plugin manifest found in source (looked for .x-code-plugin/plugin.json, .claude-plugin/plugin.json, plugin.json)');
|
|
66
|
+
}
|
|
67
|
+
if (discovery.format === 'gemini') {
|
|
68
|
+
throw new InstallError('this is a Gemini extension (gemini-extension.json) — x-code-cli does not support Gemini extensions; see docs/plugins.md');
|
|
69
|
+
}
|
|
70
|
+
let manifest;
|
|
71
|
+
try {
|
|
72
|
+
manifest = await parseManifest(discovery.manifestPath);
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
if (err instanceof ManifestParseError)
|
|
76
|
+
throw new InstallError(err.message);
|
|
77
|
+
throw err;
|
|
78
|
+
}
|
|
79
|
+
if (req.expectedName && manifest.name !== req.expectedName) {
|
|
80
|
+
throw new InstallError(`manifest name "${manifest.name}" does not match expected "${req.expectedName}"`);
|
|
81
|
+
}
|
|
82
|
+
// Now that we know the canonical plugin id, run the second
|
|
83
|
+
// policy check: blockedPlugins from known_marketplaces.json. This
|
|
84
|
+
// is an admin-style force-disable list — an install attempt for
|
|
85
|
+
// a blocked id is rejected regardless of marketplace / consent.
|
|
86
|
+
// Two match forms are accepted:
|
|
87
|
+
// - Fully-qualified id `name@marketplace` — precise (admin can
|
|
88
|
+
// block one marketplace's variant without affecting forks)
|
|
89
|
+
// - Bare name `name` — broad (admin can block every marketplace's
|
|
90
|
+
// plugin with that name in one shot; matches the npm `--ignore`
|
|
91
|
+
// style some admins expect)
|
|
92
|
+
const earlyId = `${manifest.name}@${req.marketplace}`;
|
|
93
|
+
const blocked = km.blockedPlugins?.find((b) => b === earlyId || b === manifest.name);
|
|
94
|
+
if (blocked) {
|
|
95
|
+
throw new InstallError(`plugin "${earlyId}" is on the blockedPlugins list in known_marketplaces.json ` +
|
|
96
|
+
`(matched entry: "${blocked}") — remove it from that list (or use a different plugin) to install.`);
|
|
97
|
+
}
|
|
98
|
+
// ── Consent gate ──
|
|
99
|
+
// Built from the parsed manifest so the caller can render a
|
|
100
|
+
// preview of what the plugin will contribute (hooks, mcp, scopes)
|
|
101
|
+
// and ask the user explicitly. Skipping the prompt (callback
|
|
102
|
+
// absent) is intentional for non-interactive paths — the CLI
|
|
103
|
+
// implements `--yes` by simply not passing `consent`.
|
|
104
|
+
if (req.consent) {
|
|
105
|
+
const rootProbe = await probePluginRoot(tempDir);
|
|
106
|
+
const preview = buildConsentPreview({
|
|
107
|
+
pluginId: `${manifest.name}@${req.marketplace}`,
|
|
108
|
+
manifest,
|
|
109
|
+
source: req.source,
|
|
110
|
+
marketplace: req.marketplace,
|
|
111
|
+
verified: req.verified,
|
|
112
|
+
fromReservedMarketplace: req.marketplace in RESERVED_MARKETPLACE_NAMES,
|
|
113
|
+
rootProbe,
|
|
114
|
+
});
|
|
115
|
+
const accepted = await req.consent(preview);
|
|
116
|
+
if (!accepted) {
|
|
117
|
+
throw new InstallError('install cancelled by user (consent declined)');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// ── userConfig prompt (post-consent, pre-commit) ──
|
|
121
|
+
// Only fires when the manifest declares userConfig fields AND the
|
|
122
|
+
// caller wired a prompt callback. Non-interactive paths (--yes, CI)
|
|
123
|
+
// skip the prompt — fields stay unset and the plugin sees empty env
|
|
124
|
+
// vars at hook / mcp launch time, same as before this feature.
|
|
125
|
+
// Returning null from the prompt aborts the install (treated like
|
|
126
|
+
// consent denial); a non-null object is persisted via setPluginUserConfig.
|
|
127
|
+
if (manifest.userConfig && manifest.userConfig.length > 0 && req.userConfigPrompt) {
|
|
128
|
+
const collected = await req.userConfigPrompt(manifest.userConfig);
|
|
129
|
+
if (collected === null) {
|
|
130
|
+
throw new InstallError('install cancelled by user (userConfig prompt aborted)');
|
|
131
|
+
}
|
|
132
|
+
// Persist BEFORE moving the temp dir to cache so a crash between
|
|
133
|
+
// the two phases leaves the user with no broken plugin and no
|
|
134
|
+
// orphaned secret. The settings file is keyed by plugin id and
|
|
135
|
+
// overwrites cleanly on reinstall.
|
|
136
|
+
const pluginIdForConfig = `${manifest.name}@${req.marketplace}`;
|
|
137
|
+
await setPluginUserConfig(pluginIdForConfig, collected);
|
|
138
|
+
}
|
|
139
|
+
const finalDir = pluginCacheDir(req.marketplace, manifest.name, manifest.version);
|
|
140
|
+
// Same-version reinstall: wipe existing install first. Skipping this
|
|
141
|
+
// would leave stale files mixed with new ones if the new version drops
|
|
142
|
+
// a file the old version had.
|
|
143
|
+
await fs.rm(finalDir, { recursive: true, force: true });
|
|
144
|
+
await fs.mkdir(path.dirname(finalDir), { recursive: true });
|
|
145
|
+
await moveOrCopy(tempDir, finalDir, req.signal);
|
|
146
|
+
const pluginId = `${manifest.name}@${req.marketplace}`;
|
|
147
|
+
const record = {
|
|
148
|
+
id: pluginId,
|
|
149
|
+
name: manifest.name,
|
|
150
|
+
marketplace: req.marketplace,
|
|
151
|
+
version: manifest.version,
|
|
152
|
+
source: req.source,
|
|
153
|
+
installedAt: new Date().toISOString(),
|
|
154
|
+
installScope: req.scope ?? 'user',
|
|
155
|
+
};
|
|
156
|
+
await recordInstallation(record);
|
|
157
|
+
return { pluginId, rootDir: finalDir, manifest, manifestFormat: discovery.format, record };
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
// Best-effort cleanup of the temp dir on any failure mid-install. The
|
|
161
|
+
// moveOrCopy success path renames the temp away, so this only fires
|
|
162
|
+
// when something went wrong before the move.
|
|
163
|
+
await fs.rm(tempDir, { recursive: true, force: true }).catch(() => {
|
|
164
|
+
/* nothing useful to do */
|
|
165
|
+
});
|
|
166
|
+
if (err instanceof InstallError || err instanceof ManifestParseError)
|
|
167
|
+
throw err;
|
|
168
|
+
throw new InstallError(err instanceof Error ? err.message : String(err));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// ── Source → temp dir ───────────────────────────────────────────────────
|
|
172
|
+
async function fetchToTemp(source, signal) {
|
|
173
|
+
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'xc-plugin-install-'));
|
|
174
|
+
if (source.kind === 'local') {
|
|
175
|
+
const resolved = path.resolve(source.path);
|
|
176
|
+
const stat = await fs.stat(resolved).catch(() => null);
|
|
177
|
+
if (!stat || !stat.isDirectory()) {
|
|
178
|
+
await fs.rm(tempDir, { recursive: true, force: true }).catch(() => { });
|
|
179
|
+
// Surface cwd in the error: relative paths get resolved against
|
|
180
|
+
// process.cwd(), and when xc is launched via `pnpm dev` the cwd
|
|
181
|
+
// is `packages/cli/`, not the repo root — that mismatch confuses
|
|
182
|
+
// users typing `./foo` in the slash command. Showing both the
|
|
183
|
+
// resolved absolute path and the cwd makes the cause obvious.
|
|
184
|
+
const isRelative = !path.isAbsolute(source.path);
|
|
185
|
+
const cwdHint = isRelative ? ` (resolved relative to cwd: ${process.cwd()})` : '';
|
|
186
|
+
throw new InstallError(`local source is not a directory: ${resolved}${cwdHint}`);
|
|
187
|
+
}
|
|
188
|
+
await copyDirFiltered(resolved, tempDir, signal);
|
|
189
|
+
return tempDir;
|
|
190
|
+
}
|
|
191
|
+
if (source.kind === 'git' || source.kind === 'github') {
|
|
192
|
+
const cloneUrl = source.kind === 'git' ? source.url : resolveCloneUrl(`github:${source.owner}/${source.repo}`);
|
|
193
|
+
const args = ['clone', '--depth', '1'];
|
|
194
|
+
if (source.ref)
|
|
195
|
+
args.push('--branch', source.ref);
|
|
196
|
+
// For subdir installs we still shallow-clone the whole repo. Real
|
|
197
|
+
// sparse-checkout would be faster on huge monorepos but the
|
|
198
|
+
// `--depth 1 --filter=blob:none --sparse` sequence is fragile across
|
|
199
|
+
// git versions; a depth-1 clone of even a large monorepo is usually
|
|
200
|
+
// <100 MB. Revisit if it becomes a pain point.
|
|
201
|
+
args.push(cloneUrl, tempDir);
|
|
202
|
+
try {
|
|
203
|
+
await execa('git', args, { signal, stdio: 'pipe' });
|
|
204
|
+
}
|
|
205
|
+
catch (err) {
|
|
206
|
+
await fs.rm(tempDir, { recursive: true, force: true }).catch(() => { });
|
|
207
|
+
throw new InstallError(`git clone failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
208
|
+
}
|
|
209
|
+
// Integrity check: when the marketplace.json pinned a `sha`, verify
|
|
210
|
+
// that the commit we actually cloned matches it. Defends against the
|
|
211
|
+
// upstream ref being force-pushed or the repo being compromised
|
|
212
|
+
// between marketplace review and end-user install. Must run BEFORE
|
|
213
|
+
// we drop `.git` below (rev-parse needs the repo metadata).
|
|
214
|
+
//
|
|
215
|
+
// Prefix-match semantics: declared sha can be a short sha (≥7 hex)
|
|
216
|
+
// and still validate against the full 40-char HEAD — same tolerance
|
|
217
|
+
// as `git checkout <short-sha>` and what real marketplaces produce
|
|
218
|
+
// (anthropics/claude-plugins-official sometimes ships 7-char shas).
|
|
219
|
+
//
|
|
220
|
+
// Why hard fail and not warn: a sha mismatch is by definition either
|
|
221
|
+
// a misconfigured marketplace.json (author bug) or a real
|
|
222
|
+
// supply-chain anomaly. Either way the user shouldn't end up with
|
|
223
|
+
// unreviewed code on disk. Better to surface a loud error pointing
|
|
224
|
+
// at the marketplace author than to silently install whatever HEAD
|
|
225
|
+
// happens to be.
|
|
226
|
+
if (source.expectedSha) {
|
|
227
|
+
try {
|
|
228
|
+
const result = await execa('git', ['rev-parse', 'HEAD'], { cwd: tempDir, stdio: 'pipe', signal });
|
|
229
|
+
const actualSha = result.stdout.trim().toLowerCase();
|
|
230
|
+
const expected = source.expectedSha.toLowerCase();
|
|
231
|
+
if (!actualSha.startsWith(expected)) {
|
|
232
|
+
await fs.rm(tempDir, { recursive: true, force: true }).catch(() => { });
|
|
233
|
+
throw new InstallError(`sha integrity check failed for ${cloneUrl}${source.ref ? `@${source.ref}` : ''}: ` +
|
|
234
|
+
`marketplace.json declared sha=${expected}, actual HEAD=${actualSha}. ` +
|
|
235
|
+
`The upstream ref may have been force-pushed or the repo compromised. ` +
|
|
236
|
+
`Contact the marketplace author or pin to a different version.`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
catch (err) {
|
|
240
|
+
if (err instanceof InstallError)
|
|
241
|
+
throw err;
|
|
242
|
+
// rev-parse failed (shouldn't happen on a fresh clone) — treat
|
|
243
|
+
// as integrity failure so we don't silently install unchecked.
|
|
244
|
+
await fs.rm(tempDir, { recursive: true, force: true }).catch(() => { });
|
|
245
|
+
throw new InstallError(`failed to verify sha for ${cloneUrl}: ${err instanceof Error ? err.message : String(err)}`);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// Drop the .git dir — we never need it after install and it would
|
|
249
|
+
// bloat the cache significantly for large-history repos.
|
|
250
|
+
await fs.rm(path.join(tempDir, '.git'), { recursive: true, force: true }).catch(() => { });
|
|
251
|
+
// Subdir handling: the plugin actually lives at <tempDir>/<subdir>.
|
|
252
|
+
// Re-stage so the rest of the install flow (manifest discovery +
|
|
253
|
+
// moveOrCopy to cache) operates on just that subdir. Simplest
|
|
254
|
+
// approach: copy the subdir into a fresh temp dir, discard the
|
|
255
|
+
// original clone.
|
|
256
|
+
const subdir = source.subdir;
|
|
257
|
+
if (subdir) {
|
|
258
|
+
const subdirPath = path.join(tempDir, subdir);
|
|
259
|
+
const stat = await fs.stat(subdirPath).catch(() => null);
|
|
260
|
+
if (!stat || !stat.isDirectory()) {
|
|
261
|
+
await fs.rm(tempDir, { recursive: true, force: true }).catch(() => { });
|
|
262
|
+
throw new InstallError(`subdir "${subdir}" not found in cloned repo ${cloneUrl}`);
|
|
263
|
+
}
|
|
264
|
+
const subdirTemp = await fs.mkdtemp(path.join(os.tmpdir(), 'xc-plugin-subdir-'));
|
|
265
|
+
try {
|
|
266
|
+
await copyDirFiltered(subdirPath, subdirTemp, signal);
|
|
267
|
+
}
|
|
268
|
+
catch (err) {
|
|
269
|
+
await fs.rm(subdirTemp, { recursive: true, force: true }).catch(() => { });
|
|
270
|
+
await fs.rm(tempDir, { recursive: true, force: true }).catch(() => { });
|
|
271
|
+
throw new InstallError(`failed to extract subdir: ${err instanceof Error ? err.message : String(err)}`);
|
|
272
|
+
}
|
|
273
|
+
await fs.rm(tempDir, { recursive: true, force: true }).catch(() => { });
|
|
274
|
+
return subdirTemp;
|
|
275
|
+
}
|
|
276
|
+
return tempDir;
|
|
277
|
+
}
|
|
278
|
+
await fs.rm(tempDir, { recursive: true, force: true }).catch(() => { });
|
|
279
|
+
throw new InstallError(`unknown source kind: ${source.kind}`);
|
|
280
|
+
}
|
|
281
|
+
/** Names we never copy through. `node_modules` is excluded because a
|
|
282
|
+
* bundled-deps plugin should reinstall on the user's machine; if a
|
|
283
|
+
* plugin genuinely needs node_modules we'll revisit. */
|
|
284
|
+
const COPY_SKIP = new Set(['.git', 'node_modules', '.DS_Store', 'Thumbs.db']);
|
|
285
|
+
async function copyDirFiltered(src, dst, signal, root) {
|
|
286
|
+
// `root` is captured on the first (non-recursive) call so the symlink
|
|
287
|
+
// escape check below validates against the original plugin source, not
|
|
288
|
+
// the current recursion's `src` (which moves with each subdir).
|
|
289
|
+
const rootDir = root ?? src;
|
|
290
|
+
await fs.mkdir(dst, { recursive: true });
|
|
291
|
+
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
292
|
+
for (const entry of entries) {
|
|
293
|
+
signal?.throwIfAborted();
|
|
294
|
+
if (COPY_SKIP.has(entry.name))
|
|
295
|
+
continue;
|
|
296
|
+
const s = path.join(src, entry.name);
|
|
297
|
+
const d = path.join(dst, entry.name);
|
|
298
|
+
if (entry.isDirectory()) {
|
|
299
|
+
await copyDirFiltered(s, d, signal, rootDir);
|
|
300
|
+
}
|
|
301
|
+
else if (entry.isFile()) {
|
|
302
|
+
await fs.copyFile(s, d);
|
|
303
|
+
}
|
|
304
|
+
else if (entry.isSymbolicLink()) {
|
|
305
|
+
// Resolve the symlink target relative to its containing directory.
|
|
306
|
+
// If the resolved target escapes the plugin source root, drop the
|
|
307
|
+
// symlink rather than preserve it: on POSIX a `evil -> /etc/passwd`
|
|
308
|
+
// in the plugin tree would put a host-file pointer in the cache for
|
|
309
|
+
// loader / hooks to deref at runtime; on Windows the fallback below
|
|
310
|
+
// would copy `/etc/passwd`-equivalents straight into the cache.
|
|
311
|
+
// We don't follow the symlink to validate that the target exists —
|
|
312
|
+
// a broken-but-in-bounds symlink is still safe to preserve.
|
|
313
|
+
const target = await fs.readlink(s);
|
|
314
|
+
const resolved = path.resolve(path.dirname(s), target);
|
|
315
|
+
const rel = path.relative(rootDir, resolved);
|
|
316
|
+
if (rel === '' || rel.startsWith('..') || path.isAbsolute(rel)) {
|
|
317
|
+
debugLog('plugins.copy-symlink-escape', `${s} -> ${target} (resolved ${resolved}, outside ${rootDir})`);
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
try {
|
|
321
|
+
await fs.symlink(target, d);
|
|
322
|
+
}
|
|
323
|
+
catch {
|
|
324
|
+
// Windows without symlink privilege: fall back to copying the
|
|
325
|
+
// resolved file. Best effort — broken symlinks just get dropped.
|
|
326
|
+
await fs.copyFile(s, d).catch(() => { });
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
/** Move from temp → final dir. Rename is atomic + cheap when src and dst
|
|
332
|
+
* are on the same filesystem; otherwise (EXDEV on Windows mostly) we
|
|
333
|
+
* fall back to copy + rm. */
|
|
334
|
+
async function moveOrCopy(src, dst, signal) {
|
|
335
|
+
try {
|
|
336
|
+
await fs.rename(src, dst);
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
catch (err) {
|
|
340
|
+
const code = err.code;
|
|
341
|
+
if (code !== 'EXDEV' && code !== 'EPERM' && code !== 'ENOTEMPTY') {
|
|
342
|
+
// Surfacing the original error here would block install for transient
|
|
343
|
+
// weirdness; the copy fallback below succeeds in all the cases we've
|
|
344
|
+
// seen in the wild. Still log for postmortem.
|
|
345
|
+
debugLog('plugins.install-rename-fallback', String(err));
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
await copyDirFiltered(src, dst, signal);
|
|
349
|
+
await fs.rm(src, { recursive: true, force: true }).catch(() => { });
|
|
350
|
+
}
|
|
351
|
+
// ── installed_plugins.json bookkeeping ──────────────────────────────────
|
|
352
|
+
async function readInstalledPlugins() {
|
|
353
|
+
const file = installedPluginsPath();
|
|
354
|
+
try {
|
|
355
|
+
const raw = await fs.readFile(file, 'utf-8');
|
|
356
|
+
const parsed = JSON.parse(raw);
|
|
357
|
+
if (!parsed || typeof parsed !== 'object' || !Array.isArray(parsed.plugins)) {
|
|
358
|
+
return { schemaVersion: '1', plugins: [] };
|
|
359
|
+
}
|
|
360
|
+
return { schemaVersion: parsed.schemaVersion ?? '1', plugins: parsed.plugins };
|
|
361
|
+
}
|
|
362
|
+
catch {
|
|
363
|
+
return { schemaVersion: '1', plugins: [] };
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
async function writeInstalledPlugins(data) {
|
|
367
|
+
const file = installedPluginsPath();
|
|
368
|
+
await fs.mkdir(path.dirname(file), { recursive: true });
|
|
369
|
+
await fs.writeFile(file, JSON.stringify(data, null, 2) + '\n', 'utf-8');
|
|
370
|
+
}
|
|
371
|
+
async function recordInstallation(record) {
|
|
372
|
+
const data = await readInstalledPlugins();
|
|
373
|
+
const idx = data.plugins.findIndex((p) => p.id === record.id);
|
|
374
|
+
if (idx >= 0)
|
|
375
|
+
data.plugins[idx] = record;
|
|
376
|
+
else
|
|
377
|
+
data.plugins.push(record);
|
|
378
|
+
await writeInstalledPlugins(data);
|
|
379
|
+
}
|
|
380
|
+
export async function listInstalledPlugins() {
|
|
381
|
+
const data = await readInstalledPlugins();
|
|
382
|
+
return data.plugins;
|
|
383
|
+
}
|
|
384
|
+
export async function findInstalledPlugin(id) {
|
|
385
|
+
const data = await readInstalledPlugins();
|
|
386
|
+
return data.plugins.find((p) => p.id === id);
|
|
387
|
+
}
|
|
388
|
+
/** Remove all cached versions of a plugin + drop its
|
|
389
|
+
* installed_plugins.json record. Leaves the data dir
|
|
390
|
+
* (`~/.x-code/plugins/data/<id>/`) intact so the user doesn't lose
|
|
391
|
+
* state if they reinstall later. */
|
|
392
|
+
export async function uninstallPlugin(id) {
|
|
393
|
+
const record = await findInstalledPlugin(id);
|
|
394
|
+
const result = { removedVersions: [], removedRecord: false };
|
|
395
|
+
if (record) {
|
|
396
|
+
const parent = pluginCacheParent(record.marketplace, record.name);
|
|
397
|
+
try {
|
|
398
|
+
const versions = await fs.readdir(parent);
|
|
399
|
+
result.removedVersions = versions;
|
|
400
|
+
await fs.rm(parent, { recursive: true, force: true });
|
|
401
|
+
}
|
|
402
|
+
catch {
|
|
403
|
+
// No cache entries — the record might be stale. Removing the record
|
|
404
|
+
// below still happens.
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
const data = await readInstalledPlugins();
|
|
408
|
+
const before = data.plugins.length;
|
|
409
|
+
data.plugins = data.plugins.filter((p) => p.id !== id);
|
|
410
|
+
if (data.plugins.length !== before) {
|
|
411
|
+
await writeInstalledPlugins(data);
|
|
412
|
+
result.removedRecord = true;
|
|
413
|
+
}
|
|
414
|
+
return result;
|
|
415
|
+
}
|
|
416
|
+
//# sourceMappingURL=installer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installer.js","sourceRoot":"","sources":["../../src/plugins/installer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { HookBus } from '../hooks/bus.js';
|
|
2
|
+
import { HookRegistry } from '../hooks/registry.js';
|
|
3
|
+
import type { McpServerConfig } from '../mcp/types.js';
|
|
4
|
+
import { loadAllPlugins } from './loader.js';
|
|
5
|
+
import type { LoadResult } from './loader.js';
|
|
6
|
+
export interface PluginIntegrationOutput {
|
|
7
|
+
/** Extra skill directories the skill loader should scan, with the
|
|
8
|
+
* owning plugin id stamped on each. Only enabled plugins included. */
|
|
9
|
+
skillsDirs: Array<{
|
|
10
|
+
dir: string;
|
|
11
|
+
pluginId: string;
|
|
12
|
+
}>;
|
|
13
|
+
/** Same as above for sub-agent .md files. */
|
|
14
|
+
agentsDirs: Array<{
|
|
15
|
+
dir: string;
|
|
16
|
+
pluginId: string;
|
|
17
|
+
}>;
|
|
18
|
+
/** Same as above for slash command `*.md` files. Each entry carries
|
|
19
|
+
* the owning plugin's rootDir so the command body can substitute
|
|
20
|
+
* `${CLAUDE_PLUGIN_ROOT}` at activation time. */
|
|
21
|
+
commandsDirs: Array<{
|
|
22
|
+
dir: string;
|
|
23
|
+
pluginId: string;
|
|
24
|
+
pluginRoot: string;
|
|
25
|
+
}>;
|
|
26
|
+
/** Merged `mcpServers` block from every enabled plugin. Name
|
|
27
|
+
* collisions resolved first-wins; the losers are recorded in
|
|
28
|
+
* `mcpCollisions`. */
|
|
29
|
+
mcpServers: Record<string, McpServerConfig>;
|
|
30
|
+
/** Hook registry built from every enabled plugin's `hooks` config.
|
|
31
|
+
* Empty when no plugin declared any hooks. Hand this to
|
|
32
|
+
* `new HookBus(...)` to wire the agent loop's emit-sites. */
|
|
33
|
+
hookRegistry: HookRegistry;
|
|
34
|
+
/** Ready-to-use bus over `hookRegistry`. Convenience for the CLI
|
|
35
|
+
* startup wiring — `AgentOptions.hookBus = integration.hookBus`. */
|
|
36
|
+
hookBus: HookBus;
|
|
37
|
+
/** Per-plugin summary of which event names had hooks — used by
|
|
38
|
+
* `/plugin doctor` and `/plugin info` UI. */
|
|
39
|
+
pluginHooks: Array<{
|
|
40
|
+
pluginId: string;
|
|
41
|
+
events: string[];
|
|
42
|
+
}>;
|
|
43
|
+
/** mcpServers entries dropped due to name collision with an earlier
|
|
44
|
+
* plugin. `{ name, droppedFrom, keptFrom }`. */
|
|
45
|
+
mcpCollisions: Array<{
|
|
46
|
+
name: string;
|
|
47
|
+
droppedFrom: string;
|
|
48
|
+
keptFrom: string;
|
|
49
|
+
}>;
|
|
50
|
+
/** mcpServers parse / read errors per plugin — these don't block
|
|
51
|
+
* startup, they surface in `/plugin doctor`. */
|
|
52
|
+
mcpErrors: Array<{
|
|
53
|
+
pluginId: string;
|
|
54
|
+
message: string;
|
|
55
|
+
}>;
|
|
56
|
+
/** Hooks parse / read errors per plugin. */
|
|
57
|
+
hookErrors: Array<{
|
|
58
|
+
pluginId: string;
|
|
59
|
+
message: string;
|
|
60
|
+
}>;
|
|
61
|
+
}
|
|
62
|
+
export declare function buildPluginIntegration(load: LoadResult): Promise<PluginIntegrationOutput>;
|
|
63
|
+
/** Extract the `name → cfg` block from the contents of a `.mcp.json`
|
|
64
|
+
* file. Two shapes are accepted:
|
|
65
|
+
*
|
|
66
|
+
* - Wrapped: `{ "mcpServers": { "name": cfg, ... } }`
|
|
67
|
+
* - Flat: `{ "name": cfg, ... }` (no wrapper key)
|
|
68
|
+
*
|
|
69
|
+
* Claude Code's official plugins (e.g. linear@anthropic-marketplace)
|
|
70
|
+
* ship the flat form; the wrapped form matches our own config.json
|
|
71
|
+
* layout. The detection rule is: if the parsed object has a
|
|
72
|
+
* `mcpServers` key at all, treat it as wrapped (and pass through the
|
|
73
|
+
* value as-is so the schema parser produces a clean error on
|
|
74
|
+
* misshape). Otherwise treat the whole object as the flat block. */
|
|
75
|
+
export declare function extractMcpServersBlock(parsed: unknown): unknown;
|
|
76
|
+
/** Convenience: log non-fatal integration diagnostics to debug.log so
|
|
77
|
+
* `/plugin doctor` and ad-hoc support can find them. CLI startup calls
|
|
78
|
+
* this after `buildPluginIntegration` returns. */
|
|
79
|
+
export declare function debugLogIntegrationDiagnostics(integration: PluginIntegrationOutput): void;
|
|
80
|
+
/** Re-scan plugins from disk and return just the merged plugin-contributed
|
|
81
|
+
* mcpServers block. Used by `/mcp refresh` to include plugin servers in
|
|
82
|
+
* the merged map (so they aren't silently dropped on standalone MCP
|
|
83
|
+
* refresh) and by `/plugin refresh` indirectly via buildPluginIntegration.
|
|
84
|
+
*
|
|
85
|
+
* Returns `{}` (not undefined) so callers can spread it unconditionally.
|
|
86
|
+
* Scan failures degrade to `{}` + debug log — callers shouldn't have an
|
|
87
|
+
* MCP-only refresh fail because of a plugin-system hiccup. */
|
|
88
|
+
export declare function getPluginMcpServersFromDisk(cwd: string): Promise<Record<string, McpServerConfig>>;
|
|
89
|
+
export type { LoadResult, ResolvedContributions } from './loader.js';
|
|
90
|
+
export { loadAllPlugins };
|
|
91
|
+
//# sourceMappingURL=integration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integration.d.ts","sourceRoot":"","sources":["../../src/plugins/integration.ts"],"names":[],"mappings":"AAoCA,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAEzC,OAAO,EAAE,YAAY,EAAqB,MAAM,sBAAsB,CAAA;AAItE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEtD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAyB,MAAM,aAAa,CAAA;AAIpE,MAAM,WAAW,uBAAuB;IACtC;2EACuE;IACvE,UAAU,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACpD,6CAA6C;IAC7C,UAAU,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACpD;;sDAEkD;IAClD,YAAY,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC1E;;2BAEuB;IACvB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;IAC3C;;kEAE8D;IAC9D,YAAY,EAAE,YAAY,CAAA;IAC1B;yEACqE;IACrE,OAAO,EAAE,OAAO,CAAA;IAChB;kDAC8C;IAC9C,WAAW,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAA;IAC1D;qDACiD;IACjD,aAAa,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC7E;qDACiD;IACjD,SAAS,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACvD,4CAA4C;IAC5C,UAAU,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACzD;AAED,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAuD/F;AAiCD;;;;;;;;;;;qEAWqE;AACrE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAK/D;AAsDD;;mDAEmD;AACnD,wBAAgB,8BAA8B,CAAC,WAAW,EAAE,uBAAuB,GAAG,IAAI,CAgBzF;AAED;;;;;;;+DAO+D;AAC/D,wBAAsB,2BAA2B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CASvG;AAID,YAAY,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACpE,OAAO,EAAE,cAAc,EAAE,CAAA"}
|