@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 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/plugins/types.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,EAAE;AACF,wEAAwE;AACxE,uEAAuE;AACvE,yEAAyE;AACzE,oEAAoE;AACpE,wEAAwE;AACxE,gBAAgB;AAChB,EAAE;AACF,sEAAsE;AACtE,2EAA2E;AAC3E,sEAAsE;AACtE,yEAAyE;AACzE,0CAA0C"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Value type for a single field. The manifest `type` field (string /
|
|
2
|
+
* number / boolean) is enforced at prompt time, but we round-trip
|
|
3
|
+
* through JSON which only knows these three primitives anyway. */
|
|
4
|
+
export type UserConfigValue = string | number | boolean;
|
|
5
|
+
/** Per-plugin user-config map: keyed by the manifest's `key` field. */
|
|
6
|
+
export type PluginUserConfig = Record<string, UserConfigValue>;
|
|
7
|
+
/** Read the saved config for one plugin. Returns an empty object when
|
|
8
|
+
* the plugin has no saved config yet — caller can default keys from
|
|
9
|
+
* the manifest. */
|
|
10
|
+
export declare function getPluginUserConfig(pluginId: string): Promise<PluginUserConfig>;
|
|
11
|
+
/** Write the config for one plugin. Merges with existing fields rather
|
|
12
|
+
* than replacing — caller can call this once per field if they want
|
|
13
|
+
* (e.g. interactive prompt loop). */
|
|
14
|
+
export declare function setPluginUserConfig(pluginId: string, values: PluginUserConfig): Promise<void>;
|
|
15
|
+
/** Drop the config for one plugin (e.g. on uninstall). */
|
|
16
|
+
export declare function clearPluginUserConfig(pluginId: string): Promise<void>;
|
|
17
|
+
/** Materialise a plugin's user-config map as an env-var record ready to
|
|
18
|
+
* be merged into a child process's environment. Each manifest key
|
|
19
|
+
* becomes the env var name; numbers and booleans coerce to their
|
|
20
|
+
* string forms. Unset fields are skipped (env vars left untouched). */
|
|
21
|
+
export declare function getPluginUserConfigEnv(pluginId: string): Promise<Record<string, string>>;
|
|
22
|
+
//# sourceMappingURL=user-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-config.d.ts","sourceRoot":"","sources":["../../src/plugins/user-config.ts"],"names":[],"mappings":"AAmCA;;mEAEmE;AACnE,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;AAEvD,uEAAuE;AACvE,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;AAgC9D;;oBAEoB;AACpB,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAGrF;AAED;;sCAEsC;AACtC,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAInG;AAED,0DAA0D;AAC1D,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAK3E;AAED;;;wEAGwE;AACxE,wBAAsB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAO9F"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// @x-code-cli/core — Plugin userConfig storage
|
|
2
|
+
//
|
|
3
|
+
// Each plugin can declare a `userConfig` block in its manifest — a list of
|
|
4
|
+
// fields the plugin needs from the user (API keys, account ids, working
|
|
5
|
+
// directories, etc). At install time the CLI prompts for each field's
|
|
6
|
+
// value; this module owns the on-disk persistence layer.
|
|
7
|
+
//
|
|
8
|
+
// Layout:
|
|
9
|
+
//
|
|
10
|
+
// ~/.x-code/plugins/user-config.json → {
|
|
11
|
+
// [pluginId]: { [key]: <value> }
|
|
12
|
+
// }
|
|
13
|
+
//
|
|
14
|
+
// Storage format is a plain JSON map; the file is created with 0600
|
|
15
|
+
// (owner-read-write only) so a process in another user's session can't
|
|
16
|
+
// read sensitive values. This is NOT a substitute for a real OS keychain
|
|
17
|
+
// (macOS Keychain / Windows Credential Manager / Linux libsecret) — it's
|
|
18
|
+
// a pragmatic v1 that avoids the native-build complexity. The
|
|
19
|
+
// `sensitive: true` field still drives mask-on-input at prompt time; only
|
|
20
|
+
// the at-rest storage shares one file.
|
|
21
|
+
//
|
|
22
|
+
// A future enhancement will move `sensitive` entries to a real keychain.
|
|
23
|
+
// The reader merges from both sources, so adding it later is a non-
|
|
24
|
+
// breaking change.
|
|
25
|
+
//
|
|
26
|
+
// Why not split sensitive vs non-sensitive into separate files: it would
|
|
27
|
+
// just multiply file IO without raising the security bar (both files live
|
|
28
|
+
// in the same dir with the same perms). Real protection requires a real
|
|
29
|
+
// keychain; until then, one file is honest about what we're doing.
|
|
30
|
+
import fs from 'node:fs/promises';
|
|
31
|
+
import path from 'node:path';
|
|
32
|
+
import { debugLog } from '../utils.js';
|
|
33
|
+
import { pluginsRoot } from './paths.js';
|
|
34
|
+
function userConfigPath() {
|
|
35
|
+
return path.join(pluginsRoot(), 'user-config.json');
|
|
36
|
+
}
|
|
37
|
+
async function readFile() {
|
|
38
|
+
try {
|
|
39
|
+
const raw = await fs.readFile(userConfigPath(), 'utf-8');
|
|
40
|
+
const parsed = JSON.parse(raw);
|
|
41
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
42
|
+
return {};
|
|
43
|
+
return parsed;
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
if (err.code === 'ENOENT')
|
|
47
|
+
return {};
|
|
48
|
+
debugLog('plugins.user-config-read-error', String(err));
|
|
49
|
+
return {};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async function writeFile(data) {
|
|
53
|
+
const p = userConfigPath();
|
|
54
|
+
await fs.mkdir(path.dirname(p), { recursive: true });
|
|
55
|
+
// 0600 keeps the file readable only by the owning user. On Windows
|
|
56
|
+
// this is a no-op (fs.chmod doesn't translate to ACLs the same way) —
|
|
57
|
+
// there's nothing meaningful we can do without shelling out to icacls.
|
|
58
|
+
// The keychain followup will solve Windows properly.
|
|
59
|
+
await fs.writeFile(p, JSON.stringify(data, null, 2) + '\n', { mode: 0o600 });
|
|
60
|
+
}
|
|
61
|
+
/** Read the saved config for one plugin. Returns an empty object when
|
|
62
|
+
* the plugin has no saved config yet — caller can default keys from
|
|
63
|
+
* the manifest. */
|
|
64
|
+
export async function getPluginUserConfig(pluginId) {
|
|
65
|
+
const all = await readFile();
|
|
66
|
+
return all[pluginId] ?? {};
|
|
67
|
+
}
|
|
68
|
+
/** Write the config for one plugin. Merges with existing fields rather
|
|
69
|
+
* than replacing — caller can call this once per field if they want
|
|
70
|
+
* (e.g. interactive prompt loop). */
|
|
71
|
+
export async function setPluginUserConfig(pluginId, values) {
|
|
72
|
+
const all = await readFile();
|
|
73
|
+
all[pluginId] = { ...(all[pluginId] ?? {}), ...values };
|
|
74
|
+
await writeFile(all);
|
|
75
|
+
}
|
|
76
|
+
/** Drop the config for one plugin (e.g. on uninstall). */
|
|
77
|
+
export async function clearPluginUserConfig(pluginId) {
|
|
78
|
+
const all = await readFile();
|
|
79
|
+
if (!(pluginId in all))
|
|
80
|
+
return;
|
|
81
|
+
delete all[pluginId];
|
|
82
|
+
await writeFile(all);
|
|
83
|
+
}
|
|
84
|
+
/** Materialise a plugin's user-config map as an env-var record ready to
|
|
85
|
+
* be merged into a child process's environment. Each manifest key
|
|
86
|
+
* becomes the env var name; numbers and booleans coerce to their
|
|
87
|
+
* string forms. Unset fields are skipped (env vars left untouched). */
|
|
88
|
+
export async function getPluginUserConfigEnv(pluginId) {
|
|
89
|
+
const cfg = await getPluginUserConfig(pluginId);
|
|
90
|
+
const env = {};
|
|
91
|
+
for (const [k, v] of Object.entries(cfg)) {
|
|
92
|
+
env[k] = String(v);
|
|
93
|
+
}
|
|
94
|
+
return env;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=user-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-config.js","sourceRoot":"","sources":["../../src/plugins/user-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,11 @@ export interface CacheControlArgs {
|
|
|
5
5
|
system: string;
|
|
6
6
|
/** Conversation messages to send. */
|
|
7
7
|
messages: ModelMessage[];
|
|
8
|
+
/** Tool registry passed to streamText. For Anthropic we tag the last entry
|
|
9
|
+
* with cache_control so the whole tools schema enters the cache prefix.
|
|
10
|
+
* buildTools() returns the same Record reference for the session, so key
|
|
11
|
+
* order — and therefore the cached prefix — is byte-stable across turns. */
|
|
12
|
+
tools?: Record<string, any>;
|
|
8
13
|
/** provider:model id used to select the caching strategy. */
|
|
9
14
|
modelId: string;
|
|
10
15
|
/** Stable per-session key. Used by OpenAI's `promptCacheKey` to pin
|
|
@@ -17,6 +22,10 @@ export interface CacheControlResult {
|
|
|
17
22
|
* called without a separate `system` param. */
|
|
18
23
|
system?: string;
|
|
19
24
|
messages: ModelMessage[];
|
|
25
|
+
/** For Anthropic, a shallow-cloned tools record with cache_control attached
|
|
26
|
+
* to the last entry. Other providers get the input record returned as-is
|
|
27
|
+
* (or undefined if none was passed). */
|
|
28
|
+
tools?: Record<string, any>;
|
|
20
29
|
/** Top-level providerOptions to pass through to streamText. */
|
|
21
30
|
providerOptions?: Record<string, unknown>;
|
|
22
31
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache-control.d.ts","sourceRoot":"","sources":["../../src/providers/cache-control.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cache-control.d.ts","sourceRoot":"","sources":["../../src/providers/cache-control.ts"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,IAAI,CAAA;AAYtC,MAAM,WAAW,gBAAgB;IAC/B;uDACmD;IACnD,MAAM,EAAE,MAAM,CAAA;IACd,qCAAqC;IACrC,QAAQ,EAAE,YAAY,EAAE,CAAA;IACxB;;;iFAG6E;IAE7E,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC3B,6DAA6D;IAC7D,OAAO,EAAE,MAAM,CAAA;IACf;sDACkD;IAClD,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC;;oDAEgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,YAAY,EAAE,CAAA;IACxB;;6CAEyC;IAEzC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC3B,+DAA+D;IAC/D,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC1C;AAyBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,gBAAgB,GAAG,kBAAkB,CAoC5E"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { providerOf } from './capabilities.js';
|
|
2
2
|
/** Max messages we attach an Anthropic cache breakpoint to. Anthropic allows
|
|
3
3
|
* up to 4 `cache_control` blocks per request; we spend one on the system
|
|
4
|
-
* prompt
|
|
5
|
-
* opencode's testing — a third
|
|
6
|
-
* region (the just-before-last
|
|
4
|
+
* prompt and one on the last tool definition, leaving two for the message
|
|
5
|
+
* tail. Two is the sweet spot from opencode's testing — a third message
|
|
6
|
+
* breakpoint costs a cache-write against a region (the just-before-last
|
|
7
|
+
* message) that's about to be evicted anyway. */
|
|
7
8
|
const MESSAGE_CACHE_BREAKPOINTS = 2;
|
|
8
9
|
/** Attach the given providerOptions entry to a message non-destructively. */
|
|
9
10
|
function tagMessage(msg, provider, entry) {
|
|
@@ -42,6 +43,7 @@ export function applyCacheControl(args) {
|
|
|
42
43
|
return {
|
|
43
44
|
system: undefined,
|
|
44
45
|
messages: [anthropicSystemMessage(args.system), ...tagged],
|
|
46
|
+
tools: tagLastTool(args.tools),
|
|
45
47
|
};
|
|
46
48
|
}
|
|
47
49
|
if (provider === 'openai') {
|
|
@@ -51,6 +53,7 @@ export function applyCacheControl(args) {
|
|
|
51
53
|
return {
|
|
52
54
|
system: args.system,
|
|
53
55
|
messages: args.messages,
|
|
56
|
+
tools: args.tools,
|
|
54
57
|
providerOptions: {
|
|
55
58
|
openai: { promptCacheKey: args.sessionId, store: false },
|
|
56
59
|
},
|
|
@@ -59,6 +62,30 @@ export function applyCacheControl(args) {
|
|
|
59
62
|
// OpenAI-compatible & Gemini: no explicit flags, just rely on stable prefix.
|
|
60
63
|
// Callers must ensure buildSystemPrompt is cached in LoopState so the same
|
|
61
64
|
// system string is re-sent every turn.
|
|
62
|
-
return { system: args.system, messages: args.messages };
|
|
65
|
+
return { system: args.system, messages: args.messages, tools: args.tools };
|
|
66
|
+
}
|
|
67
|
+
/** Shallow-clone `tools` and attach an Anthropic cache_control breakpoint to
|
|
68
|
+
* the last entry, so the entire tools schema enters one cached prefix slot.
|
|
69
|
+
* Returns the input unchanged when there are no tools — Anthropic rejects
|
|
70
|
+
* empty `cache_control` on a non-existent block and there's nothing to
|
|
71
|
+
* cache anyway. */
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
73
|
+
function tagLastTool(tools) {
|
|
74
|
+
if (!tools)
|
|
75
|
+
return tools;
|
|
76
|
+
const names = Object.keys(tools);
|
|
77
|
+
if (names.length === 0)
|
|
78
|
+
return tools;
|
|
79
|
+
const lastName = names[names.length - 1];
|
|
80
|
+
const lastTool = tools[lastName];
|
|
81
|
+
const existing = (lastTool?.providerOptions ?? {});
|
|
82
|
+
const tagged = {
|
|
83
|
+
...lastTool,
|
|
84
|
+
providerOptions: {
|
|
85
|
+
...existing,
|
|
86
|
+
anthropic: { ...(existing.anthropic ?? {}), cacheControl: { type: 'ephemeral' } },
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
return { ...tools, [lastName]: tagged };
|
|
63
90
|
}
|
|
64
91
|
//# sourceMappingURL=cache-control.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache-control.js","sourceRoot":"","sources":["../../src/providers/cache-control.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cache-control.js","sourceRoot":"","sources":["../../src/providers/cache-control.ts"],"names":[],"mappings":"AAoCA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE9C;;;;;kDAKkD;AAClD,MAAM,yBAAyB,GAAG,CAAC,CAAA;AAoCnC,6EAA6E;AAC7E,SAAS,UAAU,CAAC,GAAiB,EAAE,QAAgB,EAAE,KAA8B;IACrF,MAAM,QAAQ,GAAI,GAAqE,CAAC,eAAe,IAAI,EAAE,CAAA;IAC7G,OAAO;QACL,GAAG,GAAG;QACN,eAAe,EAAE;YACf,GAAG,QAAQ;YACX,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,KAAK,EAAE;SACxD;KACc,CAAA;AACnB,CAAC;AAED,yEAAyE;AACzE,SAAS,sBAAsB,CAAC,MAAc;IAC5C,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,MAAM;QACf,eAAe,EAAE;YACf,SAAS,EAAE,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE;SACnD;KACyB,CAAA;AAC9B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAsB;IACtD,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAEzC,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;QAC7B,uEAAuE;QACvE,iEAAiE;QACjE,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,yBAAyB,CAAC,CAAA;QACrE,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,CAAA;QACtC,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACrC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,EAAE,WAAW,EAAE,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CACzF,CAAA;QACD,OAAO;YACL,MAAM,EAAE,SAAS;YACjB,QAAQ,EAAE,CAAC,sBAAsB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC;YAC1D,KAAK,EAAE,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC;SAC/B,CAAA;IACH,CAAC;IAED,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1B,yEAAyE;QACzE,sEAAsE;QACtE,iDAAiD;QACjD,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,eAAe,EAAE;gBACf,MAAM,EAAE,EAAE,cAAc,EAAE,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE;aACzD;SACF,CAAA;IACH,CAAC;IAED,6EAA6E;IAC7E,2EAA2E;IAC3E,uCAAuC;IACvC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAA;AAC5E,CAAC;AAED;;;;oBAIoB;AACpB,8DAA8D;AAC9D,SAAS,WAAW,CAAC,KAAsC;IACzD,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAA;IACxB,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAChC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IACpC,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IACxC,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAA;IAChC,MAAM,QAAQ,GAAG,CAAC,QAAQ,EAAE,eAAe,IAAI,EAAE,CAA4C,CAAA;IAC7F,MAAM,MAAM,GAAG;QACb,GAAG,QAAQ;QACX,eAAe,EAAE;YACf,GAAG,QAAQ;YACX,SAAS,EAAE,EAAE,GAAG,CAAC,QAAQ,CAAC,SAAS,IAAI,EAAE,CAAC,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE;SAClF;KACF,CAAA;IACD,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;AACzC,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { SkillDefinition } from './registry.js';
|
|
2
|
+
export interface LoadSkillsOptions {
|
|
3
|
+
/** Extra skill directories to scan after the built-in user + project
|
|
4
|
+
* paths. Used to fold plugin-contributed `skills/` directories into
|
|
5
|
+
* the same registry — see packages/core/src/plugins/integration.ts.
|
|
6
|
+
* Order matters: later entries win on name collision. Plugin skills
|
|
7
|
+
* are scanned BEFORE project skills (so a user-authored project skill
|
|
8
|
+
* can override a plugin skill of the same name). */
|
|
9
|
+
extraDirs?: ReadonlyArray<{
|
|
10
|
+
dir: string;
|
|
11
|
+
pluginId: string;
|
|
12
|
+
}>;
|
|
13
|
+
}
|
|
14
|
+
/** Load skills from user + project directories, plus any extra dirs
|
|
15
|
+
* passed in (used by the plugin system to fold in plugin-contributed
|
|
16
|
+
* skill directories). Environment variable `XC_SKILLS_DIR` overrides
|
|
17
|
+
* the built-in paths for testing (extras are still honoured). */
|
|
18
|
+
export declare function loadSkills(opts?: LoadSkillsOptions): Promise<SkillDefinition[]>;
|
|
19
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/skills/loader.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AA0KpD,MAAM,WAAW,iBAAiB;IAChC;;;;;yDAKqD;IACrD,SAAS,CAAC,EAAE,aAAa,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAC7D;AAED;;;kEAGkE;AAClE,wBAAsB,UAAU,CAAC,IAAI,GAAE,iBAAsB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAkBzF"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
// @x-code-cli/core — Skill loader
|
|
2
|
+
//
|
|
3
|
+
// Scans ~/.x-code/skills/*/SKILL.md and <repo-root>/.x-code/skills/*/SKILL.md
|
|
4
|
+
// for user-defined skills with YAML frontmatter. The subdirectory layout
|
|
5
|
+
// mirrors all major competitors (Gemini CLI, Opencode, Codex) and allows
|
|
6
|
+
// future support files alongside SKILL.md.
|
|
7
|
+
//
|
|
8
|
+
// Priority: project-level skills override user-level skills of the same name.
|
|
9
|
+
// Bad files are skipped with a warning — one broken SKILL.md must never
|
|
10
|
+
// crash the CLI.
|
|
11
|
+
import fs from 'node:fs/promises';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
import { z } from 'zod';
|
|
14
|
+
import { USER_XCODE_DIR, XCODE_DIR } from '../utils.js';
|
|
15
|
+
const SKILL_FILENAME = 'SKILL.md';
|
|
16
|
+
/** Hard upper bound on the file count we list per skill — keeps the
|
|
17
|
+
* activation payload bounded even for skills that ship dozens of
|
|
18
|
+
* references / assets / scripts. Skills exceeding this get a truncation
|
|
19
|
+
* marker appended so the model knows the list isn't exhaustive. */
|
|
20
|
+
const MAX_LISTED_FILES = 50;
|
|
21
|
+
/** Directory names skipped while listing a skill's bundled files —
|
|
22
|
+
* hidden dirs and obvious heavy ones that almost never contain skill
|
|
23
|
+
* resources. Listed by basename, not glob. */
|
|
24
|
+
const SKILL_FILE_LIST_SKIP_DIRS = new Set([
|
|
25
|
+
'node_modules',
|
|
26
|
+
'__pycache__',
|
|
27
|
+
'.git',
|
|
28
|
+
'.venv',
|
|
29
|
+
'venv',
|
|
30
|
+
'dist',
|
|
31
|
+
'build',
|
|
32
|
+
'target',
|
|
33
|
+
]);
|
|
34
|
+
const frontmatterSchema = z.object({
|
|
35
|
+
name: z.string().min(1),
|
|
36
|
+
description: z.string().min(1),
|
|
37
|
+
});
|
|
38
|
+
/** Walk a skill directory and return relative paths of its non-hidden
|
|
39
|
+
* files (excluding SKILL.md itself). Used at load time so SkillRegistry
|
|
40
|
+
* has a ready-to-inject list of bundled resources — Opencode and
|
|
41
|
+
* Gemini CLI do the same listing at activation, but X-Code caches it
|
|
42
|
+
* alongside the SkillDefinition since the registry is frozen for the
|
|
43
|
+
* session anyway (`/skill refresh` rebuilds). */
|
|
44
|
+
async function listSkillFiles(skillDir) {
|
|
45
|
+
const out = [];
|
|
46
|
+
async function walk(currentDir) {
|
|
47
|
+
if (out.length >= MAX_LISTED_FILES)
|
|
48
|
+
return;
|
|
49
|
+
let entries;
|
|
50
|
+
try {
|
|
51
|
+
entries = await fs.readdir(currentDir, { withFileTypes: true });
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
for (const entry of entries) {
|
|
57
|
+
if (out.length >= MAX_LISTED_FILES)
|
|
58
|
+
return;
|
|
59
|
+
if (entry.name.startsWith('.'))
|
|
60
|
+
continue;
|
|
61
|
+
if (entry.isDirectory()) {
|
|
62
|
+
if (SKILL_FILE_LIST_SKIP_DIRS.has(entry.name))
|
|
63
|
+
continue;
|
|
64
|
+
await walk(path.join(currentDir, entry.name));
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (!entry.isFile())
|
|
68
|
+
continue;
|
|
69
|
+
const fullPath = path.join(currentDir, entry.name);
|
|
70
|
+
const rel = path.relative(skillDir, fullPath).split(path.sep).join('/');
|
|
71
|
+
if (rel === SKILL_FILENAME)
|
|
72
|
+
continue;
|
|
73
|
+
out.push(rel);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
await walk(skillDir);
|
|
77
|
+
return out.sort();
|
|
78
|
+
}
|
|
79
|
+
/** Minimal YAML frontmatter parser — reuses the same subset logic as
|
|
80
|
+
* sub-agent loader: string scalars only, no dependency on gray-matter. */
|
|
81
|
+
function parseFrontmatter(raw) {
|
|
82
|
+
const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
|
|
83
|
+
if (!match)
|
|
84
|
+
return null;
|
|
85
|
+
const yamlBlock = match[1];
|
|
86
|
+
const body = match[2];
|
|
87
|
+
const data = {};
|
|
88
|
+
// Fold YAML continuation lines: an indented non-empty line is joined to
|
|
89
|
+
// the previous line with a single space. Mirrors the folded-scalar form
|
|
90
|
+
// used by skill SKILL.md files where a long `description:` is wrapped
|
|
91
|
+
// with 2-space indented continuations.
|
|
92
|
+
const foldedLines = [];
|
|
93
|
+
for (const line of yamlBlock.split(/\r?\n/)) {
|
|
94
|
+
if (/^\s/.test(line) && line.trim() && foldedLines.length > 0) {
|
|
95
|
+
foldedLines[foldedLines.length - 1] += ' ' + line.trim();
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
foldedLines.push(line);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
for (const line of foldedLines) {
|
|
102
|
+
const trimmed = line.trim();
|
|
103
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
104
|
+
continue;
|
|
105
|
+
const colonIdx = trimmed.indexOf(':');
|
|
106
|
+
if (colonIdx < 1)
|
|
107
|
+
continue;
|
|
108
|
+
const key = trimmed.slice(0, colonIdx).trim();
|
|
109
|
+
let value = trimmed.slice(colonIdx + 1).trim();
|
|
110
|
+
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
|
|
111
|
+
value = value.slice(1, -1);
|
|
112
|
+
}
|
|
113
|
+
data[key] = value;
|
|
114
|
+
}
|
|
115
|
+
return { data, body };
|
|
116
|
+
}
|
|
117
|
+
async function loadSkillsFromDir(dir, source, pluginId) {
|
|
118
|
+
const skills = [];
|
|
119
|
+
let entries;
|
|
120
|
+
try {
|
|
121
|
+
entries = await fs.readdir(dir);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return skills;
|
|
125
|
+
}
|
|
126
|
+
for (const entry of entries) {
|
|
127
|
+
const skillDir = path.join(dir, entry);
|
|
128
|
+
const skillFile = path.join(skillDir, SKILL_FILENAME);
|
|
129
|
+
try {
|
|
130
|
+
await fs.access(skillFile);
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
const raw = await fs.readFile(skillFile, 'utf-8');
|
|
137
|
+
const parsed = parseFrontmatter(raw);
|
|
138
|
+
if (!parsed) {
|
|
139
|
+
console.error(`[skills] Skipping ${skillFile}: no valid YAML frontmatter`);
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
const result = frontmatterSchema.safeParse(parsed.data);
|
|
143
|
+
if (!result.success) {
|
|
144
|
+
console.error(`[skills] Skipping ${skillFile}: invalid frontmatter — ${result.error.issues.map((i) => i.message).join(', ')}`);
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
const files = await listSkillFiles(skillDir);
|
|
148
|
+
skills.push({
|
|
149
|
+
name: result.data.name,
|
|
150
|
+
description: result.data.description,
|
|
151
|
+
content: parsed.body.trim(),
|
|
152
|
+
source,
|
|
153
|
+
dir: skillDir,
|
|
154
|
+
files,
|
|
155
|
+
...(pluginId ? { pluginId } : {}),
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
catch (err) {
|
|
159
|
+
console.error(`[skills] Skipping ${skillFile}: ${err instanceof Error ? err.message : String(err)}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return skills;
|
|
163
|
+
}
|
|
164
|
+
/** Load skills from user + project directories, plus any extra dirs
|
|
165
|
+
* passed in (used by the plugin system to fold in plugin-contributed
|
|
166
|
+
* skill directories). Environment variable `XC_SKILLS_DIR` overrides
|
|
167
|
+
* the built-in paths for testing (extras are still honoured). */
|
|
168
|
+
export async function loadSkills(opts = {}) {
|
|
169
|
+
const override = process.env.XC_SKILLS_DIR;
|
|
170
|
+
if (override) {
|
|
171
|
+
const overrideSkills = await loadSkillsFromDir(override, 'project');
|
|
172
|
+
return [...overrideSkills, ...(await loadFromExtras(opts.extraDirs))];
|
|
173
|
+
}
|
|
174
|
+
const userDir = path.join(USER_XCODE_DIR, 'skills');
|
|
175
|
+
const projectDir = path.join(process.cwd(), XCODE_DIR, 'skills');
|
|
176
|
+
const userSkills = await loadSkillsFromDir(userDir, 'user');
|
|
177
|
+
const pluginSkills = await loadFromExtras(opts.extraDirs);
|
|
178
|
+
const projectSkills = await loadSkillsFromDir(projectDir, 'project');
|
|
179
|
+
// Merge order — last-wins in the registry (project overrides plugin
|
|
180
|
+
// overrides user builtin). This matches the precedence we tell users:
|
|
181
|
+
// a project-level skill always overrides anything from a plugin.
|
|
182
|
+
return [...userSkills, ...pluginSkills, ...projectSkills];
|
|
183
|
+
}
|
|
184
|
+
async function loadFromExtras(extras) {
|
|
185
|
+
if (!extras || extras.length === 0)
|
|
186
|
+
return [];
|
|
187
|
+
const out = [];
|
|
188
|
+
for (const { dir, pluginId } of extras) {
|
|
189
|
+
// Plugin-provided skills' filesystem source is technically the cache
|
|
190
|
+
// dir under ~/.x-code/plugins/cache/..., which makes 'user' the
|
|
191
|
+
// closest fit (it's installed user-wide, not per-project). `pluginId`
|
|
192
|
+
// carries the real provenance for the UI.
|
|
193
|
+
out.push(...(await loadSkillsFromDir(dir, 'user', pluginId)));
|
|
194
|
+
}
|
|
195
|
+
return out;
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/skills/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { type LoadSkillsOptions } from './loader.js';
|
|
2
|
+
export interface SkillDefinition {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
content: string;
|
|
6
|
+
source: 'user' | 'project';
|
|
7
|
+
/** Absolute path to the skill's directory (the one containing SKILL.md).
|
|
8
|
+
* Used at activation time so the model can resolve relative paths to
|
|
9
|
+
* bundled scripts / references / assets. */
|
|
10
|
+
dir: string;
|
|
11
|
+
/** Relative paths of files in the skill directory, excluding SKILL.md and
|
|
12
|
+
* hidden / heavy directories. Listed at activation time alongside the body
|
|
13
|
+
* so the model knows what bundled resources exist without globbing. Capped
|
|
14
|
+
* at MAX_LISTED_FILES — long lists get truncated with a "... N more" marker. */
|
|
15
|
+
files: string[];
|
|
16
|
+
/** When this skill comes from a plugin contribution, the owning plugin's
|
|
17
|
+
* id (`name@marketplace`). UI shows this as "(from plugin: …)" and
|
|
18
|
+
* `/skill uninstall` redirects to `/plugin uninstall`. */
|
|
19
|
+
pluginId?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface SkillEntry extends SkillDefinition {
|
|
22
|
+
disabled: boolean;
|
|
23
|
+
}
|
|
24
|
+
/** Summary returned by `reloadSkillRegistry()`. Drives the message
|
|
25
|
+
* surface in /skill refresh — caller can show "added: a, b" /
|
|
26
|
+
* "removed: c" / "unchanged: d, e" the same way /mcp refresh does. */
|
|
27
|
+
export interface SkillReloadSummary {
|
|
28
|
+
added: string[];
|
|
29
|
+
removed: string[];
|
|
30
|
+
changed: string[];
|
|
31
|
+
unchanged: string[];
|
|
32
|
+
}
|
|
33
|
+
export declare class SkillRegistry {
|
|
34
|
+
private byName;
|
|
35
|
+
constructor(skills: SkillDefinition[], disabled?: ReadonlySet<string>);
|
|
36
|
+
/** Replace the in-memory skill list with a fresh load. Used by
|
|
37
|
+
* /skill refresh — keeps the same SkillRegistry object identity so
|
|
38
|
+
* every cached `options.skillRegistry` reference (agent loop, CLI
|
|
39
|
+
* slash completion, App.tsx handlers) keeps pointing at the right
|
|
40
|
+
* thing. Returns a per-name diff vs the previous state so the
|
|
41
|
+
* caller can render an "added / removed / changed / unchanged"
|
|
42
|
+
* summary in the user-facing message. */
|
|
43
|
+
reload(skills: SkillDefinition[], disabled: ReadonlySet<string>): SkillReloadSummary;
|
|
44
|
+
/** Enabled skill by name. Disabled skills are hidden from the agent loop
|
|
45
|
+
* and slash-command dispatch — use `getEntry()` if you need to inspect
|
|
46
|
+
* the disabled flag (the /skill list handler does). */
|
|
47
|
+
get(name: string): SkillDefinition | undefined;
|
|
48
|
+
/** Enabled skills only. */
|
|
49
|
+
list(): SkillDefinition[];
|
|
50
|
+
/** Enabled skill names only. */
|
|
51
|
+
names(): string[];
|
|
52
|
+
/** Every loaded skill, with `disabled` flag. Used by /skill list and the
|
|
53
|
+
* disable/enable/remove handlers so they can act on disabled skills too. */
|
|
54
|
+
listAll(): SkillEntry[];
|
|
55
|
+
getEntry(name: string): SkillEntry | undefined;
|
|
56
|
+
}
|
|
57
|
+
/** Build the exact text that goes inside `<activated_skill name="...">...</activated_skill>`
|
|
58
|
+
* for both activation paths (model self-decide via `activateSkill` tool, and
|
|
59
|
+
* user explicit `/<skillname>`). Format follows Opencode's convention: body
|
|
60
|
+
* first, then a footer with base directory + relative-paths hint + file list.
|
|
61
|
+
* Sharing one formatter between the two call sites keeps the byte stream the
|
|
62
|
+
* model sees identical regardless of who triggered activation. */
|
|
63
|
+
export declare function formatSkillActivationBody(skill: SkillDefinition): string;
|
|
64
|
+
/** Wrap a skill's activation body in the `<activated_skill name="X">`
|
|
65
|
+
* XML envelope. Used by both activation paths so the wrapper is byte-
|
|
66
|
+
* identical regardless of trigger. */
|
|
67
|
+
export declare function wrapActivatedSkill(skill: SkillDefinition): string;
|
|
68
|
+
export declare function createSkillRegistry(opts?: LoadSkillsOptions): Promise<SkillRegistry>;
|
|
69
|
+
/** Re-scan skill directories + settings.json, then mutate the given
|
|
70
|
+
* registry in place. Caller is responsible for invalidating any
|
|
71
|
+
* systemPromptCache that embedded the previous skill list — the
|
|
72
|
+
* /skill refresh handler does exactly this. */
|
|
73
|
+
export declare function reloadSkillRegistry(registry: SkillRegistry, opts?: LoadSkillsOptions): Promise<SkillReloadSummary>;
|
|
74
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/skills/registry.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,KAAK,iBAAiB,EAAc,MAAM,aAAa,CAAA;AAGhE,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B;;iDAE6C;IAC7C,GAAG,EAAE,MAAM,CAAA;IACX;;;qFAGiF;IACjF,KAAK,EAAE,MAAM,EAAE,CAAA;IACf;;+DAE2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,UAAW,SAAQ,eAAe;IACjD,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED;;uEAEuE;AACvE,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,SAAS,EAAE,MAAM,EAAE,CAAA;CACpB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAyB;gBAE3B,MAAM,EAAE,eAAe,EAAE,EAAE,QAAQ,GAAE,WAAW,CAAC,MAAM,CAAa;IAShF;;;;;;8CAM0C;IAC1C,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,EAAE,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,kBAAkB;IA+BpF;;4DAEwD;IACxD,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAM9C,2BAA2B;IAC3B,IAAI,IAAI,eAAe,EAAE;IAIzB,gCAAgC;IAChC,KAAK,IAAI,MAAM,EAAE;IAIjB;iFAC6E;IAC7E,OAAO,IAAI,UAAU,EAAE;IAIvB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;CAG/C;AAQD;;;;;mEAKmE;AACnE,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAexE;AAED;;uCAEuC;AACvC,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAEjE;AAED,wBAAsB,mBAAmB,CAAC,IAAI,GAAE,iBAAsB,GAAG,OAAO,CAAC,aAAa,CAAC,CAG9F;AAED;;;gDAGgD;AAChD,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,aAAa,EACvB,IAAI,GAAE,iBAAsB,GAC3B,OAAO,CAAC,kBAAkB,CAAC,CAG7B"}
|