@falkenslab/agent-kit 0.21.0 → 0.23.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.
Files changed (57) hide show
  1. package/README.md +1 -4
  2. package/assets/extension-launcher.mjs +28 -5
  3. package/dist/chat/chatController.d.ts +60 -0
  4. package/dist/chat/chatController.js +212 -2
  5. package/dist/chat/extensions.d.ts +36 -2
  6. package/dist/chat/extensions.js +87 -3
  7. package/dist/chat/runs.d.ts +3 -1
  8. package/dist/chat/runs.js +1 -1
  9. package/dist/core/agentSpec.d.ts +11 -0
  10. package/dist/core/elicitation.d.ts +54 -0
  11. package/dist/core/elicitation.js +120 -0
  12. package/dist/core/extensionCatalog.d.ts +103 -0
  13. package/dist/core/extensionCatalog.js +235 -0
  14. package/dist/core/extensionOptions.d.ts +56 -0
  15. package/dist/core/extensionOptions.js +139 -0
  16. package/dist/core/extensionRequirements.d.ts +66 -0
  17. package/dist/core/extensionRequirements.js +112 -0
  18. package/dist/core/extensions.d.ts +75 -2
  19. package/dist/core/extensions.js +78 -6
  20. package/dist/core/externalExtensions.d.ts +101 -11
  21. package/dist/core/externalExtensions.js +263 -51
  22. package/dist/core/hooks/planGate.d.ts +2 -0
  23. package/dist/core/hooks/planGate.js +3 -0
  24. package/dist/core/interaction.d.ts +7 -0
  25. package/dist/core/liveExtensions.d.ts +15 -0
  26. package/dist/core/liveExtensions.js +33 -2
  27. package/dist/core/marketplaces.d.ts +7 -2
  28. package/dist/core/marketplaces.js +6 -4
  29. package/dist/core/messages/de.js +37 -1
  30. package/dist/core/messages/en.d.ts +44 -0
  31. package/dist/core/messages/en.js +37 -1
  32. package/dist/core/messages/es.js +37 -1
  33. package/dist/core/messages/fr.js +37 -1
  34. package/dist/core/npxPackages.d.ts +48 -0
  35. package/dist/core/npxPackages.js +121 -0
  36. package/dist/core/pluginDownloads.d.ts +2 -1
  37. package/dist/core/pluginDownloads.js +2 -2
  38. package/dist/core/readOnlyHints.d.ts +13 -0
  39. package/dist/core/readOnlyHints.js +26 -0
  40. package/dist/core/runner.js +2 -0
  41. package/dist/core/session.d.ts +17 -5
  42. package/dist/core/session.js +44 -11
  43. package/dist/core/sessionFacts.d.ts +11 -1
  44. package/dist/core/workspaceTrust.d.ts +12 -0
  45. package/dist/core/workspaceTrust.js +60 -0
  46. package/dist/extensions/awareness/tools.js +6 -2
  47. package/dist/index.d.ts +9 -2
  48. package/dist/index.js +7 -2
  49. package/dist/tui/extensionCommand.d.ts +10 -2
  50. package/dist/tui/extensionCommand.js +199 -34
  51. package/extensions/awareness/.claude-plugin/plugin.json +13 -5
  52. package/extensions/knowledge/.claude-plugin/plugin.json +13 -5
  53. package/extensions/memory/.claude-plugin/plugin.json +13 -5
  54. package/extensions/sources/.claude-plugin/plugin.json +13 -5
  55. package/package.json +7 -5
  56. package/schemas/agent-kit-metadata.schema.json +120 -0
  57. package/schemas/marketplace-catalog.schema.json +74 -0
@@ -1,14 +1,17 @@
1
- import type { Extension } from "./extensions.js";
1
+ import { type Extension, type ExtensionCapability } from "./extensions.js";
2
2
  import type { Language } from "./language.js";
3
3
  import { type ToolPhrase } from "./messages/index.js";
