@falkenslab/agent-kit 0.20.0 → 0.22.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 (53) hide show
  1. package/assets/extension-launcher.mjs +37 -7
  2. package/dist/chat/chatController.d.ts +59 -0
  3. package/dist/chat/chatController.js +209 -2
  4. package/dist/chat/extensions.d.ts +30 -2
  5. package/dist/chat/extensions.js +63 -4
  6. package/dist/chat/runs.d.ts +3 -1
  7. package/dist/chat/runs.js +1 -1
  8. package/dist/core/agentSpec.d.ts +11 -0
  9. package/dist/core/elicitation.d.ts +54 -0
  10. package/dist/core/elicitation.js +120 -0
  11. package/dist/core/extensionCatalog.d.ts +94 -0
  12. package/dist/core/extensionCatalog.js +228 -0
  13. package/dist/core/extensionOptions.d.ts +56 -0
  14. package/dist/core/extensionOptions.js +139 -0
  15. package/dist/core/extensions.d.ts +9 -1
  16. package/dist/core/extensions.js +2 -1
  17. package/dist/core/externalExtensions.d.ts +116 -13
  18. package/dist/core/externalExtensions.js +280 -34
  19. package/dist/core/hooks/planGate.d.ts +2 -0
  20. package/dist/core/hooks/planGate.js +3 -0
  21. package/dist/core/interaction.d.ts +7 -0
  22. package/dist/core/liveExtensions.d.ts +30 -5
  23. package/dist/core/liveExtensions.js +78 -5
  24. package/dist/core/marketplaces.d.ts +6 -2
  25. package/dist/core/marketplaces.js +6 -4
  26. package/dist/core/messages/de.js +33 -1
  27. package/dist/core/messages/en.d.ts +36 -0
  28. package/dist/core/messages/en.js +33 -1
  29. package/dist/core/messages/es.js +33 -1
  30. package/dist/core/messages/fr.js +33 -1
  31. package/dist/core/npxPackages.d.ts +48 -0
  32. package/dist/core/npxPackages.js +121 -0
  33. package/dist/core/pluginDownloads.d.ts +2 -1
  34. package/dist/core/pluginDownloads.js +2 -2
  35. package/dist/core/readOnlyHints.d.ts +13 -0
  36. package/dist/core/readOnlyHints.js +26 -0
  37. package/dist/core/runner.js +2 -0
  38. package/dist/core/session.d.ts +13 -1
  39. package/dist/core/session.js +44 -20
  40. package/dist/core/sessionFacts.d.ts +5 -1
  41. package/dist/core/workspaceTrust.d.ts +12 -0
  42. package/dist/core/workspaceTrust.js +60 -0
  43. package/dist/index.d.ts +7 -1
  44. package/dist/index.js +5 -1
  45. package/dist/tui/extensionCommand.d.ts +13 -3
  46. package/dist/tui/extensionCommand.js +214 -37
  47. package/extensions/awareness/.claude-plugin/plugin.json +13 -5
  48. package/extensions/knowledge/.claude-plugin/plugin.json +13 -5
  49. package/extensions/memory/.claude-plugin/plugin.json +13 -5
  50. package/extensions/sources/.claude-plugin/plugin.json +13 -5
  51. package/package.json +7 -5
  52. package/schemas/agent-kit-metadata.schema.json +62 -0
  53. package/schemas/marketplace-catalog.schema.json +64 -0
@@ -36,6 +36,8 @@ export function runQuery(prompt, options) {
36
36
  contextUsage: () => contextUsage(),
37
37
  toggleMcpServer: (server, enabled) => result.toggleMcpServer(server, enabled),
38
38
  reloadPlugins: () => result.reloadPlugins(),
39
+ reconnectMcpServer: (server) => result.reconnectMcpServer(server),
40
+ mcpServerStatus: () => result.mcpServerStatus(),
39
41
  });
