@nyte-ai/plugin 0.0.0-stage → 0.0.19
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/LICENSE +21 -0
- package/THIRD-PARTY-NOTICES.md +866 -0
- package/dist/chunks/billing-0y7dfkp2.js +146 -0
- package/dist/chunks/billing-2v3g7rd9.js +190 -0
- package/dist/chunks/billing-3j77ss7y.js +86 -0
- package/dist/chunks/billing-3scqmkzb.js +559 -0
- package/dist/chunks/billing-4vz9pxyx.js +22 -0
- package/dist/chunks/billing-6z2kgtyt.js +51 -0
- package/dist/chunks/billing-8rjk35gr.js +444 -0
- package/dist/chunks/billing-9nn3yp18.js +176 -0
- package/dist/chunks/billing-9qc0eqh4.js +174 -0
- package/dist/chunks/billing-a9vqn66p.js +351 -0
- package/dist/chunks/billing-bv5zr32b.js +369 -0
- package/dist/chunks/billing-cy1rg619.js +302 -0
- package/dist/chunks/billing-ejx2hv52.js +323 -0
- package/dist/chunks/billing-h13r0byk.js +80 -0
- package/dist/chunks/billing-hg64tqf1.js +97 -0
- package/dist/chunks/billing-j643d12p.js +197 -0
- package/dist/chunks/billing-kn3d30b4.js +276 -0
- package/dist/chunks/billing-mvc33pv6.js +36 -0
- package/dist/chunks/billing-s4rrspsk.js +7 -0
- package/dist/chunks/billing-svrhh5a5.js +307 -0
- package/dist/chunks/billing-sxc70w72.js +161 -0
- package/dist/chunks/billing-t1qrxe16.js +41 -0
- package/dist/chunks/billing-tm34gm2p.js +528 -0
- package/dist/chunks/billing-tzr3cebf.js +20 -0
- package/dist/chunks/billing-v3hg5rc7.js +373 -0
- package/dist/chunks/billing-wmcbg6fw.js +52 -0
- package/dist/chunks/billing-ye3wk5r3.js +205 -0
- package/dist/chunks/billing-zfpm2rt0.js +29 -0
- package/dist/examples/claude-code/LICENSE +21 -0
- package/dist/examples/claude-code/billing.d.ts +7 -0
- package/dist/examples/claude-code/billing.js +11 -0
- package/dist/examples/claude-code/claude-cli.d.ts +35 -0
- package/dist/examples/claude-code/claude-cli.js +15 -0
- package/dist/examples/claude-code/env.d.ts +1 -0
- package/dist/examples/claude-code/env.js +6 -0
- package/dist/examples/claude-code/index.d.ts +24 -0
- package/dist/examples/claude-code/index.js +149 -0
- package/dist/examples/claude-code/inert-mcp.d.ts +1 -0
- package/dist/examples/claude-code/inert-mcp.js +6 -0
- package/dist/examples/claude-code/model-catalog.d.ts +27 -0
- package/dist/examples/claude-code/model-catalog.js +12 -0
- package/dist/examples/claude-code/process.d.ts +22 -0
- package/dist/examples/claude-code/process.js +25 -0
- package/dist/examples/claude-code/replay.d.ts +4 -0
- package/dist/examples/claude-code/replay.js +11 -0
- package/dist/examples/claude-code/stream.d.ts +3 -0
- package/dist/examples/claude-code/stream.js +16 -0
- package/dist/examples/claude-code/transcript.d.ts +83 -0
- package/dist/examples/claude-code/transcript.js +23 -0
- package/dist/examples/claude-code/turn-relay.d.ts +48 -0
- package/dist/examples/claude-code/turn-relay.js +9 -0
- package/dist/examples/claude-code/wire.d.ts +372 -0
- package/dist/examples/claude-code/wire.js +18 -0
- package/dist/src/acp/connection.d.ts +24 -0
- package/dist/src/acp/connection.js +8 -0
- package/dist/src/acp/index.d.ts +54 -0
- package/dist/src/acp/index.js +1005 -0
- package/dist/src/acp/registry.d.ts +18 -0
- package/dist/src/acp/registry.js +9 -0
- package/dist/src/acp/thread.d.ts +46 -0
- package/dist/src/acp/thread.js +7 -0
- package/dist/src/acp/transcript.d.ts +8 -0
- package/dist/src/acp/transcript.js +11 -0
- package/dist/src/acp/translate.d.ts +33 -0
- package/dist/src/acp/translate.js +20 -0
- package/dist/src/approvals/approvals.d.ts +189 -0
- package/dist/src/approvals/approvals.js +143 -0
- package/dist/src/approvals/schema.d.ts +169 -0
- package/dist/src/approvals/schema.js +18 -0
- package/dist/src/bash-description.d.ts +30 -0
- package/dist/src/bash-description.js +18 -0
- package/dist/src/browser-tools.d.ts +25 -0
- package/dist/src/browser-tools.js +246 -0
- package/dist/src/canvas/canvas-compile.d.ts +48 -0
- package/dist/src/canvas/canvas-compile.js +8 -0
- package/dist/src/canvas/canvas-libraries.d.ts +32 -0
- package/dist/src/canvas/canvas-libraries.js +6 -0
- package/dist/src/canvas/canvas-preview.d.ts +107 -0
- package/dist/src/canvas/canvas-preview.js +12 -0
- package/dist/src/canvas/canvas-protocol.d.ts +184 -0
- package/dist/src/canvas/canvas-protocol.js +75 -0
- package/dist/src/canvas/canvas.d.ts +50 -0
- package/dist/src/canvas/canvas.js +221 -0
- package/dist/src/canvas/schema.d.ts +47 -0
- package/dist/src/canvas/schema.js +8 -0
- package/dist/src/claude-code-sdk/index.d.ts +35 -0
- package/dist/src/claude-code-sdk/index.js +379 -0
- package/dist/src/claude-code-sdk/session.d.ts +50 -0
- package/dist/src/claude-code-sdk/session.js +7 -0
- package/dist/src/claude-code-sdk/transcript.d.ts +19 -0
- package/dist/src/claude-code-sdk/transcript.js +15 -0
- package/dist/src/claude-code-sdk/translate.d.ts +18 -0
- package/dist/src/claude-code-sdk/translate.js +20 -0
- package/dist/src/client/mount.d.ts +44 -0
- package/dist/src/client/mount.js +252 -0
- package/dist/src/client/notifications.d.ts +36 -0
- package/dist/src/client/notifications.js +24 -0
- package/dist/src/client/presentation.d.ts +362 -0
- package/dist/src/client/presentation.js +391 -0
- package/dist/src/client/transcript-tui.d.ts +23 -0
- package/dist/src/client/transcript-tui.js +20 -0
- package/dist/src/client/transcript.d.ts +23 -0
- package/dist/src/client/transcript.js +51 -0
- package/dist/src/client.d.ts +53 -0
- package/dist/src/client.js +22 -0
- package/dist/src/codemode-runtime.d.ts +11 -0
- package/dist/src/codemode-runtime.js +10 -0
- package/dist/src/codemode-worker.d.ts +1 -0
- package/dist/src/codemode-worker.js +2 -0
- package/dist/src/codemode.d.ts +21 -0
- package/dist/src/codemode.js +170 -0
- package/dist/src/core.d.ts +43 -0
- package/dist/src/core.js +11 -0
- package/dist/src/find-on-path.d.ts +4 -0
- package/dist/src/find-on-path.js +8 -0
- package/dist/src/openai-astra-context.d.ts +23 -0
- package/dist/src/openai-astra-context.js +14 -0
- package/dist/src/openai-compaction.d.ts +15 -0
- package/dist/src/openai-compaction.js +55 -0
- package/dist/src/question/client/questions-tui.d.ts +9 -0
- package/dist/src/question/client/questions-tui.js +19 -0
- package/dist/src/question/client/questions.d.ts +9 -0
- package/dist/src/question/client/questions.js +160 -0
- package/dist/src/question/question.d.ts +63 -0
- package/dist/src/question/question.js +9 -0
- package/dist/src/question/schema.d.ts +101 -0
- package/dist/src/question/schema.js +14 -0
- package/dist/src/rename.d.ts +79 -0
- package/dist/src/rename.js +91 -0
- package/dist/src/telemetry.d.ts +36 -0
- package/dist/src/telemetry.js +84 -0
- package/dist/src/web-search.d.ts +78 -0
- package/dist/src/web-search.js +219 -0
- package/package.json +190 -3
- package/README.md +0 -3
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** An ACP agent this machine can start without downloading anything. */
|
|
2
|
+
export interface AcpAgent {
|
|
3
|
+
readonly id: string;
|
|
4
|
+
readonly name: string;
|
|
5
|
+
readonly command: string;
|
|
6
|
+
readonly args: readonly string[];
|
|
7
|
+
readonly env: Readonly<Record<string, string>>;
|
|
8
|
+
}
|
|
9
|
+
/** The agent entries of a registry document; anything else is no entries. */
|
|
10
|
+
export declare function registryEntries(document: unknown): readonly unknown[];
|
|
11
|
+
/**
|
|
12
|
+
* The registry agents installed on this machine, in registry order: a binary
|
|
13
|
+
* agent whose command is on `path`, or an npx agent whose package is
|
|
14
|
+
* installed globally beside `npx` (its own bin, not another command of the
|
|
15
|
+
* same name), run with the registry's arguments. An agent only the registry
|
|
16
|
+
* can download is left out, so choosing a model never downloads one.
|
|
17
|
+
*/
|
|
18
|
+
export declare function installedAgents(entries: readonly unknown[], path: string): Promise<readonly AcpAgent[]>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { ContentBlock, PromptResponse, RequestPermissionRequest, RequestPermissionResponse, SessionUpdate } from "@agentclientprotocol/sdk";
|
|
2
|
+
import type { Api, AssistantMessageEventStream, Model } from "@nyte-ai/ai";
|
|
3
|
+
import type { RuntimeCall, RuntimeVerdict } from "@nyte-ai/core";
|
|
4
|
+
/** Decides a call the agent asks permission for, under the session's policy. */
|
|
5
|
+
export type AcpApprove = (call: RuntimeCall, signal: AbortSignal) => Promise<RuntimeVerdict>;
|
|
6
|
+
/** What one of the agent's tool calls reported once it finished, or as far as it got when the turn ended. */
|
|
7
|
+
export interface AcpToolOutput {
|
|
8
|
+
readonly text: string;
|
|
9
|
+
readonly failed: boolean;
|
|
10
|
+
}
|
|
11
|
+
/** How a thread reaches its agent: one prompt turn, the cancel notification for it, the folder its session runs in, and how a permission it asks for is decided. */
|
|
12
|
+
export interface AcpChannel {
|
|
13
|
+
readonly cwd: string;
|
|
14
|
+
prompt(blocks: readonly ContentBlock[]): Promise<PromptResponse>;
|
|
15
|
+
cancel(): void;
|
|
16
|
+
readonly approve: AcpApprove;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* One ACP session on an agent: the prompt turns Nyte sends it, the updates
|
|
20
|
+
* it streams back as assistant messages, and its tool calls, which Nyte
|
|
21
|
+
* records as mirror calls whose ids start with `prefix`. A permission the
|
|
22
|
+
* agent asks for waits until Nyte records that call, then goes to the
|
|
23
|
+
* channel's `approve` under the call's ACP kind; a call Nyte skips is
|
|
24
|
+
* refused.
|
|
25
|
+
*/
|
|
26
|
+
export declare class AcpThread {
|
|
27
|
+
#private;
|
|
28
|
+
readonly prefix: string;
|
|
29
|
+
constructor(prefix: string, channel: AcpChannel);
|
|
30
|
+
get closed(): boolean;
|
|
31
|
+
/** Sends a prompt turn, or queues it behind the turn the agent is running, since ACP takes no message mid-turn. */
|
|
32
|
+
send(blocks: readonly ContentBlock[]): void;
|
|
33
|
+
update(update: SessionUpdate): void;
|
|
34
|
+
permission(request: RequestPermissionRequest): Promise<RequestPermissionResponse>;
|
|
35
|
+
/** Lets the agent's permission ask for `id`, now or later, go on to its approval: Nyte is recording the call. */
|
|
36
|
+
recording(id: string): void;
|
|
37
|
+
/** Refuses `id` when the agent asks, now or later: Nyte settled it without running it. A call this thread never saw is left alone. */
|
|
38
|
+
skip(id: string): void;
|
|
39
|
+
/** Streams the turn as one assistant message, ending at the agent's next new tool call or at the turn's end; with `tools` false, its tool calls are refused and skipped. */
|
|
40
|
+
respond(model: Model<Api>, signal: AbortSignal | undefined, tools?: boolean): AssistantMessageEventStream;
|
|
41
|
+
/** Waits for the agent to finish tool call `id`: until it completes or fails, the turn ends, or the agent waits on another call's permission. */
|
|
42
|
+
result(id: string, signal: AbortSignal): Promise<AcpToolOutput>;
|
|
43
|
+
/** Stops the running turn: tells the agent, and answers its waiting permissions as cancelled. */
|
|
44
|
+
cancel(): void;
|
|
45
|
+
close(reason?: Error): void;
|
|
46
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ContentBlock } from "@agentclientprotocol/sdk";
|
|
2
|
+
import type { Message, UserMessage } from "@nyte-ai/ai";
|
|
3
|
+
/** A message's identity for telling whether the agent's session already holds it. */
|
|
4
|
+
export declare function messageKey(message: Message): string;
|
|
5
|
+
/** A user message as prompt blocks; an image the agent cannot read becomes a note of its type. */
|
|
6
|
+
export declare function userBlocks(message: UserMessage, images: boolean): ContentBlock[];
|
|
7
|
+
/** The conversation as plain text, for an agent session that did not see it happen. */
|
|
8
|
+
export declare function transcriptText(messages: readonly Message[]): string;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ToolCallContent, Usage } from "@agentclientprotocol/sdk";
|
|
2
|
+
import type { Api, AssistantMessage, AssistantMessageEventStream, Model, ToolCall } from "@nyte-ai/ai";
|
|
3
|
+
import type { ToolClass } from "@nyte-ai/schema";
|
|
4
|
+
import { Type } from "typebox";
|
|
5
|
+
import type { Static } from "typebox";
|
|
6
|
+
export declare const ACP_PROVIDER = "acp";
|
|
7
|
+
export declare const ACP_API = "acp";
|
|
8
|
+
export declare const MIRROR_TOOL = "acp";
|
|
9
|
+
/** A mirror call's arguments: the ACP session it ran in, the agent's own call id, title, kind, input and the paths it touches. */
|
|
10
|
+
export declare const mirrorArguments: Type.TObject<{
|
|
11
|
+
thread: Type.TString;
|
|
12
|
+
id: Type.TString;
|
|
13
|
+
title: Type.TString;
|
|
14
|
+
kind: Type.TString;
|
|
15
|
+
input: Type.TRecord<"^.*$", Type.TUnknown>;
|
|
16
|
+
paths: Type.TArray<Type.TString>;
|
|
17
|
+
}>;
|
|
18
|
+
export type MirrorArguments = Static<typeof mirrorArguments>;
|
|
19
|
+
export declare function emptyMessage(model: Model<Api>): AssistantMessage;
|
|
20
|
+
/** The class Nyte shows and gates an agent's tool call by, from the ACP kind, its paths and its input. */
|
|
21
|
+
export declare function mirrorClass(args: MirrorArguments): ToolClass;
|
|
22
|
+
/** What a finished agent tool call reports, as the text its mirror call returns. */
|
|
23
|
+
export declare function toolText(content: readonly ToolCallContent[], rawOutput: unknown): string;
|
|
24
|
+
/** Builds one assistant message from an agent's streamed text, thoughts and tool calls. */
|
|
25
|
+
export declare class Translator {
|
|
26
|
+
#private;
|
|
27
|
+
constructor(model: Model<Api>, output: AssistantMessage, stream: AssistantMessageEventStream);
|
|
28
|
+
text(delta: string): void;
|
|
29
|
+
thinking(delta: string): void;
|
|
30
|
+
call(call: ToolCall): void;
|
|
31
|
+
usage(usage: Usage): void;
|
|
32
|
+
end(): void;
|
|
33
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ACP_PROVIDER2,
|
|
3
|
+
ACP_API2,
|
|
4
|
+
MIRROR_TOOL2,
|
|
5
|
+
mirrorArguments2,
|
|
6
|
+
emptyMessage2,
|
|
7
|
+
mirrorClass2,
|
|
8
|
+
toolText2,
|
|
9
|
+
Translator2
|
|
10
|
+
} from "../../chunks/billing-9nn3yp18.js";
|
|
11
|
+
export {
|
|
12
|
+
ACP_API2 as ACP_API,
|
|
13
|
+
ACP_PROVIDER2 as ACP_PROVIDER,
|
|
14
|
+
MIRROR_TOOL2 as MIRROR_TOOL,
|
|
15
|
+
Translator2 as Translator,
|
|
16
|
+
emptyMessage2 as emptyMessage,
|
|
17
|
+
mirrorArguments2 as mirrorArguments,
|
|
18
|
+
mirrorClass2 as mirrorClass,
|
|
19
|
+
toolText2 as toolText
|
|
20
|
+
};
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import type { PluginApi, RuntimeCall, RuntimeVerdict, SettingDefinition, ToolDefinition } from "@nyte-ai/core";
|
|
2
|
+
import type { ApprovalPolicy, ApprovalState } from "./schema.ts";
|
|
3
|
+
/** A tool call as the policy sees it: its tool's name, its class, and whether its tool lets a policy hold it. */
|
|
4
|
+
export interface ApprovalTool extends RuntimeCall {
|
|
5
|
+
readonly approval?: ToolDefinition["approval"];
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The host's policy for tool calls, `full` by default. It applies to every
|
|
9
|
+
* session at its next call, including one already running.
|
|
10
|
+
*
|
|
11
|
+
* @category plugins
|
|
12
|
+
* @since 0.1.0
|
|
13
|
+
*/
|
|
14
|
+
export declare const permissions: SettingDefinition<ApprovalPolicy>;
|
|
15
|
+
/**
|
|
16
|
+
* Why `policy` stops `tool` for the user in a workspace at `cwd`, or null
|
|
17
|
+
* when the call runs without asking. Reads, listings, delegation and tools
|
|
18
|
+
* whose `approval` is not `policy` never ask (a subagent's own calls ask in
|
|
19
|
+
* its session); under `auto-edit` an edit in the workspace runs unless it is
|
|
20
|
+
* under `.claude`, `.git` or `.nyte`.
|
|
21
|
+
*
|
|
22
|
+
* @category plugins
|
|
23
|
+
* @since 0.1.0
|
|
24
|
+
*/
|
|
25
|
+
export declare function approvalReason(policy: ApprovalPolicy, tool: ApprovalTool, cwd: string): ApprovalState["reason"] | null;
|
|
26
|
+
/**
|
|
27
|
+
* The approval part with its handlers: the first answer is kept, and
|
|
28
|
+
* `session` records a grant for the tool and answers the session's other
|
|
29
|
+
* waiting approvals for it.
|
|
30
|
+
*
|
|
31
|
+
* @category plugins
|
|
32
|
+
* @since 0.1.0
|
|
33
|
+
*/
|
|
34
|
+
export declare const approval: import("@nyte-ai/core").PartDefinition<{
|
|
35
|
+
class: {
|
|
36
|
+
kind: "read";
|
|
37
|
+
path: string;
|
|
38
|
+
} | {
|
|
39
|
+
kind: "list";
|
|
40
|
+
path: string;
|
|
41
|
+
} | {
|
|
42
|
+
kind: "edit";
|
|
43
|
+
path: string;
|
|
44
|
+
} | {
|
|
45
|
+
description?: string | undefined;
|
|
46
|
+
kind: "shell";
|
|
47
|
+
command: string;
|
|
48
|
+
} | {
|
|
49
|
+
kind: "delegate";
|
|
50
|
+
title: string | null;
|
|
51
|
+
role: "read" | "task" | "create" | "send" | "await" | "stop";
|
|
52
|
+
child: import("@nyte-ai/schema").Id<"session"> | null;
|
|
53
|
+
} | {
|
|
54
|
+
kind: "custom";
|
|
55
|
+
label: string;
|
|
56
|
+
};
|
|
57
|
+
reason: "edit" | "shell" | "tool" | "outside";
|
|
58
|
+
tool: string;
|
|
59
|
+
decision: "session" | "once" | "deny" | null;
|
|
60
|
+
}, {
|
|
61
|
+
once: {
|
|
62
|
+
input: import("@nyte-ai/schema").Schema<object>;
|
|
63
|
+
};
|
|
64
|
+
session: {
|
|
65
|
+
input: import("@nyte-ai/schema").Schema<object>;
|
|
66
|
+
};
|
|
67
|
+
deny: {
|
|
68
|
+
input: import("@nyte-ai/schema").Schema<object>;
|
|
69
|
+
};
|
|
70
|
+
}>;
|
|
71
|
+
declare function approveRuntimeCall(call: RuntimeCall, context: {
|
|
72
|
+
readonly api: PluginApi<"core">;
|
|
73
|
+
readonly signal: AbortSignal;
|
|
74
|
+
}): Promise<RuntimeVerdict>;
|
|
75
|
+
/**
|
|
76
|
+
* Gates tool calls on the session's `permissions` policy, keying grants on
|
|
77
|
+
* each tool's own name. A call in Nyte's loop that asks parks its
|
|
78
|
+
* before_tool hook on an approval part, so the request outlives a host
|
|
79
|
+
* restart and any client watching the session can answer it; a denial
|
|
80
|
+
* reaches the model as the rejected call's reason. A call another agent
|
|
81
|
+
* runtime asks to run comes through `approve` and waits on the same part
|
|
82
|
+
* while its runtime runs; its mirror call (`approval: "runtime"`) is not
|
|
83
|
+
* asked about again. Only a principal with owner authority can allow.
|
|
84
|
+
*
|
|
85
|
+
* @category plugins
|
|
86
|
+
* @since 0.1.0
|
|
87
|
+
*/
|
|
88
|
+
declare const _default: {
|
|
89
|
+
id: string;
|
|
90
|
+
contribute: {
|
|
91
|
+
parts: import("@nyte-ai/core").PartDefinition<{
|
|
92
|
+
class: {
|
|
93
|
+
kind: "read";
|
|
94
|
+
path: string;
|
|
95
|
+
} | {
|
|
96
|
+
kind: "list";
|
|
97
|
+
path: string;
|
|
98
|
+
} | {
|
|
99
|
+
kind: "edit";
|
|
100
|
+
path: string;
|
|
101
|
+
} | {
|
|
102
|
+
description?: string | undefined;
|
|
103
|
+
kind: "shell";
|
|
104
|
+
command: string;
|
|
105
|
+
} | {
|
|
106
|
+
kind: "delegate";
|
|
107
|
+
title: string | null;
|
|
108
|
+
role: "read" | "task" | "create" | "send" | "await" | "stop";
|
|
109
|
+
child: import("@nyte-ai/schema").Id<"session"> | null;
|
|
110
|
+
} | {
|
|
111
|
+
kind: "custom";
|
|
112
|
+
label: string;
|
|
113
|
+
};
|
|
114
|
+
reason: "edit" | "shell" | "tool" | "outside";
|
|
115
|
+
tool: string;
|
|
116
|
+
decision: "session" | "once" | "deny" | null;
|
|
117
|
+
}, {
|
|
118
|
+
once: {
|
|
119
|
+
input: import("@nyte-ai/schema").Schema<object>;
|
|
120
|
+
};
|
|
121
|
+
session: {
|
|
122
|
+
input: import("@nyte-ai/schema").Schema<object>;
|
|
123
|
+
};
|
|
124
|
+
deny: {
|
|
125
|
+
input: import("@nyte-ai/schema").Schema<object>;
|
|
126
|
+
};
|
|
127
|
+
}>[];
|
|
128
|
+
settings: SettingDefinition<"ask" | "auto-edit" | "full">[];
|
|
129
|
+
};
|
|
130
|
+
approve: typeof approveRuntimeCall;
|
|
131
|
+
hooks: {
|
|
132
|
+
before_tool: (call: Readonly<{
|
|
133
|
+
readonly call: import("@nyte-ai/schema").Id<"call">;
|
|
134
|
+
readonly name: string;
|
|
135
|
+
readonly args: import("@nyte-ai/schema").Json;
|
|
136
|
+
readonly class: {
|
|
137
|
+
readonly kind: "read";
|
|
138
|
+
readonly path: string;
|
|
139
|
+
} | {
|
|
140
|
+
readonly kind: "list";
|
|
141
|
+
readonly path: string;
|
|
142
|
+
} | {
|
|
143
|
+
readonly kind: "edit";
|
|
144
|
+
readonly path: string;
|
|
145
|
+
} | {
|
|
146
|
+
readonly description?: string | undefined;
|
|
147
|
+
readonly kind: "shell";
|
|
148
|
+
readonly command: string;
|
|
149
|
+
} | {
|
|
150
|
+
readonly kind: "delegate";
|
|
151
|
+
readonly title: string | null;
|
|
152
|
+
readonly role: "read" | "task" | "create" | "send" | "await" | "stop";
|
|
153
|
+
readonly child: import("@nyte-ai/schema").Id<"session"> | null;
|
|
154
|
+
} | {
|
|
155
|
+
readonly kind: "custom";
|
|
156
|
+
readonly label: string;
|
|
157
|
+
};
|
|
158
|
+
}>, context: {
|
|
159
|
+
readonly api: {
|
|
160
|
+
readonly side: "core";
|
|
161
|
+
readonly sdk: import("@nyte-ai/core").Connection;
|
|
162
|
+
readonly contribute: import("@nyte-ai/core").Registries<"core">;
|
|
163
|
+
readonly storage: import("@nyte-ai/core").PluginStorage;
|
|
164
|
+
readonly signal: AbortSignal;
|
|
165
|
+
hook<N extends "session_activated" | "before_send" | "run_started" | "transform_transcript" | "before_compaction" | "before_request" | "before_tool" | "after_tool" | "after_request" | "run_ended">(name: N, entry: import("@nyte-ai/core").HookEntry<"core", N>): import("@nyte-ai/schema").Disposer;
|
|
166
|
+
report(issue: import("@nyte-ai/schema").ValidationIssue): void;
|
|
167
|
+
reload(): void;
|
|
168
|
+
} & {
|
|
169
|
+
readonly session: import("@nyte-ai/core").Session;
|
|
170
|
+
readonly env: import("@nyte-ai/core").ExecutionEnv;
|
|
171
|
+
wrapEnv(wrap: import("@nyte-ai/core").EnvironmentWrap): import("@nyte-ai/schema").Disposer;
|
|
172
|
+
readonly inputs: import("@nyte-ai/core").Resources;
|
|
173
|
+
request<T = string>(input: import("@nyte-ai/schema").ModelRequestInput<T>): Promise<import("@nyte-ai/schema").ModelRequestOutcome<T>>;
|
|
174
|
+
approve(call: RuntimeCall, signal: AbortSignal): Promise<RuntimeVerdict>;
|
|
175
|
+
};
|
|
176
|
+
readonly signal: AbortSignal;
|
|
177
|
+
readonly session: import("@nyte-ai/schema").SessionId | null;
|
|
178
|
+
readonly head: import("@nyte-ai/schema").HeadName | null;
|
|
179
|
+
readonly run: import("@nyte-ai/schema").RunId | null;
|
|
180
|
+
} & import("@nyte-ai/core").Durable) => Promise<{
|
|
181
|
+
action: "continue";
|
|
182
|
+
reason?: undefined;
|
|
183
|
+
} | {
|
|
184
|
+
action: "reject";
|
|
185
|
+
reason: string;
|
|
186
|
+
}>;
|
|
187
|
+
};
|
|
188
|
+
};
|
|
189
|
+
export default _default;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PERMISSIONS2,
|
|
3
|
+
approvalPolicy2,
|
|
4
|
+
APPROVAL_POLICIES2,
|
|
5
|
+
approval2,
|
|
6
|
+
openApprovals2
|
|
7
|
+
} from "../../chunks/billing-h13r0byk.js";
|
|
8
|
+
|
|
9
|
+
// src/approvals/approvals.ts
|
|
10
|
+
import { posix } from "node:path";
|
|
11
|
+
import { definePart } from "@nyte-ai/core";
|
|
12
|
+
import { SdkError } from "@nyte-ai/schema";
|
|
13
|
+
var DENIED = "The user denied this tool call. Ask them how to proceed instead of retrying it.";
|
|
14
|
+
var UNANSWERED = "The approval request closed before the user answered.";
|
|
15
|
+
var permissions = {
|
|
16
|
+
id: PERMISSIONS2,
|
|
17
|
+
label: "Permissions",
|
|
18
|
+
schema: approvalPolicy2,
|
|
19
|
+
choices: APPROVAL_POLICIES2,
|
|
20
|
+
default: "full",
|
|
21
|
+
scope: "host"
|
|
22
|
+
};
|
|
23
|
+
var GUARDED = new Set([".claude", ".git", ".nyte"]);
|
|
24
|
+
function grantKey(tool) {
|
|
25
|
+
return `grant:${tool}`;
|
|
26
|
+
}
|
|
27
|
+
function workspacePath(cwd, path) {
|
|
28
|
+
const root = posix.resolve(cwd);
|
|
29
|
+
const target = posix.resolve(root, path);
|
|
30
|
+
if (target === root)
|
|
31
|
+
return "";
|
|
32
|
+
return target.startsWith(`${root}/`) ? target.slice(root.length + 1) : null;
|
|
33
|
+
}
|
|
34
|
+
function approvalReason(policy, tool, cwd) {
|
|
35
|
+
const subject = tool.class;
|
|
36
|
+
if (policy === "full" || (tool.approval ?? "policy") !== "policy")
|
|
37
|
+
return null;
|
|
38
|
+
if (subject.kind === "read" || subject.kind === "list" || subject.kind === "delegate")
|
|
39
|
+
return null;
|
|
40
|
+
if (subject.kind === "shell")
|
|
41
|
+
return "shell";
|
|
42
|
+
if (subject.kind === "edit") {
|
|
43
|
+
const path = workspacePath(cwd, subject.path);
|
|
44
|
+
if (path === null)
|
|
45
|
+
return "outside";
|
|
46
|
+
return policy === "ask" || GUARDED.has(path.split("/", 1)[0] ?? "") ? "edit" : null;
|
|
47
|
+
}
|
|
48
|
+
return "tool";
|
|
49
|
+
}
|
|
50
|
+
async function readPolicy(api) {
|
|
51
|
+
const value = await api.contribute.settings.value(PERMISSIONS2);
|
|
52
|
+
const checked = approvalPolicy2["~standard"].validate(value);
|
|
53
|
+
return checked instanceof Promise || checked.issues !== undefined ? permissions.default : checked.value;
|
|
54
|
+
}
|
|
55
|
+
async function pendingReason(api, tool) {
|
|
56
|
+
const reason = approvalReason(await readPolicy(api), tool, api.env.cwd);
|
|
57
|
+
if (reason === null)
|
|
58
|
+
return null;
|
|
59
|
+
return await api.storage.get(grantKey(tool.name)) === true ? null : reason;
|
|
60
|
+
}
|
|
61
|
+
function verdict(action) {
|
|
62
|
+
if (action === "once" || action === "session")
|
|
63
|
+
return { kind: "allow" };
|
|
64
|
+
return { kind: "deny", reason: action === "deny" ? DENIED : UNANSWERED };
|
|
65
|
+
}
|
|
66
|
+
async function decide(decision, context) {
|
|
67
|
+
const allowed = decision === "deny" || context.authority.has("owner");
|
|
68
|
+
let granted = null;
|
|
69
|
+
let refused = false;
|
|
70
|
+
const outcome = await context.part.update((current) => {
|
|
71
|
+
refused = current.decision === null && !allowed;
|
|
72
|
+
granted = current.decision === null || current.decision === decision ? current.tool : null;
|
|
73
|
+
return current.decision === null && allowed ? { ...current, decision } : current;
|
|
74
|
+
});
|
|
75
|
+
if (outcome.kind !== "updated")
|
|
76
|
+
throw new SdkError("invalid", "This approval is no longer waiting.");
|
|
77
|
+
if (refused)
|
|
78
|
+
throw new SdkError("denied", "Only the host's owner can allow a tool call.");
|
|
79
|
+
if (granted === null)
|
|
80
|
+
throw new SdkError("invalid", "This approval was already answered.");
|
|
81
|
+
if (decision !== "session")
|
|
82
|
+
return;
|
|
83
|
+
await context.api.storage.set(grantKey(granted), true);
|
|
84
|
+
for (const sibling of openApprovals2(await context.api.session.view())) {
|
|
85
|
+
if (sibling.part !== context.part.id && sibling.tool === granted)
|
|
86
|
+
await context.api.session.part(sibling.part).act("once", {});
|
|
87
|
+
}
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
var handlers = {
|
|
91
|
+
once: (_input, context) => decide("once", context),
|
|
92
|
+
session: (_input, context) => decide("session", context),
|
|
93
|
+
deny: (_input, context) => decide("deny", context)
|
|
94
|
+
};
|
|
95
|
+
var approval = definePart({
|
|
96
|
+
...approval2,
|
|
97
|
+
onAction: (action, input, context) => handlers[action](input, context)
|
|
98
|
+
});
|
|
99
|
+
async function approveRuntimeCall(call, context) {
|
|
100
|
+
const { api, signal } = context;
|
|
101
|
+
const reason = await pendingReason(api, call);
|
|
102
|
+
if (reason === null)
|
|
103
|
+
return { kind: "allow" };
|
|
104
|
+
const part = await api.session.parts.create(approval, {
|
|
105
|
+
state: { tool: call.name, class: call.class, reason, decision: null },
|
|
106
|
+
placement: { kind: "modal" }
|
|
107
|
+
});
|
|
108
|
+
try {
|
|
109
|
+
return verdict((await part.answer({ signal }))?.action);
|
|
110
|
+
} finally {
|
|
111
|
+
if (signal.aborted)
|
|
112
|
+
await part.close().catch(() => {
|
|
113
|
+
return;
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
var approvals_default = {
|
|
118
|
+
id: "approvals",
|
|
119
|
+
contribute: { parts: [approval], settings: [permissions] },
|
|
120
|
+
approve: approveRuntimeCall,
|
|
121
|
+
hooks: {
|
|
122
|
+
before_tool: async (call, context) => {
|
|
123
|
+
const { api } = context;
|
|
124
|
+
const definition = api.contribute.tools.list().find((tool) => tool.name === call.name);
|
|
125
|
+
const reason = await context.memo("reason", () => pendingReason(api, { name: call.name, class: call.class, approval: definition?.approval }));
|
|
126
|
+
if (reason === null)
|
|
127
|
+
return { action: "continue" };
|
|
128
|
+
const part = await api.session.parts.create(approval, {
|
|
129
|
+
state: { tool: call.name, class: call.class, reason, decision: null },
|
|
130
|
+
placement: { kind: "modal" }
|
|
131
|
+
});
|
|
132
|
+
const outcome = await context.wait({ kind: "part", part: part.id });
|
|
133
|
+
const answered = verdict(outcome.kind === "part" ? outcome.answer?.action : undefined);
|
|
134
|
+
return answered.kind === "allow" ? { action: "continue" } : { action: "reject", reason: answered.reason };
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
export {
|
|
139
|
+
approval,
|
|
140
|
+
approvalReason,
|
|
141
|
+
approvals_default as default,
|
|
142
|
+
permissions
|
|
143
|
+
};
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import type { Infer, PartId, SessionView } from "@nyte-ai/schema";
|
|
2
|
+
declare const policy: import("@nyte-ai/schema").Schema<"ask" | "auto-edit" | "full">;
|
|
3
|
+
/**
|
|
4
|
+
* When a tool call waits for the user: `ask` before any call that may change
|
|
5
|
+
* the workspace, `auto-edit` before shell commands, edits outside the
|
|
6
|
+
* workspace and tools whose effects are unknown, `full` never.
|
|
7
|
+
*/
|
|
8
|
+
export type ApprovalPolicy = Infer<typeof policy>;
|
|
9
|
+
/** The setting that holds the policy; it names the terminal's `/permissions` command. */
|
|
10
|
+
export declare const PERMISSIONS = "permissions";
|
|
11
|
+
/** The policy setting's schema, shared by the plugin and the clients that read it. */
|
|
12
|
+
export declare const approvalPolicy: import("@nyte-ai/schema").Schema<"ask" | "auto-edit" | "full">;
|
|
13
|
+
/** Each policy with the words every client shows for it, in menu order. */
|
|
14
|
+
export declare const APPROVAL_POLICIES: readonly [{
|
|
15
|
+
readonly value: "ask";
|
|
16
|
+
readonly label: "Ask first";
|
|
17
|
+
readonly description: "Asks before every command and file change";
|
|
18
|
+
}, {
|
|
19
|
+
readonly value: "auto-edit";
|
|
20
|
+
readonly label: "Auto-edit";
|
|
21
|
+
readonly description: "Edits workspace files, asks before commands and anything outside";
|
|
22
|
+
}, {
|
|
23
|
+
readonly value: "full";
|
|
24
|
+
readonly label: "Full access";
|
|
25
|
+
readonly description: "Runs every tool without asking";
|
|
26
|
+
}];
|
|
27
|
+
declare const state: import("@nyte-ai/schema").Schema<{
|
|
28
|
+
class: {
|
|
29
|
+
kind: "read";
|
|
30
|
+
path: string;
|
|
31
|
+
} | {
|
|
32
|
+
kind: "list";
|
|
33
|
+
path: string;
|
|
34
|
+
} | {
|
|
35
|
+
kind: "edit";
|
|
36
|
+
path: string;
|
|
37
|
+
} | {
|
|
38
|
+
description?: string | undefined;
|
|
39
|
+
kind: "shell";
|
|
40
|
+
command: string;
|
|
41
|
+
} | {
|
|
42
|
+
kind: "delegate";
|
|
43
|
+
title: string | null;
|
|
44
|
+
role: "read" | "task" | "create" | "send" | "await" | "stop";
|
|
45
|
+
child: import("@nyte-ai/schema").Id<"session"> | null;
|
|
46
|
+
} | {
|
|
47
|
+
kind: "custom";
|
|
48
|
+
label: string;
|
|
49
|
+
};
|
|
50
|
+
reason: "edit" | "shell" | "tool" | "outside";
|
|
51
|
+
tool: string;
|
|
52
|
+
decision: "session" | "once" | "deny" | null;
|
|
53
|
+
}>;
|
|
54
|
+
/**
|
|
55
|
+
* One gated tool call: its tool, its class, why it asks (`shell`, `edit` in
|
|
56
|
+
* the workspace, `outside` the workspace, or another `tool`), and the user's
|
|
57
|
+
* first decision, null while it waits.
|
|
58
|
+
*/
|
|
59
|
+
export type ApprovalState = Infer<typeof state>;
|
|
60
|
+
/** What the user can answer, as part actions. */
|
|
61
|
+
export type ApprovalDecision = Exclude<ApprovalState["decision"], null>;
|
|
62
|
+
/** The three answers in the order every client offers them, with their shared labels. */
|
|
63
|
+
export declare const APPROVAL_ACTIONS: readonly [{
|
|
64
|
+
readonly action: "once";
|
|
65
|
+
readonly label: "Allow once";
|
|
66
|
+
}, {
|
|
67
|
+
readonly action: "session";
|
|
68
|
+
readonly label: "Allow for this session";
|
|
69
|
+
}, {
|
|
70
|
+
readonly action: "deny";
|
|
71
|
+
readonly label: "Deny";
|
|
72
|
+
}];
|
|
73
|
+
/** The question an approval asks and the command, path or label it is about. */
|
|
74
|
+
export interface ApprovalPrompt {
|
|
75
|
+
readonly title: string;
|
|
76
|
+
readonly detail: string;
|
|
77
|
+
}
|
|
78
|
+
/** The words every client shows for an approval. */
|
|
79
|
+
export declare function approvalPrompt(current: Pick<ApprovalState, "tool" | "class" | "reason">): ApprovalPrompt;
|
|
80
|
+
/**
|
|
81
|
+
* A modal request to run one tool call. Its first answer stands: once,
|
|
82
|
+
* session (which also allows the tool for the rest of the session), or deny.
|
|
83
|
+
*
|
|
84
|
+
* @category plugins
|
|
85
|
+
* @since 0.1.0
|
|
86
|
+
*/
|
|
87
|
+
export declare const approval: {
|
|
88
|
+
kind: string;
|
|
89
|
+
state: import("@nyte-ai/schema").Schema<{
|
|
90
|
+
class: {
|
|
91
|
+
kind: "read";
|
|
92
|
+
path: string;
|
|
93
|
+
} | {
|
|
94
|
+
kind: "list";
|
|
95
|
+
path: string;
|
|
96
|
+
} | {
|
|
97
|
+
kind: "edit";
|
|
98
|
+
path: string;
|
|
99
|
+
} | {
|
|
100
|
+
description?: string | undefined;
|
|
101
|
+
kind: "shell";
|
|
102
|
+
command: string;
|
|
103
|
+
} | {
|
|
104
|
+
kind: "delegate";
|
|
105
|
+
title: string | null;
|
|
106
|
+
role: "read" | "task" | "create" | "send" | "await" | "stop";
|
|
107
|
+
child: import("@nyte-ai/schema").Id<"session"> | null;
|
|
108
|
+
} | {
|
|
109
|
+
kind: "custom";
|
|
110
|
+
label: string;
|
|
111
|
+
};
|
|
112
|
+
reason: "edit" | "shell" | "tool" | "outside";
|
|
113
|
+
tool: string;
|
|
114
|
+
decision: "session" | "once" | "deny" | null;
|
|
115
|
+
}>;
|
|
116
|
+
actions: {
|
|
117
|
+
once: {
|
|
118
|
+
input: import("@nyte-ai/schema").Schema<object>;
|
|
119
|
+
};
|
|
120
|
+
session: {
|
|
121
|
+
input: import("@nyte-ai/schema").Schema<object>;
|
|
122
|
+
};
|
|
123
|
+
deny: {
|
|
124
|
+
input: import("@nyte-ai/schema").Schema<object>;
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
fallback: (current: {
|
|
128
|
+
class: {
|
|
129
|
+
kind: "read";
|
|
130
|
+
path: string;
|
|
131
|
+
} | {
|
|
132
|
+
kind: "list";
|
|
133
|
+
path: string;
|
|
134
|
+
} | {
|
|
135
|
+
kind: "edit";
|
|
136
|
+
path: string;
|
|
137
|
+
} | {
|
|
138
|
+
description?: string | undefined;
|
|
139
|
+
kind: "shell";
|
|
140
|
+
command: string;
|
|
141
|
+
} | {
|
|
142
|
+
kind: "delegate";
|
|
143
|
+
title: string | null;
|
|
144
|
+
role: "read" | "task" | "create" | "send" | "await" | "stop";
|
|
145
|
+
child: import("@nyte-ai/schema").Id<"session"> | null;
|
|
146
|
+
} | {
|
|
147
|
+
kind: "custom";
|
|
148
|
+
label: string;
|
|
149
|
+
};
|
|
150
|
+
reason: "edit" | "shell" | "tool" | "outside";
|
|
151
|
+
tool: string;
|
|
152
|
+
decision: "session" | "once" | "deny" | null;
|
|
153
|
+
}, { id }: {
|
|
154
|
+
readonly id: PartId;
|
|
155
|
+
}) => string;
|
|
156
|
+
};
|
|
157
|
+
/** An approval still waiting for the user, with the part its answer goes to. */
|
|
158
|
+
export type OpenApproval = Pick<ApprovalState, "tool" | "class" | "reason"> & {
|
|
159
|
+
readonly part: PartId;
|
|
160
|
+
};
|
|
161
|
+
/**
|
|
162
|
+
* Returns the live approvals nobody has answered, oldest first. Parts from a
|
|
163
|
+
* stopped run and parts with invalid state are left out.
|
|
164
|
+
*
|
|
165
|
+
* @category plugins
|
|
166
|
+
* @since 0.1.0
|
|
167
|
+
*/
|
|
168
|
+
export declare function openApprovals(view: Pick<SessionView, "parts"> | undefined): readonly OpenApproval[];
|
|
169
|
+
export {};
|