4
+ import { type ExtensionOption, type OptionValue } from "./extensionOptions.js";
5
+ import { checkRequirements, type ExtensionRequirement } from "./extensionRequirements.js";
6
+ import { type CachedPackage } from "./npxPackages.js";
4
7
  /**
5
8
  * External extensions (ADR-025, #37): installed into an agent, for all its projects (the
6
9
  * agent's scope) or for one (the project's, which wins), from a folder or a git repository.
7
10
  * Each scope is a folder of extensions, one per subfolder, with a lock (`extensions.lock.json`)
8
11
  * that records where each came from, a SHA-256 over its files and whether it's enabled. An
9
12
  * extension is a Claude Code plugin as it is (#38): its MCP servers come from its `.mcp.json`,
10
- * and the kit starts each with Node through a launcher that leaves it only the system's
11
- * variables and its own `env`. The `"agent-kit"` key of its `plugin.json` is optional: it adds
13
+ * and the kit starts each with Node (an `npx` one from its package cache, #54) through a launcher that leaves it only the system's
14
+ * variables and its own `env`. The `metadata["agent-kit"]` of its `plugin.json` is optional: it adds
12
15
  * what the kit's gates and chat can use (capabilities, read-only tools, labels, help). Each has a
13
16
  * data folder of its own (`${CLAUDE_PLUGIN_DATA}`, as Claude Code gives a plugin), kept across
14
17
  * sessions and updates; one being developed is linked rather than copied (#52).
@@ -42,7 +45,7 @@ export interface ExtensionAuthor {
42
45
  }
43
46
  /**
44
47
  * An external extension's manifest: its `plugin.json`, the plugin's own metadata (Claude Code's
45
- * fields, which its validator checks) and the kit's key (`"agent-kit"`, which it ignores).
48
+ * fields, which its validator checks) and the kit's data (`metadata["agent-kit"]`, which it doesn't read).
46
49
  */