40
42
  // The main agent's tool calls by id, to name the results that come back for them.
41
43
  const toolNames = new Map();
@@ -6,7 +6,7 @@ import type { ToolLabels } from "./toolLabels.js";
6
6
  import type { AgentSpec, BaseSessionConfig } from "./agentSpec.js";
7
7
  import { type Language } from "./language.js";
8
8
  import { type RunFolder } from "./runs.js";
9
- import { type ExtensionSwitch } from "./liveExtensions.js";
9
+ import { type ExtensionRestart, type ExtensionSwitch } from "./liveExtensions.js";
10
10
  /**
11
11
  * Builds the `options` object passed to the Agent SDK's `query()` — everything about
12
12
  * *how* the agent runs a session (system prompt, tools, MCP servers, hooks), independent
@@ -44,11 +44,23 @@ export declare function buildSessionOptions<TConfig extends BaseSessionConfig>(c
44
44
  apis: Record<string, Record<string, unknown>>;
45
45
  /** Turns an installed extension off or on in the running session; false when that takes opening it again (#49). */
46
46
  switchExtension: ExtensionSwitch;
47
+ /** Restarts an installed extension's servers in the running session, with its options as they are now (#55). */
48
+ restartExtension: ExtensionRestart;
47
49
  }>;
48
50
  export { createModeControl, togglePlanMode, type ModeControl } from "./modeControl.js";
49
51
  /** The extensions of a session: where they're installed, what's installed, what runs and what can't (with why). */
