@falkenslab/agent-kit 0.25.0 → 0.27.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/chat/extensions.d.ts +14 -0
- package/dist/chat/extensions.js +39 -3
- package/dist/core/agentSpec.d.ts +33 -0
- package/dist/core/claudeAiConnectors.d.ts +35 -0
- package/dist/core/claudeAiConnectors.js +76 -0
- package/dist/core/extensions.d.ts +7 -0
- package/dist/core/externalExtensions.d.ts +30 -0
- package/dist/core/externalExtensions.js +37 -0
- package/dist/core/hooks/guidedGate.d.ts +57 -0
- package/dist/core/hooks/guidedGate.js +97 -0
- package/dist/core/hooks/remoteGate.d.ts +22 -0
- package/dist/core/hooks/remoteGate.js +35 -0
- package/dist/core/hooks/transcriptLogger.d.ts +2 -0
- package/dist/core/hooks/transcriptLogger.js +1 -1
- package/dist/core/messages/de.js +10 -1
- package/dist/core/messages/en.d.ts +22 -0
- package/dist/core/messages/en.js +10 -1
- package/dist/core/messages/es.js +10 -1
- package/dist/core/messages/fr.js +10 -1
- package/dist/core/readOnlyHints.d.ts +12 -6
- package/dist/core/readOnlyHints.js +14 -8
- package/dist/core/runner.js +24 -0
- package/dist/core/session.d.ts +5 -0
- package/dist/core/session.js +88 -6
- package/dist/core/sessionFacts.d.ts +6 -0
- package/dist/core/sessionFacts.js +1 -0
- package/dist/core/tools/humanApproval.d.ts +4 -2
- package/dist/core/tools/humanApproval.js +3 -1
- package/dist/extensions/awareness/tools.js +6 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/tui/extensionCommand.d.ts +1 -1
- package/dist/tui/extensionCommand.js +14 -6
- package/package.json +1 -1
- package/schemas/agent-kit-metadata.schema.json +5 -0
package/dist/core/messages/de.js
CHANGED
|
@@ -35,7 +35,7 @@ export const de = {
|
|
|
35
35
|
extensionSwitched: (name, enabled) => `(${name} ${enabled ? "aktiviert" : "deaktiviert"}, in derselben Sitzung)`,
|
|
36
36
|
extensionToggled: (name, enabled) => `(${name} ${enabled ? "aktiviert" : "deaktiviert"}: die Sitzung wird mit derselben Unterhaltung neu geöffnet)`,
|
|
37
37
|
extensionNotInstalled: (name) => `(${name} ist nicht installiert: /extensions listet sie auf)`,
|
|
38
|
-
extensionsUsage: "(Verwendung: /extensions, enable|disable <Name>, config <Name> [Schlüssel=Wert…], search [Wörter], install <Name>, update [Name], remove <Name> [--delete-data], reload, trust, sign-in <Name> [Rückruf-URL], sign-out <Name>)",
|
|
38
|
+
extensionsUsage: "(Verwendung: /extensions, enable|disable <Name>, config <Name> [Schlüssel=Wert… | confirm=on|off|reset], search [Wörter], install <Name>, update [Name], remove <Name> [--delete-data], reload, trust, sign-in <Name> [Rückruf-URL], sign-out <Name>)",
|
|
39
39
|
extensionsCantReopen: "(dieser Chat kann seine Sitzung nicht neu öffnen: im Terminal aktivieren oder deaktivieren und neu starten)",
|
|
40
40
|
extensionOptions: (name) => `Optionen von ${name}:`,
|
|
41
41
|
extensionNoOptions: (name) => `(${name} hat keine Optionen)`,
|
|
@@ -60,6 +60,15 @@ export const de = {
|
|
|
60
60
|
extensionAlreadySignedIn: (name) => `(${name} ist bereits angemeldet)`,
|
|
61
61
|
extensionSignInUnavailable: (name) => `(bei ${name} kann man sich hier nicht anmelden: sie läuft nicht in dieser Sitzung, hat keinen entfernten Server, oder das SDK dieses Agenten kann es nicht)`,
|
|
62
62
|
extensionSignedOut: (name) => `(bei ${name} abgemeldet: sie bittet dich, dich erneut anzumelden)`,
|
|
63
|
+
remoteCallTitle: (destination) => `Das an ${destination} senden? Es verlässt diesen Computer`,
|
|
64
|
+
guidedTitle: (extension) => `${extension} das tun lassen?`,
|
|
65
|
+
confirmAnswers: { yes: "Ja", session: "Ja, für diese Sitzung", always: "Ja, immer", no: "Nein", never: "Nein, nie" },
|
|
66
|
+
extensionConfirmOn: (name) => `Im geführten Modus fragen die Werkzeuge von ${name}, die etwas ändern, zuerst (confirm=off führt sie ohne Nachfrage aus):`,
|
|
67
|
+
extensionConfirmOff: (name) => `Im geführten Modus laufen die Werkzeuge von ${name} ohne Nachfrage (confirm=on fragt wieder).`,
|
|
68
|
+
confirmKept: (tool, answer) => ` ${tool}: ${answer === "always" ? "immer ja" : "nie"}`,
|
|
69
|
+
confirmNoneKept: " (keine gespeicherten Antworten; confirm=reset vergisst sie)",
|
|
70
|
+
connectorsAllowed: (names) => `claude.ai-Connectoren: ${names}`,
|
|
71
|
+
connectorsMissing: (names) => `Nicht in deinem claude.ai-Konto: ${names} (verbinde ihn auf claude.ai und öffne die Sitzung neu)`,
|
|
63
72
|
extensionInstalled: (name) => `(${name} installiert: in einem neuen Gespräch da, oder sofort mit /extensions reload, ohne dieses zu verlieren)`,
|
|
64
73
|
extensionUpdated: (name, from, to) => `(${name} aktualisiert, ${from} → ${to}: in einem neuen Gespräch da, oder sofort mit /extensions reload)`,
|
|
65
74
|
extensionsUpToDate: "(alle Erweiterungen aus einem Marketplace sind aktuell)",
|
|
@@ -82,6 +82,28 @@ export interface Messages {
|
|
|
82
82
|
extensionAlreadySignedIn(name: string): string;
|
|
83
83
|
extensionSignInUnavailable(name: string): string;
|
|
84
84
|
extensionSignedOut(name: string): string;
|
|
85
|
+
/** Before a call to a remote MCP server, when the agent asks first (#70): where it goes. */
|
|
86
|
+
remoteCallTitle(destination: string): string;
|
|
87
|
+
/** Guided mode's question before an installed extension's tool that changes things (#74): its title. */
|
|
88
|
+
guidedTitle(extension: string): string;
|
|
89
|
+
/** Its answers (#76): this call, this session, always, no, never. */
|
|
90
|
+
confirmAnswers: {
|
|
91
|
+
yes: string;
|
|
92
|
+
session: string;
|
|
93
|
+
always: string;
|
|
94
|
+
no: string;
|
|
95
|
+
never: string;
|
|
96
|
+
};
|
|
97
|
+
/** In /extensions config: whether its tools ask in guided mode, before the answers kept. */
|
|
98
|
+
extensionConfirmOn(name: string): string;
|
|
99
|
+
extensionConfirmOff(name: string): string;
|
|
100
|
+
/** A kept answer about one of its tools. */
|
|
101
|
+
confirmKept(tool: string, answer: "always" | "never"): string;
|
|
102
|
+
confirmNoneKept: string;
|
|
103
|
+
/** In /extensions: the claude.ai connectors let in (#70). */
|
|
104
|
+
connectorsAllowed(names: string): string;
|
|
105
|
+
/** In /extensions: connectors the agent asked for that the account hasn't. */
|
|
106
|
+
connectorsMissing(names: string): string;
|
|
85
107
|
extensionUpdated(name: string, from: string, to: string): string;
|
|
86
108
|
extensionsUpToDate: string;
|
|
87
109
|
extensionRemoved(name: string, withData: boolean): string;
|
package/dist/core/messages/en.js
CHANGED
|
@@ -34,7 +34,7 @@ export const en = {
|
|
|
34
34
|
extensionSwitched: (name, enabled) => `(${name} ${enabled ? "enabled" : "disabled"}, in this same session)`,
|
|
35
35
|
extensionToggled: (name, enabled) => `(${name} ${enabled ? "enabled" : "disabled"}: the session reopens, with the same conversation)`,
|
|
36
36
|
extensionNotInstalled: (name) => `(${name} isn't installed: /extensions lists them)`,
|
|
37
|
-
extensionsUsage: "(usage: /extensions, enable|disable <name>, config <name> [key=value…], search [words], install <name>, update [name], remove <name> [--delete-data], reload, trust, sign-in <name> [callback URL], sign-out <name>)",
|
|
37
|
+
extensionsUsage: "(usage: /extensions, enable|disable <name>, config <name> [key=value… | confirm=on|off|reset], search [words], install <name>, update [name], remove <name> [--delete-data], reload, trust, sign-in <name> [callback URL], sign-out <name>)",
|
|
38
38
|
extensionsCantReopen: "(this chat can't reopen its session: enable or disable it from the terminal, and start again)",
|
|
39
39
|
extensionOptions: (name) => `${name}'s options:`,
|
|
40
40
|
extensionNoOptions: (name) => `(${name} has no options)`,
|
|
@@ -60,6 +60,15 @@ export const en = {
|
|
|
60
60
|
extensionAlreadySignedIn: (name) => `(${name} is already signed in)`,
|
|
61
61
|
extensionSignInUnavailable: (name) => `(${name} can't be signed in to here: it isn't running in this session, has no remote server, or this agent's SDK can't sign in)`,
|
|
62
62
|
extensionSignedOut: (name) => `(signed out of ${name}: it will ask you to sign in again)`,
|
|
63
|
+
remoteCallTitle: (destination) => `Send this to ${destination}? It leaves this computer`,
|
|
64
|
+
guidedTitle: (extension) => `Let ${extension} do this?`,
|
|
65
|
+
confirmAnswers: { yes: "Yes", session: "Yes, for this session", always: "Yes, always", no: "No", never: "No, never" },
|
|
66
|
+
extensionConfirmOn: (name) => `In guided mode, ${name}'s tools that change things ask first (confirm=off runs them without asking):`,
|
|
67
|
+
extensionConfirmOff: (name) => `In guided mode, ${name}'s tools run without asking (confirm=on asks again).`,
|
|
68
|
+
confirmKept: (tool, answer) => ` ${tool}: ${answer === "always" ? "always yes" : "never"}`,
|
|
69
|
+
confirmNoneKept: " (no kept answers; confirm=reset forgets them)",
|
|
70
|
+
connectorsAllowed: (names) => `claude.ai connectors: ${names}`,
|
|
71
|
+
connectorsMissing: (names) => `Not in your claude.ai account: ${names} (connect it on claude.ai, then reopen the session)`,
|
|
63
72
|
extensionUpdated: (name, from, to) => `(${name} updated, ${from} → ${to}: it's there in a new conversation, or now with /extensions reload)`,
|
|
64
73
|
extensionsUpToDate: "(every extension from a marketplace is up to date)",
|
|
65
74
|
extensionRemoved: (name, withData) => `(${name} removed${withData ? ", with its data" : "; its data is kept for a reinstall"})`,
|
package/dist/core/messages/es.js
CHANGED
|
@@ -35,7 +35,7 @@ export const es = {
|
|
|
35
35
|
extensionSwitched: (name, enabled) => `(${name} ${enabled ? "activada" : "desactivada"}, en esta misma sesión)`,
|
|
36
36
|
extensionToggled: (name, enabled) => `(${name} ${enabled ? "activada" : "desactivada"}: la sesión se reabre, con la misma conversación)`,
|
|
37
37
|
extensionNotInstalled: (name) => `(${name} no está instalada: /extensions las lista)`,
|
|
38
|
-
extensionsUsage: "(uso: /extensions, enable|disable <nombre>, config <nombre> [clave=valor…], search [palabras], install <nombre>, update [nombre], remove <nombre> [--delete-data], reload, trust, sign-in <nombre> [URL de vuelta], sign-out <nombre>)",
|
|
38
|
+
extensionsUsage: "(uso: /extensions, enable|disable <nombre>, config <nombre> [clave=valor… | confirm=on|off|reset], search [palabras], install <nombre>, update [nombre], remove <nombre> [--delete-data], reload, trust, sign-in <nombre> [URL de vuelta], sign-out <nombre>)",
|
|
39
39
|
extensionsCantReopen: "(este chat no puede reabrir su sesión: actívala o desactívala desde la terminal y vuelve a empezar)",
|
|
40
40
|
extensionOptions: (name) => `Opciones de ${name}:`,
|
|
41
41
|
extensionNoOptions: (name) => `(${name} no tiene opciones)`,
|
|
@@ -60,6 +60,15 @@ export const es = {
|
|
|
60
60
|
extensionAlreadySignedIn: (name) => `(${name} ya tiene la sesión iniciada)`,
|
|
61
61
|
extensionSignInUnavailable: (name) => `(no se puede iniciar sesión en ${name} aquí: no se ejecuta en esta sesión, no tiene servidor remoto, o el SDK de este agente no sabe hacerlo)`,
|
|
62
62
|
extensionSignedOut: (name) => `(sesión cerrada en ${name}: te pedirá que vuelvas a iniciarla)`,
|
|
63
|
+
remoteCallTitle: (destination) => `¿Enviar esto a ${destination}? Sale de este ordenador`,
|
|
64
|
+
guidedTitle: (extension) => `¿Dejas que ${extension} haga esto?`,
|
|
65
|
+
confirmAnswers: { yes: "Sí", session: "Sí, en esta sesión", always: "Sí, siempre", no: "No", never: "No, nunca" },
|
|
66
|
+
extensionConfirmOn: (name) => `En modo guiado, las herramientas de ${name} que cambian cosas preguntan antes (confirm=off las ejecuta sin preguntar):`,
|
|
67
|
+
extensionConfirmOff: (name) => `En modo guiado, las herramientas de ${name} se ejecutan sin preguntar (confirm=on vuelve a preguntar).`,
|
|
68
|
+
confirmKept: (tool, answer) => ` ${tool}: ${answer === "always" ? "siempre sí" : "nunca"}`,
|
|
69
|
+
confirmNoneKept: " (ninguna respuesta guardada; confirm=reset las olvida)",
|
|
70
|
+
connectorsAllowed: (names) => `Conectores de claude.ai: ${names}`,
|
|
71
|
+
connectorsMissing: (names) => `No están en tu cuenta de claude.ai: ${names} (conéctalo en claude.ai y vuelve a abrir la sesión)`,
|
|
63
72
|
extensionInstalled: (name) => `(${name} instalada: está en una conversación nueva, o ya con /extensions reload, sin perder esta)`,
|
|
64
73
|
extensionUpdated: (name, from, to) => `(${name} actualizada, ${from} → ${to}: está en una conversación nueva, o ya con /extensions reload)`,
|
|
65
74
|
extensionsUpToDate: "(todas las extensiones de un marketplace están al día)",
|
package/dist/core/messages/fr.js
CHANGED
|
@@ -35,7 +35,7 @@ export const fr = {
|
|
|
35
35
|
extensionSwitched: (name, enabled) => `(${name} ${enabled ? "activée" : "désactivée"}, dans cette même session)`,
|
|
36
36
|
extensionToggled: (name, enabled) => `(${name} ${enabled ? "activée" : "désactivée"} : la session se rouvre, avec la même conversation)`,
|
|
37
37
|
extensionNotInstalled: (name) => `(${name} n'est pas installée : /extensions les liste)`,
|
|
38
|
-
extensionsUsage: "(usage : /extensions, enable|disable <nom>, config <nom> [clé=valeur…], search [mots], install <nom>, update [nom], remove <nom> [--delete-data], reload, trust, sign-in <nom> [URL de retour], sign-out <nom>)",
|
|
38
|
+
extensionsUsage: "(usage : /extensions, enable|disable <nom>, config <nom> [clé=valeur… | confirm=on|off|reset], search [mots], install <nom>, update [nom], remove <nom> [--delete-data], reload, trust, sign-in <nom> [URL de retour], sign-out <nom>)",
|
|
39
39
|
extensionsCantReopen: "(ce chat ne peut pas rouvrir sa session : activez-la ou désactivez-la depuis le terminal, puis recommencez)",
|
|
40
40
|
extensionOptions: (name) => `Options de ${name} :`,
|
|
41
41
|
extensionNoOptions: (name) => `(${name} n'a pas d'options)`,
|
|
@@ -60,6 +60,15 @@ export const fr = {
|
|
|
60
60
|
extensionAlreadySignedIn: (name) => `(${name} est déjà connectée)`,
|
|
61
61
|
extensionSignInUnavailable: (name) => `(impossible de se connecter à ${name} ici : elle ne tourne pas dans cette session, n'a pas de serveur distant, ou le SDK de cet agent ne sait pas le faire)`,
|
|
62
62
|
extensionSignedOut: (name) => `(déconnecté de ${name} : elle vous demandera de vous reconnecter)`,
|
|
63
|
+
remoteCallTitle: (destination) => `Envoyer ceci à ${destination} ? Cela quitte cet ordinateur`,
|
|
64
|
+
guidedTitle: (extension) => `Laisser ${extension} faire ceci ?`,
|
|
65
|
+
confirmAnswers: { yes: "Oui", session: "Oui, pour cette session", always: "Oui, toujours", no: "Non", never: "Non, jamais" },
|
|
66
|
+
extensionConfirmOn: (name) => `En mode guidé, les outils de ${name} qui modifient des choses demandent d'abord (confirm=off les exécute sans demander) :`,
|
|
67
|
+
extensionConfirmOff: (name) => `En mode guidé, les outils de ${name} s'exécutent sans demander (confirm=on demande à nouveau).`,
|
|
68
|
+
confirmKept: (tool, answer) => ` ${tool} : ${answer === "always" ? "toujours oui" : "jamais"}`,
|
|
69
|
+
confirmNoneKept: " (aucune réponse gardée ; confirm=reset les oublie)",
|
|
70
|
+
connectorsAllowed: (names) => `Connecteurs claude.ai : ${names}`,
|
|
71
|
+
connectorsMissing: (names) => `Absents de votre compte claude.ai : ${names} (connectez-le sur claude.ai, puis rouvrez la session)`,
|
|
63
72
|
extensionInstalled: (name) => `(${name} installée : elle est là dans une nouvelle conversation, ou dès maintenant avec /extensions reload, en gardant celle-ci)`,
|
|
64
73
|
extensionUpdated: (name, from, to) => `(${name} mise à jour, ${from} → ${to} : elle est là dans une nouvelle conversation, ou dès maintenant avec /extensions reload)`,
|
|
65
74
|
extensionsUpToDate: "(toutes les extensions d'un marketplace sont à jour)",
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import type { McpServerStatus } from "@anthropic-ai/claude-agent-sdk";
|
|
2
|
+
/** What an MCP tool's own server says about it: `readOnlyHint`, `destructiveHint`. */
|
|
3
|
+
export type ToolHint = "readOnly" | "destructive";
|
|
2
4
|
/**
|
|
3
|
-
*
|
|
4
|
-
* whose manifest lists no `readOnlyTools
|
|
5
|
+
* What the MCP servers themselves say about their tools (#53, #76): for an installed extension
|
|
6
|
+
* whose manifest lists no `readOnlyTools` (plan mode, guided mode) or no `confirmTools` (guided
|
|
7
|
+
* mode), a tool its server marks `readOnlyHint` only reads, and one it marks `destructiveHint`
|
|
8
|
+
* always asks.
|
|
5
9
|
*
|
|
6
|
-
* Asked when
|
|
10
|
+
* Asked when a gate meets the call, not once at start: a server is `pending` for seconds after
|
|
7
11
|
* the session starts, and one turned off and on again (liveExtensions.ts) may come back with
|
|
8
12
|
* other tools. The SDK's `mcpServerStatus()` gives each connected server's tools with
|
|
9
|
-
* `annotations.readOnly
|
|
10
|
-
* empirically
|
|
11
|
-
* Anything else — not connected, not asked in time, no hint — is no
|
|
13
|
+
* `annotations.readOnly` (and `destructive`), set exactly when the server says the hint is `true`
|
|
14
|
+
* (confirmed empirically for `readOnlyHint`: `false` and no hint both leave it out; the names are
|
|
15
|
+
* the short ones). Anything else — not connected, not asked in time, no hint — is no.
|
|
12
16
|
*/
|
|
17
|
+
export declare function createToolHints(servers: readonly string[], status: () => (() => Promise<McpServerStatus[]>) | undefined, hint: ToolHint): (toolName: string) => Promise<boolean>;
|
|
18
|
+
/** Plan mode's read-only tools from the servers themselves: `createToolHints()` for `readOnlyHint`. */
|
|
13
19
|
export declare function createReadOnlyHints(servers: readonly string[], status: () => (() => Promise<McpServerStatus[]>) | undefined): (toolName: string) => Promise<boolean>;
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* whose manifest lists no `readOnlyTools
|
|
2
|
+
* What the MCP servers themselves say about their tools (#53, #76): for an installed extension
|
|
3
|
+
* whose manifest lists no `readOnlyTools` (plan mode, guided mode) or no `confirmTools` (guided
|
|
4
|
+
* mode), a tool its server marks `readOnlyHint` only reads, and one it marks `destructiveHint`
|
|
5
|
+
* always asks.
|
|
4
6
|
*
|
|
5
|
-
* Asked when
|
|
7
|
+
* Asked when a gate meets the call, not once at start: a server is `pending` for seconds after
|
|
6
8
|
* the session starts, and one turned off and on again (liveExtensions.ts) may come back with
|
|
7
9
|
* other tools. The SDK's `mcpServerStatus()` gives each connected server's tools with
|
|
8
|
-
* `annotations.readOnly
|
|
9
|
-
* empirically
|
|
10
|
-
* Anything else — not connected, not asked in time, no hint — is no
|
|
10
|
+
* `annotations.readOnly` (and `destructive`), set exactly when the server says the hint is `true`
|
|
11
|
+
* (confirmed empirically for `readOnlyHint`: `false` and no hint both leave it out; the names are
|
|
12
|
+
* the short ones). Anything else — not connected, not asked in time, no hint — is no.
|
|
11
13
|
*/
|
|
12
|
-
export function
|
|
14
|
+
export function createToolHints(servers, status, hint) {
|
|
13
15
|
return async (toolName) => {
|
|
14
16
|
const server = servers.find((name) => toolName.startsWith(`mcp__${name}__`));
|
|
15
17
|
const read = status();
|
|
@@ -18,9 +20,13 @@ export function createReadOnlyHints(servers, status) {
|
|
|
18
20
|
const tool = toolName.slice(`mcp__${server}__`.length);
|
|
19
21
|
const statuses = await within(read(), []);
|
|
20
22
|
const found = statuses.find((entry) => entry.name === server && entry.status === "connected");
|
|
21
|
-
return found?.tools?.some((entry) => entry.name === tool && entry.annotations?.
|
|
23
|
+
return found?.tools?.some((entry) => entry.name === tool && entry.annotations?.[hint] === true) ?? false;
|
|
22
24
|
};
|
|
23
25
|
}
|
|
26
|
+
/** Plan mode's read-only tools from the servers themselves: `createToolHints()` for `readOnlyHint`. */
|
|
27
|
+
export function createReadOnlyHints(servers, status) {
|
|
28
|
+
return createToolHints(servers, status, "readOnly");
|
|
29
|
+
}
|
|
24
30
|
// A call to the session made from a hook, before a tool runs: never let it hold the tool up.
|
|
25
31
|
const TIMEOUT_MS = 3000;
|
|
26
32
|
const within = (promise, fallback) => Promise.race([promise.catch(() => fallback), new Promise((resolve) => setTimeout(() => resolve(fallback), TIMEOUT_MS).unref())]);
|
package/dist/core/runner.js
CHANGED
|
@@ -35,6 +35,29 @@ function signInControls(result) {
|
|
|
35
35
|
...(clear ? { mcpClearAuth: (server) => clear(server) } : {}),
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Turns back on the servers the CLI saved as switched off in an earlier session (#75):
|
|
40
|
+
* `toggleMcpServer(name, false)` is saved in the Claude Code config of the session's folder
|
|
41
|
+
* (`~/.claude.json`, `disabledMcpServers`), not only in the session (confirmed empirically, CLI
|
|
42
|
+
* 2.1.300), so a server the kit passes again would start disabled. The kit passes only what it
|
|
43
|
+
* wants running, so one of them that starts disabled is turned on, which also removes the saved
|
|
44
|
+
* entry. Only while the session's servers start: switching one off later in the session is the
|
|
45
|
+
* live switch's (liveExtensions.ts).
|
|
46
|
+
*/
|
|
47
|
+
async function restoreSavedSwitches(result, options) {
|
|
48
|
+
const passed = new Set(Object.keys(options.mcpServers ?? {}));
|
|
49
|
+
if (!passed.size)
|
|
50
|
+
return;
|
|
51
|
+
for (let attempt = 0; attempt < 30; attempt++) {
|
|
52
|
+
const status = (await result.mcpServerStatus().catch(() => [])).filter((server) => passed.has(server.name));
|
|
53
|
+
for (const server of status)
|
|
54
|
+
if (server.status === "disabled")
|
|
55
|
+
await result.toggleMcpServer(server.name, true).catch(() => undefined);
|
|
56
|
+
if (status.length && !status.some((server) => server.status === "pending" || server.status === "disabled"))
|
|
57
|
+
return;
|
|
58
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
38
61
|
/**
|
|
39
62
|
* Thin wrapper around the SDK's own `query()`: same two-argument shape (a plain string
|
|
40
63
|
* for a one-shot run, or an `AsyncIterable<SDKUserMessage>` — see `createInputQueue()` —
|
|
@@ -56,6 +79,7 @@ export function runQuery(prompt, options) {
|
|
|
56
79
|
mcpServerStatus: () => result.mcpServerStatus(),
|
|
57
80
|
...signInControls(result),
|
|
58
81
|
});
|
|
82
|
+
void restoreSavedSwitches(result, options);
|
|
59
83
|
// The main agent's tool calls by id, to name the results that come back for them.
|
|
60
84
|
const toolNames = new Map();
|
|
61
85
|
async function* generateEvents() {
|
package/dist/core/session.d.ts
CHANGED
|
@@ -77,6 +77,11 @@ export interface ExtensionsStatus {
|
|
|
77
77
|
sessionTools?: () => readonly string[];
|
|
78
78
|
/** Its MCP servers as they are now (empty until it has started): which remote ones need signing in (#61). */
|
|
79
79
|
serverStatus?: () => Promise<McpServerStatus[]>;
|
|
80
|
+
/** The claude.ai connectors let in (#70), and the ones asked for that the account hasn't; none when the agent asks for none. */
|
|
81
|
+
connectors?: {
|
|
82
|
+
allowed: string[];
|
|
83
|
+
missing: string[];
|
|
84
|
+
};
|
|
80
85
|
}
|
|
81
86
|
/**
|
|
82
87
|
* The CLI's folder for a project, where it keeps each session's transcript and large tool
|
package/dist/core/session.js
CHANGED
|
@@ -8,6 +8,9 @@ import { createSubagentTypeGate } from "./hooks/subagentTypeGate.js";
|
|
|
8
8
|
import { createSubagentForegroundGate } from "./hooks/subagentForegroundGate.js";
|
|
9
9
|
import { createFileScopeGate } from "./hooks/fileScopeGate.js";
|
|
10
10
|
import { createPlanGate } from "./hooks/planGate.js";
|
|
11
|
+
import { createRemoteGate } from "./hooks/remoteGate.js";
|
|
12
|
+
import { createGuidedGate } from "./hooks/guidedGate.js";
|
|
13
|
+
import { chooseConnectors, discoverConnectors, serverToolPrefix } from "./claudeAiConnectors.js";
|
|
11
14
|
import { createHumanApprovalServer } from "./tools/humanApproval.js";
|
|
12
15
|
import { createManualLoginServer } from "./tools/manualLogin.js";
|
|
13
16
|
import { createTimeServer } from "./tools/time.js";
|
|
@@ -17,7 +20,7 @@ import { aboutExtension, describeCapability, extensionsPromptSection, resolveExt
|
|
|
17
20
|
import { allowAnyMcpTool } from "./mcpPermissions.js";
|
|
18
21
|
import { pluginAgents } from "./pluginAgents.js";
|
|
19
22
|
import { outsideArchive, unpackedClaudeExecutable } from "./packaged.js";
|
|
20
|
-
import { listInstalled, loadExternalExtensions, scopePrivateDir } from "./externalExtensions.js";
|
|
23
|
+
import { listInstalled, loadExternalExtensions, readLock, scopePrivateDir } from "./externalExtensions.js";
|
|
21
24
|
import { replyLanguageInstruction } from "./language.js";
|
|
22
25
|
import { chooseLanguage } from "./messages/index.js";
|
|
23
26
|
import { createRunStore } from "./runs.js";
|
|
@@ -25,7 +28,7 @@ import { createSessionView, registerSessionView } from "./sessionFacts.js";
|
|
|
25
28
|
import { createExtensionAuth, createExtensionRestart, createExtensionSwitch, mountPlugin } from "./liveExtensions.js";
|
|
26
29
|
import { secretsDir } from "./extensionOptions.js";
|
|
27
30
|
import { createElicitationHandler } from "./elicitation.js";
|
|
28
|
-
import { createReadOnlyHints } from "./readOnlyHints.js";
|
|
31
|
+
import { createReadOnlyHints, createToolHints } from "./readOnlyHints.js";
|
|
29
32
|
import { agentKitVersion } from "./version.js";
|
|
30
33
|
/**
|
|
31
34
|
* Builds the `options` object passed to the Agent SDK's `query()` — everything about
|
|
@@ -179,6 +182,28 @@ export async function buildSessionOptions(config, runDir, spec, options = {}) {
|
|
|
179
182
|
const readOnlyTools = fromExtensions((contribution) => contribution.readOnlyTools);
|
|
180
183
|
// Those whose manifest lists none: their servers say, asked while the session runs (#53).
|
|
181
184
|
const readOnlyHintServers = fromExtensions((contribution) => contribution.readOnlyHintServers);
|
|
185
|
+
const readOnlyHinted = readOnlyHintServers.length ? createReadOnlyHints(readOnlyHintServers, () => late.view?.controls().mcpServerStatus) : undefined;
|
|
186
|
+
// Guided mode's gate for the installed extensions' tools that change things (#74, #76): whose
|
|
187
|
+
// they are, which always ask (the manifest's list and the agent's, else the servers' hints),
|
|
188
|
+
// and those the person said never to, kept in the lock: out of the session altogether.
|
|
189
|
+
const gateSpec = spec.extensionGate ?? {};
|
|
190
|
+
const guardedExtensions = gateSpec.enabled === false
|
|
191
|
+
? []
|
|
192
|
+
: resolved.active.flatMap(({ extension }, index) => {
|
|
193
|
+
const installed = installedDirs.get(extension.name);
|
|
194
|
+
if (!installed)
|
|
195
|
+
return [];
|
|
196
|
+
const servers = Object.keys(added[index]?.mcpServers ?? {});
|
|
197
|
+
const own = (gateSpec.confirmTools?.[extension.name] ?? []).flatMap((tool) => servers.map((server) => `mcp__${server}__${tool}`));
|
|
198
|
+
return [{ name: extension.name, scopeDir: installed.scopeDir, servers, confirmTools: [...(added[index]?.confirmTools ?? []), ...own] }];
|
|
199
|
+
});
|
|
200
|
+
const neverTools = (await Promise.all(guardedExtensions.map(async (extension) => {
|
|
201
|
+
const confirm = (await readLock(extension.scopeDir).catch(() => ({})))[extension.name]?.confirm;
|
|
202
|
+
if (confirm?.off)
|
|
203
|
+
return [];
|
|
204
|
+
const never = Object.entries(confirm?.tools ?? {}).filter(([, answer]) => answer === "never");
|
|
205
|
+
return never.flatMap(([tool]) => extension.servers.map((server) => `mcp__${server}__${tool}`));
|
|
206
|
+
}))).flat();
|
|
182
207
|
// What no file tool may touch: the agent's denied paths and the SDK's own credentials.
|
|
183
208
|
// And the installed extensions' sensitive option values (#55), in each scope's .secrets/.
|
|
184
209
|
const deniedPaths = [
|
|
@@ -191,6 +216,19 @@ export async function buildSessionOptions(config, runDir, spec, options = {}) {
|
|
|
191
216
|
];
|
|
192
217
|
const transcriptPath = path.join(runDir, "transcript.jsonl");
|
|
193
218
|
const transcriptLogger = createTranscriptLogger(transcriptPath, config.secrets ?? []);
|
|
219
|
+
const guidedGate = guardedExtensions.length
|
|
220
|
+
? createGuidedGate({
|
|
221
|
+
runDir,
|
|
222
|
+
mode: () => modeControl.mode,
|
|
223
|
+
extensions: guardedExtensions,
|
|
224
|
+
isReadOnly: async (tool) => readOnlyTools.includes(tool) || ((await readOnlyHinted?.(tool)) ?? false),
|
|
225
|
+
isDestructive: createToolHints(fromExtensions((contribution) => contribution.confirmHintServers), () => late.view?.controls().mcpServerStatus, "destructive"),
|
|
226
|
+
...(gateSpec.autonomous ? { autonomous: gateSpec.autonomous } : {}),
|
|
227
|
+
// The session's labels, built below: read when a call is asked about.
|
|
228
|
+
labels: () => toolLabels,
|
|
229
|
+
record: (decision) => transcriptLogger.note("guided_decision", { ...decision }),
|
|
230
|
+
})
|
|
231
|
+
: undefined;
|
|
194
232
|
const promptSections = [
|
|
195
233
|
spec.buildSystemPrompt(config),
|
|
196
234
|
// What's on and what isn't, then the extensions' own sections.
|
|
@@ -200,6 +238,12 @@ export async function buildSessionOptions(config, runDir, spec, options = {}) {
|
|
|
200
238
|
];
|
|
201
239
|
// Packaged, the SDK would look for its CLI binary inside the archive, and hang (#42).
|
|
202
240
|
const claudeExecutable = unpackedClaudeExecutable();
|
|
241
|
+
// The claude.ai connectors the agent lets in (#70): the account asked which it has, the rest
|
|
242
|
+
// denied by name (a session setting, never the person's config). None asked, none looked for.
|
|
243
|
+
const connectors = config.claudeAiConnectors?.length
|
|
244
|
+
? chooseConnectors(await discoverConnectors(config.projectDir, claudeExecutable ? { pathToClaudeCodeExecutable: claudeExecutable } : {}), config.claudeAiConnectors)
|
|
245
|
+
: undefined;
|
|
246
|
+
const allowedConnectors = connectors?.allowed ?? [];
|
|
203
247
|
const sdkOptions = {
|
|
204
248
|
...(claudeExecutable ? { pathToClaudeCodeExecutable: claudeExecutable } : {}),
|
|
205
249
|
systemPrompt: withReplyLine(promptSections.join("\n\n")),
|
|
@@ -220,7 +264,8 @@ export async function buildSessionOptions(config, runDir, spec, options = {}) {
|
|
|
220
264
|
autoCompactEnabled: options.autoCompactEnabled ?? true,
|
|
221
265
|
autoMemoryEnabled: false,
|
|
222
266
|
includeGitInstructions: false,
|
|
223
|
-
disableClaudeAiConnectors:
|
|
267
|
+
disableClaudeAiConnectors: !allowedConnectors.length,
|
|
268
|
+
...(allowedConnectors.length && connectors.denied.length ? { deniedMcpServers: connectors.denied.map((serverName) => ({ serverName })) } : {}),
|
|
224
269
|
// An installed extension's plugin may carry hooks: none run (ADR-025). The kit's own,
|
|
225
270
|
// passed in `hooks`, still do (confirmed empirically).
|
|
226
271
|
...(externalPlugins.size ? { disableAllHooks: true } : {}),
|
|
@@ -246,7 +291,8 @@ export async function buildSessionOptions(config, runDir, spec, options = {}) {
|
|
|
246
291
|
// mcpPermissions.ts for why a fixed allowedTools wildcard can't cover a server whose
|
|
247
292
|
// name isn't known ahead of time.
|
|
248
293
|
canUseTool: allowAnyMcpTool,
|
|
249
|
-
|
|
294
|
+
// And the extensions' tools the person said never to (#76).
|
|
295
|
+
disallowedTools: [...(spec.disallowedTools ?? []), ...neverTools],
|
|
250
296
|
// TodoWrite (todos.ts) only exists with CLAUDE_CODE_ENABLE_TASKS=0: by default the CLI
|
|
251
297
|
// offers its TaskCreate/TaskUpdate/TaskList/TaskGet tools instead, and drops TodoWrite from
|
|
252
298
|
// the session even when `tools` names it (confirmed empirically). `env` replaces the
|
|
@@ -279,7 +325,7 @@ export async function buildSessionOptions(config, runDir, spec, options = {}) {
|
|
|
279
325
|
...(subagentDefinitions ? { agents: subagentDefinitions } : {}),
|
|
280
326
|
mcpServers: {
|
|
281
327
|
...spec.buildMcpServers(config, runDir),
|
|
282
|
-
...(includeApprovalTool ? { approvals: createHumanApprovalServer(runDir, spec.humanApprovalTexts, { modeControl }) } : {}),
|
|
328
|
+
...(includeApprovalTool ? { approvals: createHumanApprovalServer(runDir, spec.humanApprovalTexts, { modeControl, ...(guidedGate ? { onApproval: guidedGate.approvalAnswered } : {}) }) } : {}),
|
|
283
329
|
...(manualInterventionTexts ? { manualLogin: createManualLoginServer(runDir, manualInterventionTexts) } : {}),
|
|
284
330
|
// The extensions' tools (the knowledge base's, the sources').
|
|
285
331
|
...Object.assign({}, ...added.map((contribution) => contribution.mcpServers ?? {})),
|
|
@@ -292,6 +338,20 @@ export async function buildSessionOptions(config, runDir, spec, options = {}) {
|
|
|
292
338
|
hooks: {
|
|
293
339
|
PreToolUse: [
|
|
294
340
|
{ hooks: [transcriptLogger.preToolUse] },
|
|
341
|
+
// Remote servers (#70): connectors not chosen are blocked; the rest as `remoteServers` says.
|
|
342
|
+
{
|
|
343
|
+
hooks: [
|
|
344
|
+
createRemoteGate({
|
|
345
|
+
runDir,
|
|
346
|
+
policy: config.remoteServers ?? "allow",
|
|
347
|
+
destination: (tool) => remoteDestinations.find(([prefix]) => tool.startsWith(prefix))?.[1],
|
|
348
|
+
allowedConnectors: allowedConnectors.map(serverToolPrefix),
|
|
349
|
+
canAsk: () => modeControl.mode !== "autonomous",
|
|
350
|
+
}),
|
|
351
|
+
],
|
|
352
|
+
},
|
|
353
|
+
// Guided mode asks before an installed extension's tool that changes things (#74, #76).
|
|
354
|
+
...(guidedGate ? [{ hooks: [guidedGate.preToolUse] }] : []),
|
|
295
355
|
...(fileTools.length || toolOnlyDirs.length
|
|
296
356
|
? [{ hooks: [createFileScopeGate({
|
|
297
357
|
projectDir: config.projectDir,
|
|
@@ -323,7 +383,7 @@ export async function buildSessionOptions(config, runDir, spec, options = {}) {
|
|
|
323
383
|
createPlanGate({
|
|
324
384
|
projectDir: config.projectDir,
|
|
325
385
|
readOnlyTools,
|
|
326
|
-
...(
|
|
386
|
+
...(readOnlyHinted ? { isReadOnlyHinted: readOnlyHinted } : {}),
|
|
327
387
|
...(spec.planMode?.isPlanFile ? { isPlanFile: (filePath) => spec.planMode.isPlanFile(filePath, config) } : {}),
|
|
328
388
|
...(spec.planMode?.isReadOnlyTool ? { isReadOnlyTool: spec.planMode.isReadOnlyTool } : {}),
|
|
329
389
|
}, () => modeControl.mode === "plan"),
|
|
@@ -340,8 +400,28 @@ export async function buildSessionOptions(config, runDir, spec, options = {}) {
|
|
|
340
400
|
: []),
|
|
341
401
|
],
|
|
342
402
|
PostToolUse: [{ hooks: [transcriptLogger.postToolUse] }],
|
|
403
|
+
// The person's message ends a batch they approved (guided mode, #74).
|
|
404
|
+
...(guidedGate ? { UserPromptSubmit: [{ hooks: [guidedGate.userPromptSubmit] }] } : {}),
|
|
343
405
|
},
|
|
344
406
|
};
|
|
407
|
+
// Where each remote server's calls go (#70), for the remote gate: an http/sse server's host
|
|
408
|
+
// (an installed extension's, the agent's own), or the claude.ai connector itself.
|
|
409
|
+
const remoteDestinations = [
|
|
410
|
+
...Object.entries(sdkOptions.mcpServers ?? {}).flatMap(([name, server]) => {
|
|
411
|
+
const remote = server;
|
|
412
|
+
if ((remote.type !== "http" && remote.type !== "sse") || !remote.url)
|
|
413
|
+
return [];
|
|
414
|
+
let host = remote.url;
|
|
415
|
+
try {
|
|
416
|
+
host = new URL(remote.url).host;
|
|
417
|
+
}
|
|
418
|
+
catch {
|
|
419
|
+
// Not a URL the kit can read: the address as given.
|
|
420
|
+
}
|
|
421
|
+
return [[serverToolPrefix(name), host]];
|
|
422
|
+
}),
|
|
423
|
+
...allowedConnectors.map((name) => [serverToolPrefix(name), name]),
|
|
424
|
+
];
|
|
345
425
|
// The extensions' own hooks (the memory hears the person's messages), after the kit's.
|
|
346
426
|
for (const contribution of added) {
|
|
347
427
|
for (const [event, matchers] of Object.entries(contribution.hooks ?? {})) {
|
|
@@ -360,6 +440,7 @@ export async function buildSessionOptions(config, runDir, spec, options = {}) {
|
|
|
360
440
|
sessionTools: () => late.view?.controls().tools ?? [],
|
|
361
441
|
serverStatus: async () => (await late.view?.controls().mcpServerStatus?.().catch(() => [])) ?? [],
|
|
362
442
|
inactive: resolved.inactive,
|
|
443
|
+
...(connectors ? { connectors: { allowed: connectors.allowed, missing: connectors.missing } } : {}),
|
|
363
444
|
};
|
|
364
445
|
// What the session is, for the extensions that ask (sessionFacts.ts, #43).
|
|
365
446
|
const viewBase = {
|
|
@@ -378,6 +459,7 @@ export async function buildSessionOptions(config, runDir, spec, options = {}) {
|
|
|
378
459
|
})),
|
|
379
460
|
// Its own list: /extensions' status has another, and the live switch changes both.
|
|
380
461
|
inactive: [...resolved.inactive],
|
|
462
|
+
...(connectors ? { connectors: { allowed: connectors.allowed, missing: connectors.missing } } : {}),
|
|
381
463
|
},
|
|
382
464
|
subagents: Object.entries(allAgents).map(([name, agent]) => ({ name, description: agent.description })),
|
|
383
465
|
skills: sdkOptions.skills === "all" ? await pluginSkills(pluginRoots) : [...(sdkOptions.skills ?? [])],
|
|
@@ -37,6 +37,11 @@ export interface SessionFacts {
|
|
|
37
37
|
name: string;
|
|
38
38
|
reason: string;
|
|
39
39
|
}[];
|
|
40
|
+
/** The claude.ai connectors let in (#70), and the ones asked for that the account hasn't. */
|
|
41
|
+
connectors?: {
|
|
42
|
+
allowed: string[];
|
|
43
|
+
missing: string[];
|
|
44
|
+
};
|
|
40
45
|
};
|
|
41
46
|
/** The subagents it can delegate to. */
|
|
42
47
|
subagents: {
|
|
@@ -93,6 +98,7 @@ export type StaticSessionFacts = Omit<SessionFacts, "mode" | "switchableModes" |
|
|
|
93
98
|
servers: string[];
|
|
94
99
|
})[];
|
|
95
100
|
inactive: SessionFacts["extensions"]["inactive"];
|
|
101
|
+
connectors?: SessionFacts["extensions"]["connectors"];
|
|
96
102
|
};
|
|
97
103
|
};
|
|
98
104
|
export interface SessionView {
|
|
@@ -26,6 +26,7 @@ export function createSessionView(base, modeControl) {
|
|
|
26
26
|
tools: tools.length ? tools.filter((tool) => servers.some((server) => tool.startsWith(`mcp__${server}__`))) : servers.map((server) => `mcp__${server}__*`),
|
|
27
27
|
})),
|
|
28
28
|
inactive: base.extensions.inactive,
|
|
29
|
+
...(base.extensions.connectors ? { connectors: base.extensions.connectors } : {}),
|
|
29
30
|
},
|
|
30
31
|
tools,
|
|
31
32
|
skills: live.skills ?? base.skills,
|
|
@@ -10,10 +10,12 @@ export declare const DEFAULT_HUMAN_APPROVAL_TEXTS: HumanApprovalTexts;
|
|
|
10
10
|
/**
|
|
11
11
|
* The tools that ask the person, in every mode but autonomous: `request_human_approval`
|
|
12
12
|
* (right before an action that publishes something visible to others and that's hard to
|
|
13
|
-
* undo
|
|
13
|
+
* undo; approved, guided mode lets the calls that follow through until the person's next
|
|
14
|
+
* message, see hooks/guidedGate.ts), `ask_human` (a choice between options, in a panel, within the turn) and, when the
|
|
14
15
|
* session can be in plan mode (`modeControl`), `present_plan`, the kit's own way out of plan
|
|
15
16
|
* mode (ADR-023): the person runs the plan, keeps planning or cancels.
|
|
16
17
|
*/
|
|
17
18
|
export declare function createHumanApprovalServer(runDir: string, texts?: HumanApprovalTexts, options?: {
|
|
18
|
-
modeControl?: ModeControl;
|
|
19
|
+
modeControl?: ModeControl; /** Each approval's answer: guided mode's batch (#74). */
|
|
20
|
+
onApproval?: (approved: boolean) => void;
|
|
19
21
|
}): import("@anthropic-ai/claude-agent-sdk").McpSdkServerConfigWithInstance;
|
|
@@ -16,7 +16,8 @@ const ok = (text) => ({ content: [{ type: "text", text }] });
|
|
|
16
16
|
/**
|
|
17
17
|
* The tools that ask the person, in every mode but autonomous: `request_human_approval`
|
|
18
18
|
* (right before an action that publishes something visible to others and that's hard to
|
|
19
|
-
* undo
|
|
19
|
+
* undo; approved, guided mode lets the calls that follow through until the person's next
|
|
20
|
+
* message, see hooks/guidedGate.ts), `ask_human` (a choice between options, in a panel, within the turn) and, when the
|
|
20
21
|
* session can be in plan mode (`modeControl`), `present_plan`, the kit's own way out of plan
|
|
21
22
|
* mode (ADR-023): the person runs the plan, keeps planning or cancels.
|
|
22
23
|
*/
|
|
@@ -29,6 +30,7 @@ export function createHumanApprovalServer(runDir, texts = DEFAULT_HUMAN_APPROVAL
|
|
|
29
30
|
lines: [t().summaryLine(args.summary)],
|
|
30
31
|
});
|
|
31
32
|
const approved = APPROVED_ANSWERS.has(answer);
|
|
33
|
+
options.onApproval?.(approved);
|
|
32
34
|
return {
|
|
33
35
|
content: [{ type: "text", text: approved ? texts.approved : texts.rejected }],
|
|
34
36
|
};
|
|
@@ -27,6 +27,12 @@ export function describeSession(facts) {
|
|
|
27
27
|
});
|
|
28
28
|
const inactive = facts.extensions.inactive.map(({ name, reason }) => `- **${name}** is off: it ${reason}.`);
|
|
29
29
|
sections.push(`## Extensions\n\n${[...active, ...inactive].join("\n") || "None."}`);
|
|
30
|
+
// The claude.ai connectors let in (#70): the account's integrations, not installed extensions.
|
|
31
|
+
const connectors = facts.extensions.connectors;
|
|
32
|
+
if (connectors && (connectors.allowed.length || connectors.missing.length)) {
|
|
33
|
+
const missing = connectors.missing.length ? ` Asked for but not in the person's claude.ai account: ${connectors.missing.join(", ")} (they connect it on claude.ai, then the session opens again).` : "";
|
|
34
|
+
sections.push(`## claude.ai connectors\n\n${connectors.allowed.length ? `${connectors.allowed.join(", ")}: their tools are the person's claude.ai integrations; what you send them leaves the computer.` : "None of the ones asked for."}${missing}`);
|
|
35
|
+
}
|
|
30
36
|
if (facts.subagents.length)
|
|
31
37
|
sections.push(`## Subagents you can delegate to\n\n${facts.subagents.map(({ name, description }) => `- **${name}**: ${description}`).join("\n")}`);
|
|
32
38
|
const own = facts.tools.filter((tool) => !tool.startsWith("mcp__"));
|
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export { createPromptLoader } from "./core/promptTemplate.js";
|
|
|
6
6
|
export { resolveClaudeAuth, type ClaudeAuthConfig } from "./core/claudeAuth.js";
|
|
7
7
|
export { ensureClaudeAuth } from "./tui/claudeAuth.js";
|
|
8
8
|
export { createFriendlyToolLabel, truncate, truncatePath, withToolLabels, withToolPhrases, type ToolDescriber, type ToolLabel, type ToolLabels, } from "./core/toolLabels.js";
|
|
9
|
-
export type { Mode, BaseSessionConfig, AgentSpec, AgentIdentity, PlanModeSpec } from "./core/agentSpec.js";
|
|
9
|
+
export type { Mode, BaseSessionConfig, AgentSpec, AgentIdentity, PlanModeSpec, ExtensionGateSpec } from "./core/agentSpec.js";
|
|
10
10
|
export { buildSessionOptions, createInputQueue, createDeferred, createModeControl, togglePlanMode, type ModeControl, type ExtensionsStatus } from "./core/session.js";
|
|
11
11
|
export { runQuery, type AgentEvent, type AgentRun, type SessionUsage, type ContextUsage } from "./core/runner.js";
|
|
12
12
|
export type { McpAuthentication, SessionFacts } from "./core/sessionFacts.js";
|
|
@@ -17,7 +17,7 @@ export { knowledge, type KnowledgeOptions } from "./extensions/knowledge/index.j
|
|
|
17
17
|
export { memory, type MemoryOptions } from "./extensions/memory/index.js";
|
|
18
18
|
export { describeCapability, readExtensionManifest, type AboutExtension, type CapabilityText, type DescribedCapability, type Extension, type ExtensionCapability, type ExtensionContext, type ExtensionContribution, type ExtensionManifest, type FolderOption, type UnavailableCapability, } from "./core/extensions.js";
|
|
19
19
|
export { checkRequirements, type ExtensionRequirement, type RequirementCheck } from "./core/extensionRequirements.js";
|
|
20
|
-
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 LocalServer, type RemoteServer, isRemoteServer, remoteHosts, remoteServerName, type InstalledExtension, type LockEntry, type ExtensionOptionState, } from "./core/externalExtensions.js";
|
|
20
|
+
export { addExtension, codeStoreDir, installTarget, scopePrivateDir, extensionDataDir, extensionOptionStates, setExtensionOptions, removeExtension, setExtensionEnabled, setExtensionConfirm, listInstalled, readExternalManifest, type ExtensionAuthor, type ExtensionDirs, type ExtensionScope, type ExternalManifest, type ExternalToolLabel, type PluginServer, type LocalServer, type RemoteServer, isRemoteServer, remoteHosts, remoteServerName, type InstalledExtension, type LockEntry, type ExtensionOptionState, type ExtensionConfirm, type ToolConfirmation, } from "./core/externalExtensions.js";
|
|
21
21
|
export type { ExtensionOption, OptionValue } from "./core/extensionOptions.js";
|
|
22
22
|
export type { ExtensionAuth, ExtensionRestart, ExtensionSwitch, SignIn } from "./core/liveExtensions.js";
|
|
23
23
|
export { packageCacheDir, type CachedPackage } from "./core/npxPackages.js";
|
|
@@ -41,6 +41,7 @@ export { createSubagentTypeGate } from "./core/hooks/subagentTypeGate.js";
|
|
|
41
41
|
export { createSubagentForegroundGate } from "./core/hooks/subagentForegroundGate.js";
|
|
42
42
|
export { createFileScopeGate, checkFileScope, type FileScope } from "./core/hooks/fileScopeGate.js";
|
|
43
43
|
export { createPlanGate, checkPlanScope, type PlanScope } from "./core/hooks/planGate.js";
|
|
44
|
+
export { createGuidedGate, type GuardedExtension, type GuidedDecision, type GuidedGate } from "./core/hooks/guidedGate.js";
|
|
44
45
|
export { askForDecision, askForManualIntervention, askForChoice, askForText, type ChoiceAnswer } from "./core/hooks/humanInput.js";
|
|
45
46
|
export { setInteractionPort, getInteractionPort, type InteractionPort, type ApprovalPrompt, type ChoiceSettings } from "./core/interaction.js";
|
|
46
47
|
export { formFields, type FormAnswer, type FormField, type FormRequest } from "./core/elicitation.js";
|
package/dist/index.js
CHANGED
|
@@ -17,7 +17,7 @@ export { knowledge } from "./extensions/knowledge/index.js";
|
|
|
17
17
|
export { memory } from "./extensions/memory/index.js";
|
|
18
18
|
export { describeCapability, readExtensionManifest, } from "./core/extensions.js";
|
|
19
19
|
export { checkRequirements } from "./core/extensionRequirements.js";
|
|
20
|
-
export { addExtension, codeStoreDir, installTarget, scopePrivateDir, extensionDataDir, extensionOptionStates, setExtensionOptions, removeExtension, setExtensionEnabled, listInstalled, readExternalManifest, isRemoteServer, remoteHosts, remoteServerName, } from "./core/externalExtensions.js";
|
|
20
|
+
export { addExtension, codeStoreDir, installTarget, scopePrivateDir, extensionDataDir, extensionOptionStates, setExtensionOptions, removeExtension, setExtensionEnabled, setExtensionConfirm, listInstalled, readExternalManifest, isRemoteServer, remoteHosts, remoteServerName, } from "./core/externalExtensions.js";
|
|
21
21
|
export { packageCacheDir } from "./core/npxPackages.js";
|
|
22
22
|
export { addMarketplace, findPlugin, inspectMarketplace, installFromMarketplace, listMarketplaces, readMarketplaceManifest, removeMarketplace, resolvePluginSource, updateMarketplace, } from "./core/marketplaces.js";
|
|
23
23
|
export { extensionCatalog, installExtension, restoreExtensions, updateExtension } from "./core/extensionCatalog.js";
|
|
@@ -40,6 +40,7 @@ export { createSubagentTypeGate } from "./core/hooks/subagentTypeGate.js";
|
|
|
40
40
|
export { createSubagentForegroundGate } from "./core/hooks/subagentForegroundGate.js";
|
|
41
41
|
export { createFileScopeGate, checkFileScope } from "./core/hooks/fileScopeGate.js";
|
|
42
42
|
export { createPlanGate, checkPlanScope } from "./core/hooks/planGate.js";
|
|
43
|
+
export { createGuidedGate } from "./core/hooks/guidedGate.js";
|
|
43
44
|
export { askForDecision, askForManualIntervention, askForChoice, askForText } from "./core/hooks/humanInput.js";
|
|
44
45
|
export { setInteractionPort, getInteractionPort } from "./core/interaction.js";
|
|
45
46
|
export { formFields } from "./core/elicitation.js";
|
|
@@ -12,7 +12,7 @@ export { chatExtensionsCommand, describe } from "../chat/extensions.js";
|
|
|
12
12
|
* - `extension add <folder> --link [--project]`: registered where it is, to develop it (not copied, its files not checked)
|
|
13
13
|
* - `extension remove <name> [--project | --agent] [--yes | --keep-data]`: asks before deleting its data folder
|
|
14
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)
|
|
15
|
+
* - `extension config <name> [key=value… | key… | --unset key… | confirm=on|off|reset] [--project | --agent]`: its options; `key` alone asks for it (without echo when it's a secret); `confirm=` what guided mode asks about its tools (#74, #76)
|
|
16
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
17
|
* - `extension restore [--trust]`: gets the code a workspace's lock lists and this computer lacks (#57); `--trust` trusts it too
|
|
18
18
|
* - `extension trust [name…]`: lets a workspace's extensions run, as their code is now
|