47
50
  export interface ExternalManifest {
48
51
  name: string;
@@ -53,20 +56,37 @@ export interface ExternalManifest {
53
56
  repository?: string;
54
57
  license?: string;
55
58
  keywords?: string[];
59
+ /** What it lets the agent use: its `provides` and its capabilities' ids. */
56
60
  provides: string[];
57
61
  requires: string[];
62
+ /** What it lets the agent do, described for the person (#62): skills and tools together. */
63
+ capabilities: ExtensionCapability[];
58
64
  /** The agent-kit versions it works with, e.g. `">=0.19.0 <0.21.0"`. */
59
65
  kit?: string;
60
- /** Programs it needs on this computer, found on the `PATH` (`"docker"`, `"python3"`): without one it's off, saying which. */
61
- needs: string[];
66
+ /**
67
+ * Programs it needs on this computer (#63): checked when it loads, never installed. Without one
68
+ * the whole extension needs, it's off; without one only some capabilities need, those are.
69
+ */
70
+ requirements: ExtensionRequirement[];
62
71
  /** Its MCP servers, by name (`mcp__<name>__<tool>`), from the plugin's `.mcp.json` or `plugin.json`. */
63
72
  servers: Record<string, PluginServer>;
64
- /** Its tools that only read (short names, of any of its servers): plan mode lets them through. */
65
- readOnlyTools: string[];
73
+ /**
74
+ * Its tools that only read (short names, of any of its servers): plan mode lets them through.
75
+ * Without the key, plan mode asks its servers which (their tools' `readOnlyHint`); with it, the
76
+ * list is the whole answer, even empty.
77
+ */
78
+ readOnlyTools?: string[];
66
79
  /** Its tools' chat labels, by short name (of any of its servers) and language (English when the kit's isn't there). */
67
80
  labels: Record<string, Partial<Record<Language, ExternalToolLabel>>>;
68
81
  /** What it says about itself in a session, for the agent to tell the person (`SessionFacts`). */
69
82
  help?: string;
83
+ /** Its options (`userConfig`, as Claude Code declares them, #55): its servers take them as `${user_config.KEY}`. */
84
+ userConfig: Record<string, ExtensionOption>;
85
+ /** How a catalog shows it (#59): its `logo` (square) and `banner` (wide), paths inside its folder, as its manifest gives them. */
86
+ catalog?: {
87
+ logo?: string;
88
+ banner?: string;
89
+ };
70
90
  }
71
91
  /** One extension in a scope's lock. */
72
92
  export interface LockEntry {
@@ -79,10 +99,22 @@ export interface LockEntry {
79
99
  linked?: boolean;
80
100
  /** The commit it was cloned at, for a git source. */
81
101
  commit?: string;
102
+ /** The folder inside its source it was installed from (a git repository's subfolder). */
103
+ subdir?: string;
104
+ /**
105
+ * Its code is in the agent's store (`<agent scope>/.store/<name>/<hash>/`), not in its scope's
106
+ * folder (#57): a project's scope keeps only its lock, so a workspace shared with others carries
107
+ * what it uses and at which version, never the code itself (`restoreExtensions()` gets it).
108
+ */
109
+ stored?: boolean;
82
110
  /** The marketplace it was installed from (`<name>@<marketplace>`), if any. */
83
111
  marketplace?: string;
84
112
  /** SHA-256 over its files, checked when it loads; empty for a linked one. */
85
113
  sha256: string;
114
+ /** Its options' non-sensitive values (#55); the sensitive ones are in the scope's `.secrets/`. */
115
+ options?: Record<string, OptionValue>;
116
+ /** The npm packages its servers run with npx (#54), by `<package>@<version>`: in the agent's package cache, checked when it loads. */
117
+ packages?: Record<string, CachedPackage>;
86
118
  enabled: boolean;
87
119
  /** When it was installed, ISO 8601 in UTC. */
88
120
  installed: string;
@@ -95,11 +127,34 @@ export declare const LOCK_FILE = "extensions.lock.json";
95
127
  * asks before deleting it.
96
128
  */
97
129
  export declare function extensionDataDir(scopeDir: string, name: string): string;
130
+ /**
131
+ * Where a scope keeps what's the person's, not the workspace's: its extensions' data and secrets
132
+ * (#57). The agent's scope, its own folder; a project's, a folder of its own in the agent's
133
+ * (`<agent scope>/.projects/<project>-<hash>/`), so nothing private travels with a project. An
134
+ * agent without a scope of its own keeps it in the project's.
135
+ */
136
+ export declare function scopePrivateDir(dirs: ExtensionDirs, scope: ExtensionScope): string | undefined;
137
+ /** The agent's store of extensions' code, by content (#57): where a project's scope keeps its extensions' code. */
138
+ export declare function codeStoreDir(dirs: ExtensionDirs): string | undefined;
139
+ /** Where a stored extension's code is: by its name and its files' hash. */
140
+ export declare function storedCodeDir(store: string, name: string, sha256: string): string;
141
+ /**
142
+ * How an install into `scope` is done: its npx packages into the agent's cache, and a project's
143
+ * code into the agent's store when the agent has a scope of its own.
144
+ */
145
+ export declare function installTarget(dirs: ExtensionDirs, scope: ExtensionScope): {
146
+ packages?: string;
147
+ store?: string;
148
+ };
98
149
  /** A scope's lock: its extensions by name. */
99
150
  export declare function readLock(scopeDir: string): Promise<Record<string, LockEntry>>;
100
151
  /** Reads an extension's manifest, checking what the kit needs from it. */
101
152
  export declare function readExternalManifest(dir: string): Promise<ExternalManifest>;
102
- /** SHA-256 over an extension's files (their paths and contents, in order), `.git` aside. */
153
+ /**
154
+ * SHA-256 over an extension's files (their paths and contents, in order), `.git` aside. A text
155
+ * file's line endings don't count (CRLF is taken as LF): git checks the same commit out with CRLF
156
+ * on one computer and LF on another, and a workspace's lock must match on both (#57).
157
+ */
103
158
  export declare function hashExtension(dir: string): Promise<string>;
104
159
  /**
105
160
  * Whether `version` (x.y.z) is in `range`: comparators separated by spaces, all of which must
@@ -114,8 +169,10 @@ export interface InstalledExtension {
114
169
  scopeDir: string;
115
170
  /** Its plugin: in its scope's folder, or where it is when it's linked. */
116
171
  dir: string;
117
- /** Its data folder (`${CLAUDE_PLUGIN_DATA}`), which may not exist yet. */
172
+ /** Its data folder (`${CLAUDE_PLUGIN_DATA}`), which may not exist yet: in its scope's private folder. */
118
173
  dataDir: string;
174
+ /** Its scope's private folder (`scopePrivateDir()`): its data and secrets. */
175
+ privateDir: string;
119
176
  lock: LockEntry;
120
177
  /** Also installed in the project's scope, which wins: this one isn't used. */
121
178
  shadowed: boolean;
@@ -133,10 +190,18 @@ export declare function loadExternalExtensions(dirs: ExtensionDirs): Promise<{
133
190
  name: string;
134
191
  reason: string;
135
192
  }[];
193
+ untrusted: InstalledExtension[];
136
194
  }>;
137
195
  /** Why an installed extension can't load, or its manifest when it can. */
138
196
  /** Whether a program is on the `PATH`, as a shell would find it (with `PATHEXT`'s extensions on Windows). */
139
197
  export declare function onPath(program: string, env?: NodeJS.ProcessEnv): Promise<boolean>;
198
+ /** A requirement this computer lacks, as the person reads it: what it is, what for, and how to install it. */
199
+ export declare function missingRequirement(check: Awaited<ReturnType<typeof checkRequirements>>[number]): string;
200
+ /** What an installed extension can't do on this computer, and why: its capabilities whose requirements are missing (#63). */
201
+ export interface UnavailableCapabilities {
202
+ capabilities: string[];
203
+ reason: string;
204
+ }
140
205
  /** Whether `source` names a git repository rather than a folder. */
141
206
  export declare function isGitSource(source: string): boolean;
142
207
  /**
@@ -145,7 +210,9 @@ export declare function isGitSource(source: string): boolean;
145
210
  * manifest, and locks it, enabled, with the marketplace it came from when it did (`origin`, for a
146
211
  * temporary folder, is what the lock says it came from). An extension with the same name in that
147
212
  * scope is replaced; its data folder stays. With `link`, a folder is registered where it is
148
- * instead, to develop it: not copied, and its files not checked.
213
+ * instead, to develop it: not copied, and its files not checked. The packages its npx servers
214
+ * run are fetched into `packages` (#54), the agent's package cache (`packageCacheDir()`; by
215
+ * default the scope's).
149
216
  */
150
217
  export declare function addExtension(source: string, scopeDir: string, options?: {
151
218
  subdir?: string;
@@ -153,10 +220,13 @@ export declare function addExtension(source: string, scopeDir: string, options?:
153
220
  marketplace?: string;
154
221
  origin?: string;
155
222
  link?: boolean;
223
+ packages?: string;
224
+ store?: string;
156
225
  }): Promise<{
157
226
  name: string;
158
227
  replaced: boolean;
159
228
  commit?: string;
229
+ missing: string[];
160
230
  }>;
161
231
  /**
162
232
  * Removes an extension from a scope (its files and its lock entry; a linked one's folder is left
@@ -164,8 +234,28 @@ export declare function addExtension(source: string, scopeDir: string, options?:
164
234
  */
165
235
  export declare function removeExtension(scopeDir: string, name: string, options?: {
166
236
  deleteData?: boolean;
237
+ privateDir?: string;
167
238
  }): Promise<boolean>;
168
239
  /** The size in bytes of the files under `dir` (0 when it doesn't exist). */
169
240
  export declare function folderSize(dir: string): Promise<number>;
170
241
  /** Enables or disables an installed extension in a scope; false when it isn't there. */
171
242
  export declare function setExtensionEnabled(scopeDir: string, name: string, enabled: boolean): Promise<boolean>;
243
+ /**
244
+ * Sets an installed extension's options (#55), each from what the person typed (`undefined`
245
+ * clears it), checked against its `userConfig`: sensitive ones into the scope's secrets, the rest
246
+ * into its lock. A running session's servers take them when they start again.
247
+ */
248
+ export declare function setExtensionOptions(where: string | InstalledExtension, name: string, typed: Record<string, string | undefined>): Promise<void>;
249
+ /** One of an installed extension's options and its value now (a sensitive one's value is never given: only whether it's set). */
250
+ export interface ExtensionOptionState {
251
+ key: string;
252
+ option: ExtensionOption;
253
+ /** Its value, when it has one and isn't sensitive. */
254
+ value?: OptionValue;
255
+ /** Whether it has a value (its own or its default). */
256
+ set: boolean;
257
+ /** Its value is its default, not one the person gave. */
258
+ isDefault: boolean;
259
+ }
260
+ /** An installed extension's options, as they are now. */
261
+ export declare function extensionOptionStates(installed: InstalledExtension): Promise<ExtensionOptionState[]>;