50
52
  export interface ExtensionsStatus {
51
53
  dirs: ExtensionDirs;
54
+ /** The agent's own marketplace (`officialMarketplace`), for the chats' catalog. */
55
+ official?: string;
56
+ /** The topics the chats' catalog shows (`catalogTopics`); none, every extension. */
57
+ catalogTopics?: string[];
58
+ /** The workspace's extensions that don't run until the person trusts them there (#57): the chats ask. */
59
+ untrusted: {
60
+ name: string;
61
+ version?: string;
62
+ source: string;
63
+ }[];
52
64
  installed: InstalledExtension[];
53
65
  /** The names of the extensions this session runs with, the kit's and the agent's too. */
54
66
  active: string[];
@@ -1,4 +1,4 @@
1
- import { cp, readdir, readFile, rm } from "node:fs/promises";
1
+ import { readdir, readFile } from "node:fs/promises";
2
2
  import os from "node:os";
3
3
  import path from "node:path";
4
4
  import { createTranscriptLogger } from "./hooks/transcriptLogger.js";
@@ -17,12 +17,15 @@ import { extensionsPromptSection, resolveExtensions, skillsMissingCapabilities }
17
17
  import { allowAnyMcpTool } from "./mcpPermissions.js";
18
18
  import { pluginAgents } from "./pluginAgents.js";
19
19
  import { outsideArchive, unpackedClaudeExecutable } from "./packaged.js";
20
- import { listInstalled, loadExternalExtensions } from "./externalExtensions.js";
20
+ import { listInstalled, loadExternalExtensions, scopePrivateDir } from "./externalExtensions.js";
21
21
  import { replyLanguageInstruction } from "./language.js";
22
22
  import { chooseLanguage } from "./messages/index.js";
23
23
  import { createRunStore } from "./runs.js";
24
24
  import { createSessionView, registerSessionView } from "./sessionFacts.js";
25
- import { createExtensionSwitch } from "./liveExtensions.js";
25
+ import { createExtensionRestart, createExtensionSwitch, mountPlugin } from "./liveExtensions.js";
26
+ import { secretsDir } from "./extensionOptions.js";
27
+ import { createElicitationHandler } from "./elicitation.js";
28
+ import { createReadOnlyHints } from "./readOnlyHints.js";
26
29
  import { agentKitVersion } from "./version.js";
27
30
  /**
28
31
  * Builds the `options` object passed to the Agent SDK's `query()` — everything about
@@ -81,15 +84,15 @@ export async function buildSessionOptions(config, runDir, spec, options = {}) {
81
84
  const enabledNames = new Set((spec.extensions ?? []).map((extension) => extension.name));
82
85
  const resolved = resolveExtensions([...(spec.extensions ?? []), ...external.extensions.filter((extension) => !enabledNames.has(extension.name))], extensionContext);
83
86
  resolved.inactive.push(...external.off, ...external.extensions.filter((extension) => enabledNames.has(extension.name)).map((extension) => ({ name: extension.name, reason: "has the name of one this agent already has" })));
84
- // Each installed one's plugin, copied into the run's folder: the running session empties and
85
- // fills the copy to turn the extension off and on (liveExtensions.ts), never what's installed.
87
+ // Each installed one's plugin, mounted in the run's folder (a link, nothing copied): the running
88
+ // session unmounts and mounts it to turn the extension off and on (liveExtensions.ts), never
89
+ // touching what's installed.
86
90
  const installedDirs = new Map();
87
91
  for (const { extension } of resolved.active.filter(({ extension }) => extension.external)) {
88
- const copy = path.join(runDir, "extensions", extension.name);
89
- await rm(copy, { recursive: true, force: true });
90
- await cp(extension.plugin, copy, { recursive: true });
91
- installedDirs.set(extension.name, extension.plugin);
92
- extension.plugin = copy;
92
+ const mount = path.join(runDir, "extensions", extension.name);
93
+ await mountPlugin(extension.plugin, mount);
94
+ installedDirs.set(extension.name, { dir: extension.plugin, scopeDir: extension.installedIn ?? path.dirname(extension.plugin) });
95
+ extension.plugin = mount;
93
96
  }
94
97
  const externalPlugins = new Set(resolved.active.filter(({ extension }) => extension.external).map(({ extension }) => path.resolve(extension.plugin)));
95
98
  extensionContext.capabilities = resolved.capabilities;
@@ -170,8 +173,18 @@ export async function buildSessionOptions(config, runDir, spec, options = {}) {
170
173
  const allowedSubagentTypes = [...new Set([...(subagents?.allowedSubagentTypes ?? []), ...Object.keys(fromPlugins)])];
171
174
  // The extensions' read-only tools, for the plan gate: a list the live switch changes (liveExtensions.ts).
172
175
  const readOnlyTools = fromExtensions((contribution) => contribution.readOnlyTools);
176
+ // Those whose manifest lists none: their servers say, asked while the session runs (#53).
177
+ const readOnlyHintServers = fromExtensions((contribution) => contribution.readOnlyHintServers);
173
178
  // What no file tool may touch: the agent's denied paths and the SDK's own credentials.
174
- const deniedPaths = [...(config.deniedPaths ?? []), path.join(claudeConfigDir(), ".credentials.json")];
179
+ // And the installed extensions' sensitive option values (#55), in each scope's .secrets/.
180
+ const deniedPaths = [
181
+ ...(config.deniedPaths ?? []),
182
+ path.join(claudeConfigDir(), ".credentials.json"),
183
+ ...["agent", "project"].flatMap((scope) => {
184
+ const privateDir = config.extensionDirs ? scopePrivateDir(config.extensionDirs, scope) : undefined;
185
+ return privateDir ? [secretsDir(privateDir)] : [];
186
+ }),
187
+ ];
175
188
  const transcriptPath = path.join(runDir, "transcript.jsonl");
176
189
  const transcriptLogger = createTranscriptLogger(transcriptPath, config.secrets ?? []);
177
190
  const promptSections = [
@@ -269,6 +282,9 @@ export async function buildSessionOptions(config, runDir, spec, options = {}) {
269
282
  // The date and date arithmetic, in every session and mode: only reads (tools/time.ts).
270
283
  time: createTimeServer(config.timeZone),
271
284
  },
285
+ // A server asking the person for something mid-tool (MCP elicitation, #58): through the
286
+ // interaction port, never the model; declined when no one can be asked (autonomous).
287
+ onElicitation: createElicitationHandler(runDir, () => modeControl.mode !== "autonomous"),
272
288
  hooks: {
273
289
  PreToolUse: [
274
290
  { hooks: [transcriptLogger.preToolUse] },
@@ -303,6 +319,7 @@ export async function buildSessionOptions(config, runDir, spec, options = {}) {
303
319
  createPlanGate({
304
320
  projectDir: config.projectDir,
305
321
  readOnlyTools,
322
+ ...(readOnlyHintServers.length ? { isReadOnlyHinted: createReadOnlyHints(readOnlyHintServers, () => late.view?.controls().mcpServerStatus) } : {}),
306
323
  ...(spec.planMode?.isPlanFile ? { isPlanFile: (filePath) => spec.planMode.isPlanFile(filePath, config) } : {}),
307
324
  ...(spec.planMode?.isReadOnlyTool ? { isReadOnlyTool: spec.planMode.isReadOnlyTool } : {}),
308
325
  }, () => modeControl.mode === "plan"),
@@ -330,6 +347,9 @@ export async function buildSessionOptions(config, runDir, spec, options = {}) {
330
347
  const toolLabels = Object.assign({}, ...added.map((contribution) => contribution.toolLabels ?? {}));
331
348
  const extensions = {
332
349
  dirs: extensionDirs,
350
+ ...(config.officialMarketplace ? { official: config.officialMarketplace } : {}),
351
+ ...(config.catalogTopics?.length ? { catalogTopics: config.catalogTopics } : {}),
352
+ untrusted: external.untrusted.map((installed) => ({ name: installed.name, ...(installed.manifest?.version ? { version: installed.manifest.version } : {}), source: installed.lock.marketplace ?? installed.lock.source })),
333
353
  installed: await listInstalled(extensionDirs),
334
354
  active: resolved.active.map(({ extension }) => extension.name),
335
355
  about: Object.fromEntries(resolved.active.map(({ extension, manifest }) => [extension.name, { description: manifest.description, provides: manifest.provides }])),
@@ -357,18 +377,19 @@ export async function buildSessionOptions(config, runDir, spec, options = {}) {
357
377
  };
358
378
  late.view = createSessionView(viewBase, modeControl);
359
379
  registerSessionView(sdkOptions, late.view);
360
- // Turning an installed extension off and on while the session runs (#49).
361
- const switchExtension = createExtensionSwitch(resolved.active.flatMap(({ extension, manifest }, index) => {
362
- const installedDir = installedDirs.get(extension.name);
363
- if (!installedDir)
380
+ // Turning an installed extension off and on while the session runs (#49), and restarting its
381
+ // servers when its options change (#55).
382
+ const liveExtensions = resolved.active.flatMap(({ extension, manifest }, index) => {
383
+ const installed = installedDirs.get(extension.name);
384
+ if (!installed)
364
385
  return [];
365
386
  const contribution = added[index];
366
387
  return [
367
388
  {
368
389
  name: extension.name,
369
- installedDir,
370
- scopeDir: path.dirname(installedDir),
371
- pluginCopy: extension.plugin,
390
+ installedDir: installed.dir,
391
+ scopeDir: installed.scopeDir,
392
+ pluginMount: extension.plugin,
372
393
  servers: Object.keys(contribution?.mcpServers ?? {}),
373
394
  readOnlyTools: contribution?.readOnlyTools ?? [],
374
395
  toolLabels: contribution?.toolLabels ?? {},
@@ -378,9 +399,12 @@ export async function buildSessionOptions(config, runDir, spec, options = {}) {
378
399
  help: contribution?.helpLines ?? [],
379
400
  },
380
401
  ];
381
- }), { readOnlyTools, allowedSubagentTypes, toolLabels, status: extensions, facts: viewBase, controls: () => late.view?.controls() ?? {} });
402
+ });
403
+ const liveTargets = { readOnlyTools, allowedSubagentTypes, toolLabels, status: extensions, facts: viewBase, controls: () => late.view?.controls() ?? {} };
404
+ const switchExtension = createExtensionSwitch(liveExtensions, liveTargets);
405
+ const restartExtension = createExtensionRestart(liveExtensions, liveTargets);
382
406
  const apis = Object.fromEntries(resolved.active.flatMap(({ extension }, index) => (added[index]?.api ? [[extension.name, added[index].api]] : [])));
383
- return { options: sdkOptions, transcriptLogger, transcriptPath, modeControl, language, toolLabels, extensions, apis, switchExtension };
407
+ return { options: sdkOptions, transcriptLogger, transcriptPath, modeControl, language, toolLabels, extensions, apis, switchExtension, restartExtension };
384
408
  }
385
409
  export { createModeControl, togglePlanMode } from "./modeControl.js";
386
410
  /** The Claude Code configuration folder the SDK's CLI uses: `CLAUDE_CONFIG_DIR`, or `~/.claude`. */
@@ -1,4 +1,4 @@
1
- import type { Options, SlashCommand } from "@anthropic-ai/claude-agent-sdk";
1
+ import type { McpServerStatus, Options, SlashCommand } from "@anthropic-ai/claude-agent-sdk";
2
2
  import type { AgentIdentity, Mode } from "./agentSpec.js";
3
3
  import type { Language } from "./language.js";
4
4
  import type { ModeControl } from "./modeControl.js";
@@ -61,6 +61,10 @@ export interface SessionLive {
61
61
  /** The running session's controls an installed extension is turned off and on with (liveExtensions.ts). */
62
62
  toggleMcpServer?: (server: string, enabled: boolean) => Promise<void>;
63
63
  reloadPlugins?: () => Promise<unknown>;
64
+ /** Restarts one of its MCP servers: an installed extension's, when its options change (#55). */
65
+ reconnectMcpServer?: (server: string) => Promise<void>;
66
+ /** Its MCP servers as they are now: their tools and what each says of itself (plan mode's read-only hints). */
67
+ mcpServerStatus?: () => Promise<McpServerStatus[]>;
64
68
  }
65
69
  /** The facts known when the options are built: everything but the mode and what only the running session knows. */
66
70
  export type StaticSessionFacts = Omit<SessionFacts, "mode" | "switchableModes" | "tools" | "commands" | "context" | "extensions"> & {
@@ -0,0 +1,12 @@
1
+ import { type ExtensionDirs, type LockEntry } from "./externalExtensions.js";
2
+ /** What's trusted of an extension: its code, its files' hash and its npx packages'. */
3
+ export declare function codeHash(lock: LockEntry): string;
4
+ /** Whether an extension of a project's scope is trusted in that workspace, with the code its lock has now. */
5
+ export declare function isTrusted(agentDir: string, projectScope: string, name: string, lock: LockEntry): Promise<boolean>;
6
+ /** Trusts these extensions of a project's scope, with the code their lock has now. */
7
+ export declare function trust(agentDir: string, projectScope: string, entries: Record<string, LockEntry>): Promise<void>;
8
+ /**
9
+ * Trusts a workspace's extensions (its project scope's, all or `names`) with the code its lock
10
+ * has now: what the person does when the chat asks, or with `extension trust`. The names trusted.
11
+ */
12
+ export declare function trustWorkspace(dirs: ExtensionDirs, names?: readonly string[]): Promise<string[]>;
@@ -0,0 +1,60 @@
1
+ import { createHash } from "node:crypto";
2
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { readLock } from "./externalExtensions.js";
5
+ /**
6
+ * Trusting a workspace's extensions (#57): a project's scope comes with the project, from whoever
7
+ * shared it (a clone, a download), and its extensions' servers run code on this computer. They
8
+ * run only once the person trusts them in that workspace: what's trusted is each one's code (its
9
+ * files' SHA-256 and its npx packages'), kept in the agent's folder, outside the project, so a
10
+ * project can't trust itself. Another version (a changed lock, an update from someone else) asks
11
+ * again; turning one on or off, or its options, don't. What the person installs into the
12
+ * project's scope themselves is trusted as they install it. The agent's own scope is the
13
+ * person's: it never asks.
14
+ */
15
+ const TRUST_FILE = ".trust.json";
16
+ /** What's trusted of an extension: its code, its files' hash and its npx packages'. */
17
+ export function codeHash(lock) {
18
+ const packages = Object.entries(lock.packages ?? {})
19
+ .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
20
+ .map(([spec, cached]) => `${spec}=${cached.sha256}`);
21
+ // A linked one has no hash of its own: its folder is what's trusted.
22
+ return createHash("sha256").update([lock.linked ? `linked:${path.resolve(lock.source)}` : lock.sha256, ...packages].join("\n")).digest("hex");
23
+ }
24
+ async function readTrust(agentDir) {
25
+ try {
26
+ return JSON.parse(await readFile(path.join(agentDir, TRUST_FILE), "utf8"));
27
+ }
28
+ catch (error) {
29
+ if (error.code === "ENOENT")
30
+ return {};
31
+ throw error;
32
+ }
33
+ }
34
+ /** The workspace a project scope is, as the trust file names it. */
35
+ const workspaceKey = (projectScope) => path.resolve(projectScope);
36
+ /** Whether an extension of a project's scope is trusted in that workspace, with the code its lock has now. */
37
+ export async function isTrusted(agentDir, projectScope, name, lock) {
38
+ return (await readTrust(agentDir))[workspaceKey(projectScope)]?.[name] === codeHash(lock);
39
+ }
40
+ /** Trusts these extensions of a project's scope, with the code their lock has now. */
41
+ export async function trust(agentDir, projectScope, entries) {
42
+ const file = await readTrust(agentDir);
43
+ const workspace = (file[workspaceKey(projectScope)] ??= {});
44
+ for (const [name, lock] of Object.entries(entries))
45
+ workspace[name] = codeHash(lock);
46
+ await mkdir(agentDir, { recursive: true });
47
+ await writeFile(path.join(agentDir, TRUST_FILE), `${JSON.stringify(file, null, 2)}\n`, "utf8");
48
+ }
49
+ /**
50
+ * Trusts a workspace's extensions (its project scope's, all or `names`) with the code its lock
51
+ * has now: what the person does when the chat asks, or with `extension trust`. The names trusted.
52
+ */
53
+ export async function trustWorkspace(dirs, names) {
54
+ if (!dirs.agent || !dirs.project)
55
+ return [];
56
+ const lock = await readLock(dirs.project);
57
+ const entries = Object.fromEntries(Object.entries(lock).filter(([name]) => !names || names.includes(name)));
58
+ await trust(dirs.agent, dirs.project, entries);
59
+ return Object.keys(entries);
60
+ }
package/dist/index.d.ts CHANGED
@@ -16,8 +16,13 @@ export { sources, type SourcesOptions } from "./extensions/sources/index.js";
16
16
  export { knowledge, type KnowledgeOptions } from "./extensions/knowledge/index.js";
17
17
  export { memory, type MemoryOptions } from "./extensions/memory/index.js";
18
18
  export { readExtensionManifest, type Extension, type ExtensionContext, type ExtensionContribution, type ExtensionManifest, type FolderOption, } from "./core/extensions.js";
19
- export { addExtension, removeExtension, setExtensionEnabled, listInstalled, readExternalManifest, type ExtensionAuthor, type ExtensionDirs, type ExtensionScope, type ExternalManifest, type ExternalToolLabel, type PluginServer, type InstalledExtension, type LockEntry, } from "./core/externalExtensions.js";
19
+ export { addExtension, codeStoreDir, installTarget, scopePrivateDir, extensionDataDir, extensionOptionStates, setExtensionOptions, removeExtension, setExtensionEnabled, listInstalled, readExternalManifest, type ExtensionAuthor, type ExtensionDirs, type ExtensionScope, type ExternalManifest, type ExternalToolLabel, type PluginServer, type InstalledExtension, type LockEntry, type ExtensionOptionState, } from "./core/externalExtensions.js";
20
+ export type { ExtensionOption, OptionValue } from "./core/extensionOptions.js";
21
+ export type { ExtensionRestart, ExtensionSwitch } from "./core/liveExtensions.js";
22
+ export { packageCacheDir, type CachedPackage } from "./core/npxPackages.js";
20
23
  export { addMarketplace, findPlugin, inspectMarketplace, installFromMarketplace, listMarketplaces, readMarketplaceManifest, removeMarketplace, resolvePluginSource, updateMarketplace, type KnownMarketplace, type MarketplaceManifest, type MarketplacePlugin, type PluginSource, } from "./core/marketplaces.js";
24
+ export { extensionCatalog, installExtension, restoreExtensions, updateExtension, type CatalogEntry } from "./core/extensionCatalog.js";
25
+ export { trustWorkspace } from "./core/workspaceTrust.js";
21
26
  export { runExtensionCommand } from "./tui/extensionCommand.js";
22
27
  export { agentKitVersion } from "./core/version.js";
23
28
  export { BUILT_IN_PAGE_TYPES, isSlug, parseId, linkedIds, type KnowledgeStore, type PageType, type KnowledgePage, type PageInfo, type SearchHit, type CheckReport, type FieldChanges, type NewPage, } from "./extensions/knowledge/knowledgeStore.js";
@@ -37,6 +42,7 @@ export { createFileScopeGate, checkFileScope, type FileScope } from "./core/hook
37
42
  export { createPlanGate, checkPlanScope, type PlanScope } from "./core/hooks/planGate.js";
38
43
  export { askForDecision, askForManualIntervention, askForChoice, askForText, type ChoiceAnswer } from "./core/hooks/humanInput.js";
39
44
  export { setInteractionPort, getInteractionPort, type InteractionPort, type ApprovalPrompt, type ChoiceSettings } from "./core/interaction.js";
45
+ export { formFields, type FormAnswer, type FormField, type FormRequest } from "./core/elicitation.js";
40
46
  export { terminalInteractionPort, setSharedReadline, getSharedReadline } from "./tui/terminalInteraction.js";
41
47
  export { createHumanApprovalServer, DEFAULT_HUMAN_APPROVAL_TEXTS, type HumanApprovalTexts } from "./core/tools/humanApproval.js";
42
48
  export { createManualLoginServer, type ManualInterventionTexts } from "./core/tools/manualLogin.js";
package/dist/index.js CHANGED
@@ -16,8 +16,11 @@ export { sources } from "./extensions/sources/index.js";
16
16
  export { knowledge } from "./extensions/knowledge/index.js";
17
17
  export { memory } from "./extensions/memory/index.js";
18
18
  export { readExtensionManifest, } from "./core/extensions.js";
19
- export { addExtension, removeExtension, setExtensionEnabled, listInstalled, readExternalManifest, } from "./core/externalExtensions.js";
19
+ export { addExtension, codeStoreDir, installTarget, scopePrivateDir, extensionDataDir, extensionOptionStates, setExtensionOptions, removeExtension, setExtensionEnabled, listInstalled, readExternalManifest, } from "./core/externalExtensions.js";
20
+ export { packageCacheDir } from "./core/npxPackages.js";
20
21
  export { addMarketplace, findPlugin, inspectMarketplace, installFromMarketplace, listMarketplaces, readMarketplaceManifest, removeMarketplace, resolvePluginSource, updateMarketplace, } from "./core/marketplaces.js";
22
+ export { extensionCatalog, installExtension, restoreExtensions, updateExtension } from "./core/extensionCatalog.js";
23
+ export { trustWorkspace } from "./core/workspaceTrust.js";
21
24
  export { runExtensionCommand } from "./tui/extensionCommand.js";
22
25
  export { agentKitVersion } from "./core/version.js";
23
26
  export { BUILT_IN_PAGE_TYPES, isSlug, parseId, linkedIds, } from "./extensions/knowledge/knowledgeStore.js";
@@ -38,6 +41,7 @@ export { createFileScopeGate, checkFileScope } from "./core/hooks/fileScopeGate.
38
41
  export { createPlanGate, checkPlanScope } from "./core/hooks/planGate.js";
39
42
  export { askForDecision, askForManualIntervention, askForChoice, askForText } from "./core/hooks/humanInput.js";
40
43
  export { setInteractionPort, getInteractionPort } from "./core/interaction.js";
44
+ export { formFields } from "./core/elicitation.js";
41
45
  export { terminalInteractionPort, setSharedReadline, getSharedReadline } from "./tui/terminalInteraction.js";
42
46
  // The checkpoints answer on the terminal by default, as they always have; a non-terminal
43
47
  // host replaces the port with its own (or null, to answer through the response file only).
@@ -8,8 +8,14 @@ export { chatExtensionsCommand, describe } from "../chat/extensions.js";
8
8
  *
9
9
  * - `extension list`
10
10
  * - `extension info <name>`: its metadata, what it offers and where its README is
11
- * - `extension add <folder | git URL[#ref] | plugin[@marketplace]> [--project] [--path <subfolder>] [--yes]`
12
- * - `extension remove|enable|disable <name> [--project | --agent]`
11
+ * - `extension add <folder | git URL[#ref] | plugin[@marketplace]> [--project] [--path <subfolder>] [--set key=value…] [--yes]`: asks for its options (#55) unless `--set` gives them
12
+ * - `extension add <folder> --link [--project]`: registered where it is, to develop it (not copied, its files not checked)
13
+ * - `extension remove <name> [--project | --agent] [--yes | --keep-data]`: asks before deleting its data folder
14
+ * - `extension enable|disable <name> [--project | --agent]`
15
+ * - `extension config <name> [key=value… | key… | --unset key…] [--project | --agent]`: its options; `key` alone asks for it (without echo when it's a secret)
16
+ * - `extension update [name] [--yes]`: one installed from a marketplace (or all that have a newer version there) to the version it offers now, its data and options kept
17
+ * - `extension restore [--trust]`: gets the code a workspace's lock lists and this computer lacks (#57); `--trust` trusts it too
18
+ * - `extension trust [name…]`: lets a workspace's extensions run, as their code is now
13
19
  * - `extension search [words]`: what the known marketplaces offer
14
20
  * - `extension marketplace add <folder | git URL[#ref] | owner/repo> [--yes]`, `list`, `update [name]`, `remove <name>`
15
21
  *
@@ -25,6 +31,10 @@ export declare function runExtensionCommand(argv: readonly string[], options: {
25
31
  write?: (line: string) => void;
26
32
  /** The agent's official marketplace: a folder or a git URL (`#ref`). */
27
33
  official?: string;
28
- /** Asks the person (a confirmation); by default on the terminal, and nothing without one. */
34
+ /** The topics of the extensions `search` shows (#59), as the agent's `catalogTopics`; without it, every one. */
35
+ catalogTopics?: string[];
36
+ /** Asks the person (a confirmation, an option's value); by default on the terminal, and nothing without one. */
29
37
  ask?: (question: string) => Promise<string>;
38
+ /** Asks for a secret (a sensitive option), without echo; by default on the terminal. */
39
+ askSecret?: (question: string) => Promise<string>;
30
40
  }): Promise<boolean>;