@anhlp/alp-protocol 0.0.1-beta.3 → 0.0.1-beta.4
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/conformance/cases.json +1 -1
- package/dist/connection.d.ts +4 -0
- package/dist/contract-v1.d.ts +4867 -1197
- package/dist/contract-v1.js +1 -1
- package/dist/events.d.ts +41 -0
- package/dist/index.d.ts +1 -0
- package/dist/rpc.d.ts +651 -11
- package/dist/schedule.d.ts +43 -0
- package/dist/schedule.js +0 -0
- package/dist/session.d.ts +142 -2
- package/dist/wire.d.ts +112 -0
- package/dist/wire.js +78 -3
- package/fixtures/v1/cases.json +3247 -0
- package/package.json +1 -1
- package/schema/ipc-v1.json +953 -17
- package/schema/methods-v1.json +4854 -933
- package/src/connection.ts +4 -0
- package/src/contract-v1.js +1 -1
- package/src/events.ts +28 -2
- package/src/index.ts +1 -0
- package/src/rpc.ts +171 -12
- package/src/schedule.ts +43 -0
- package/src/session.ts +120 -4
- package/src/wire.js +128 -2
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A scheduled continuation: a one-shot job that opens a new turn on a root session at a
|
|
3
|
+
* given time, without a user message. The protocol owns the shape so every
|
|
4
|
+
* client (the CLI, a viewer, an agent tool) reads the same state.
|
|
5
|
+
*/
|
|
6
|
+
/** Where a job stands: waiting for its time, delivered, failed, or cancelled before it fired. */
|
|
7
|
+
export type ScheduleStatus = 'pending' | 'delivered' | 'failed' | 'cancelled';
|
|
8
|
+
/** Why a job failed or still waits; failed may mean execution is unknown. */
|
|
9
|
+
export type ScheduleError = {
|
|
10
|
+
message: string;
|
|
11
|
+
code?: string;
|
|
12
|
+
};
|
|
13
|
+
/** One job as `schedule.list` and `schedule.get` answer it. */
|
|
14
|
+
export type ScheduleJob = {
|
|
15
|
+
/** The job's own id, `sch_` and sixteen hex digits. */
|
|
16
|
+
id: string;
|
|
17
|
+
/** The project whose root session the job continues. */
|
|
18
|
+
projectRoot: string;
|
|
19
|
+
/** The root session the job opens a turn on. */
|
|
20
|
+
sessionId: string;
|
|
21
|
+
/** The continuation the job delivers. */
|
|
22
|
+
prompt: string;
|
|
23
|
+
/** When the job is due, in UTC (ISO 8601). */
|
|
24
|
+
dueAt: string;
|
|
25
|
+
status: ScheduleStatus;
|
|
26
|
+
/**
|
|
27
|
+
* How many times alpd tried to deliver the job. A job delivered once may have been
|
|
28
|
+
* tried twice: a retry after a crash reads the receipt of the first delivery.
|
|
29
|
+
*/
|
|
30
|
+
attempts: number;
|
|
31
|
+
createdAt: string;
|
|
32
|
+
updatedAt: string;
|
|
33
|
+
/** When the job was delivered, failed or cancelled. */
|
|
34
|
+
deliveredAt?: string;
|
|
35
|
+
failedAt?: string;
|
|
36
|
+
cancelledAt?: string;
|
|
37
|
+
/** When the first delivery was tried. */
|
|
38
|
+
attemptedAt?: string;
|
|
39
|
+
/** How late the delivery was, in milliseconds; 0 when it was on time. */
|
|
40
|
+
lateByMs?: number;
|
|
41
|
+
/** The last error of the job: why it failed, or why it still waits. */
|
|
42
|
+
lastError?: ScheduleError;
|
|
43
|
+
};
|
package/dist/schedule.js
ADDED
|
File without changes
|
package/dist/session.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RuntimeKind } from './dto.js';
|
|
2
|
-
import type { SessionSnapshot } from './events.js';
|
|
2
|
+
import type { SessionSnapshot, TurnAttention } from './events.js';
|
|
3
3
|
/** MCP servers a client adds to the agent's own; the agent's names win no collisions. */
|
|
4
4
|
export type HostMcpServer = {
|
|
5
5
|
type: 'stdio';
|
|
@@ -38,6 +38,8 @@ export type SessionSpec = {
|
|
|
38
38
|
maxPeers: number;
|
|
39
39
|
supervisor?: boolean;
|
|
40
40
|
};
|
|
41
|
+
/** Claude: `threadId` does not exist yet and is made from this conversation on its first prompt (a fork or rewind, §12.7). */
|
|
42
|
+
base?: NativeBase;
|
|
41
43
|
};
|
|
42
44
|
/** Where the native harness works, when not the project root: an assignment's git worktree. ALP files are still read from cwd. */
|
|
43
45
|
workdir?: string;
|
|
@@ -60,13 +62,34 @@ export type PromptImage = {
|
|
|
60
62
|
data: string;
|
|
61
63
|
name?: string;
|
|
62
64
|
};
|
|
63
|
-
/**
|
|
65
|
+
/** A stored attachment in a prompt (capability `attachments`, §12.6): its opaque id only, never a path or URL. */
|
|
66
|
+
export type PromptAttachment = {
|
|
67
|
+
type: 'attachment';
|
|
68
|
+
attachmentId: string;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* What alpd hands a runtime for an attachment part once it validated and pinned it (§12.6, the
|
|
72
|
+
* runtime seam of issue #121 branch J): ids, display metadata and digest, never a host path. The
|
|
73
|
+
* runtime reads the bytes through the AttachmentReader alpd binds, and only for a session whose
|
|
74
|
+
* runtime declared it takes attachments.
|
|
75
|
+
*/
|
|
76
|
+
export type RuntimeAttachment = {
|
|
77
|
+
type: 'attachment';
|
|
78
|
+
attachmentId: string;
|
|
79
|
+
name: string;
|
|
80
|
+
mimeType: string;
|
|
81
|
+
detectedMimeType: string;
|
|
82
|
+
size: number;
|
|
83
|
+
sha256: string;
|
|
84
|
+
};
|
|
85
|
+
/** Text parts carry `text`; image parts (`type: 'image'`) carry PromptImage's fields; attachment parts (`type: 'attachment'`) `attachmentId`. */
|
|
64
86
|
export type PromptContent = Array<{
|
|
65
87
|
type: string;
|
|
66
88
|
text?: string;
|
|
67
89
|
mimeType?: string;
|
|
68
90
|
data?: string;
|
|
69
91
|
name?: string;
|
|
92
|
+
attachmentId?: string;
|
|
70
93
|
}>;
|
|
71
94
|
export type PromptInput = {
|
|
72
95
|
clientMessageId: string;
|
|
@@ -139,7 +162,124 @@ export type SessionSummary = SessionSnapshot & {
|
|
|
139
162
|
status: SessionStatus;
|
|
140
163
|
title?: string;
|
|
141
164
|
archived?: boolean;
|
|
165
|
+
/** A root's turn that ended unseen, until a client acknowledges it (capability `session.attention`). */
|
|
166
|
+
attention?: TurnAttention;
|
|
142
167
|
lastError?: SessionError;
|
|
143
168
|
createdAt?: string;
|
|
144
169
|
updatedAt?: string;
|
|
170
|
+
/**
|
|
171
|
+
* Whether alpd can fork or rewind this session's conversation now, and why not (capabilities
|
|
172
|
+
* `session.fork` and `session.rewind`, §12.7). A single turn may still be refused: one in
|
|
173
|
+
* progress, the first one, or one alpd cannot map to the runtime's own history.
|
|
174
|
+
*/
|
|
175
|
+
conversation?: {
|
|
176
|
+
fork: boolean;
|
|
177
|
+
rewind: boolean;
|
|
178
|
+
/** Whether session.reload can restart this root's native process (capability `session.reload`, §12.8); the root must also be open and idle. */
|
|
179
|
+
reload?: boolean;
|
|
180
|
+
/** Whether session.configure can change this root's model, effort or team (capability `session.configure.live`, §12.9); the root must also be open and idle. */
|
|
181
|
+
configure?: boolean;
|
|
182
|
+
reason?: 'runtime_unsupported' | 'not_persistent' | 'not_root';
|
|
183
|
+
};
|
|
184
|
+
/** The session this root was forked from (§12.7). */
|
|
185
|
+
forkedFrom?: ForkProvenance;
|
|
186
|
+
/** Conversation branches rewinds set aside, oldest first; each stays recoverable with session.fork { branchId } (§12.7). */
|
|
187
|
+
branches?: ConversationBranch[];
|
|
188
|
+
};
|
|
189
|
+
/**
|
|
190
|
+
* A Claude conversation ALP has bound a session to but the runtime has not written yet (§12.7): the
|
|
191
|
+
* first prompt resumes `threadId` as a new session, keeping its history through the entry `at` (all of
|
|
192
|
+
* it when absent). Internal to alpd and its runtime; never accepted from a remote client.
|
|
193
|
+
*/
|
|
194
|
+
export type NativeBase = {
|
|
195
|
+
threadId: string;
|
|
196
|
+
at?: string;
|
|
197
|
+
};
|
|
198
|
+
/** Where a fork came from (§12.7): the source root, and the turn its conversation was cut at. */
|
|
199
|
+
export type ForkProvenance = {
|
|
200
|
+
sessionId: string;
|
|
201
|
+
/** The cut: through this turn, or before it; absent when the whole conversation was taken. */
|
|
202
|
+
turnId?: string;
|
|
203
|
+
boundary: 'through' | 'before' | 'whole';
|
|
204
|
+
/** Set when the fork restored a branch a rewind set aside. */
|
|
205
|
+
branchId?: string;
|
|
206
|
+
at: string;
|
|
207
|
+
};
|
|
208
|
+
/** The later turns of a conversation a rewind set aside (§12.7): kept, never deleted, recoverable as a new session. */
|
|
209
|
+
export type ConversationBranch = {
|
|
210
|
+
branchId: string;
|
|
211
|
+
/** The turn the rewind went back to before; it and every later turn are in the branch. */
|
|
212
|
+
beforeTurnId: string;
|
|
213
|
+
/** How many turns the branch holds past the kept conversation. */
|
|
214
|
+
turns: number;
|
|
215
|
+
at: string;
|
|
216
|
+
};
|
|
217
|
+
/**
|
|
218
|
+
* The ALP CLI command that continues a session in a terminal (session.resumeCommand, §12.8): `argv`
|
|
219
|
+
* and the same command quoted for a POSIX shell and for Windows (cmd.exe). `display` is the one for
|
|
220
|
+
* the daemon host's own platform. Never a native runtime's command, credential, env or path.
|
|
221
|
+
*/
|
|
222
|
+
export type ResumeCommand = {
|
|
223
|
+
argv: string[];
|
|
224
|
+
posix: string;
|
|
225
|
+
windows: string;
|
|
226
|
+
display: string;
|
|
227
|
+
platform: 'posix' | 'windows';
|
|
228
|
+
};
|
|
229
|
+
/**
|
|
230
|
+
* The configuration a root runs with, or would after a change, as alpd resolved it (§12.9): its team,
|
|
231
|
+
* agent, runtime, model, effort and mode, and what they bring (delegation targets, ALP tools, MCP
|
|
232
|
+
* servers by name and kind, hook count, an instructions digest). Never a path, command or credential.
|
|
233
|
+
*/
|
|
234
|
+
export type EffectiveConfig = {
|
|
235
|
+
team: string;
|
|
236
|
+
teamLabel?: string;
|
|
237
|
+
agent: string;
|
|
238
|
+
runtime: RuntimeKind;
|
|
239
|
+
model: string;
|
|
240
|
+
thinking: string;
|
|
241
|
+
mode: string;
|
|
242
|
+
/** The permission profile capping the agent's mode, when one does. */
|
|
243
|
+
permissionProfile?: string;
|
|
244
|
+
supervisor: boolean;
|
|
245
|
+
maxPeers?: number;
|
|
246
|
+
delegates: string[];
|
|
247
|
+
tools: string[];
|
|
248
|
+
mcpServers: Array<{
|
|
249
|
+
name: string;
|
|
250
|
+
kind: 'stdio' | 'http';
|
|
251
|
+
}>;
|
|
252
|
+
hooks: number;
|
|
253
|
+
instructionsSha?: string;
|
|
254
|
+
};
|
|
255
|
+
export type ConfigureChange = 'model' | 'thinking' | 'team' | 'mode';
|
|
256
|
+
export type ConfigureRefusal = 'session_busy' | 'session_closed' | 'not_root' | 'runtime_unsupported' | 'runtime_mismatch' | 'agent_mismatch' | 'permission_escalation' | 'team_not_found' | 'invalid_params' | 'not_persistent';
|
|
257
|
+
/** session.configure.preview (§12.9): the current and proposed configuration, and whether alpd would apply it now. */
|
|
258
|
+
export type ConfigurePreview = {
|
|
259
|
+
current: EffectiveConfig;
|
|
260
|
+
proposed: EffectiveConfig;
|
|
261
|
+
changes: ConfigureChange[];
|
|
262
|
+
/** Applying it restarts the root's native process on its own conversation. */
|
|
263
|
+
restart: boolean;
|
|
264
|
+
/** session.configure would take it now; a tree that gets busy meanwhile still refuses it. */
|
|
265
|
+
allowed: boolean;
|
|
266
|
+
reason?: ConfigureRefusal;
|
|
267
|
+
message?: string;
|
|
268
|
+
teams: Array<{
|
|
269
|
+
id: string;
|
|
270
|
+
label: string;
|
|
271
|
+
description?: string;
|
|
272
|
+
}>;
|
|
273
|
+
};
|
|
274
|
+
/** What a session.configure with model, thinking or team did (§12.9): what was asked, and what the root runs with now. */
|
|
275
|
+
export type ConfigureOutcome = {
|
|
276
|
+
status: 'applied' | 'unchanged';
|
|
277
|
+
requested: {
|
|
278
|
+
model?: string;
|
|
279
|
+
thinking?: string;
|
|
280
|
+
team?: string;
|
|
281
|
+
mode?: string;
|
|
282
|
+
};
|
|
283
|
+
effective: EffectiveConfig;
|
|
284
|
+
restarted: boolean;
|
|
145
285
|
};
|
package/dist/wire.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The decoded bytes one attachment.chunk may carry over frames of at most `maxFrame` bytes:
|
|
3
|
+
* `maxChunkBytes`, lowered so its base64 and ATTACHMENT_CHUNK_OVERHEAD fit. At least 1 byte.
|
|
4
|
+
* @param {number} [maxFrame] @param {number} [maxChunkBytes]
|
|
5
|
+
*/
|
|
6
|
+
export function attachmentChunkBytes(maxFrame?: number, maxChunkBytes?: number): number;
|
|
1
7
|
/**
|
|
2
8
|
* Whether a path relative to a workspace names something workspace.files.list and
|
|
3
9
|
* workspace.files.read never show, whatever the grant: a segment that is a blocked directory, or
|
|
@@ -11,6 +17,31 @@ export function blockedFilePath(relative: string): boolean;
|
|
|
11
17
|
export function encodeFrame(value: unknown): string;
|
|
12
18
|
/** Parse one complete frame. Buffering and failure handling belong to the socket owner. @param {string} line @returns {unknown} */
|
|
13
19
|
export function decodeFrame(line: string): unknown;
|
|
20
|
+
/** One argument for a POSIX shell: as it is when nothing in it is special, else in single quotes. @param {string} arg */
|
|
21
|
+
export function quotePosix(arg: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* One argument for cmd.exe: as it is when nothing in it is special; else in double quotes for the C
|
|
24
|
+
* runtime's split (backslashes before the closing quote doubled), with every cmd.exe metacharacter,
|
|
25
|
+
* the quotes too, escaped with ^ for the interactive parse; the shim's second parse then sees one
|
|
26
|
+
* quoted argument, inside which `&|<>()^` are literal. `"`, `%` and `!` are refused (see above).
|
|
27
|
+
* @param {string} arg
|
|
28
|
+
*/
|
|
29
|
+
export function quoteWindows(arg: string): string;
|
|
30
|
+
/** argv as one command line. @param {string[]} argv @param {'posix' | 'windows'} platform */
|
|
31
|
+
export function commandLine(argv: string[], platform: "posix" | "windows"): string;
|
|
32
|
+
/**
|
|
33
|
+
* session.resumeCommand's answer for a session: `alp attach <sessionId>`, which follows the session in
|
|
34
|
+
* a terminal (a closed one says how to send it a message). ALP keeps the orchestration, so it is never
|
|
35
|
+
* a native runtime's own resume command.
|
|
36
|
+
* @param {string} sessionId @param {'posix' | 'windows'} platform the daemon host's
|
|
37
|
+
*/
|
|
38
|
+
export function resumeCommandOf(sessionId: string, platform: "posix" | "windows"): {
|
|
39
|
+
argv: string[];
|
|
40
|
+
posix: string;
|
|
41
|
+
windows: string;
|
|
42
|
+
display: string;
|
|
43
|
+
platform: "posix" | "windows";
|
|
44
|
+
};
|
|
14
45
|
/** Wire protocol of alpd (plans/reference/ALPD.md §3). Bump only for incompatible changes. */
|
|
15
46
|
export const PROTOCOL_VERSION: 1;
|
|
16
47
|
export const MAX_FRAME: number;
|
|
@@ -39,7 +70,12 @@ export const RPC_ERROR: Readonly<{
|
|
|
39
70
|
* a daemon that lists none (one older than this list) has none of them. Unknown names are ignored.
|
|
40
71
|
*/
|
|
41
72
|
export const CAPABILITY: Readonly<{
|
|
73
|
+
sessionInterruptTurn: "session.interrupt.turn";
|
|
42
74
|
attachAfter: "attach.after";
|
|
75
|
+
sessionHistory: "session.history";
|
|
76
|
+
workspaceRegistry: "workspace.registry";
|
|
77
|
+
workspaceWorktree: "workspace.worktree";
|
|
78
|
+
workspaceGit: "workspace.git";
|
|
43
79
|
promptReceipts: "prompt.receipts";
|
|
44
80
|
extensionMethods: "extension.methods";
|
|
45
81
|
team: "team";
|
|
@@ -50,9 +86,18 @@ export const CAPABILITY: Readonly<{
|
|
|
50
86
|
sessionListPage: "session.list.page";
|
|
51
87
|
questionWatch: "question.watch";
|
|
52
88
|
questionWatchTurns: "question.watch.turns";
|
|
89
|
+
sessionAttention: "session.attention";
|
|
53
90
|
workspaceFiles: "workspace.files";
|
|
54
91
|
workspaceFilesRead: "workspace.files.read";
|
|
55
92
|
promptImages: "prompt.images";
|
|
93
|
+
schedule: "schedule";
|
|
94
|
+
attachments: "attachments";
|
|
95
|
+
sessionFork: "session.fork";
|
|
96
|
+
sessionRewind: "session.rewind";
|
|
97
|
+
sessionReload: "session.reload";
|
|
98
|
+
sessionResumeCommand: "session.resumeCommand";
|
|
99
|
+
sessionConfigureLive: "session.configure.live";
|
|
100
|
+
terminal: "terminal";
|
|
56
101
|
}>;
|
|
57
102
|
/**
|
|
58
103
|
* What alpd takes as images in one session.prompt (capability `prompt.images`): inline base64 of
|
|
@@ -78,3 +123,70 @@ export const WORKSPACE_FILES: Readonly<{
|
|
|
78
123
|
maxListEntries: 1000;
|
|
79
124
|
maxPathLength: 4096;
|
|
80
125
|
}>;
|
|
126
|
+
/**
|
|
127
|
+
* Limits of workspace.git.status and workspace.git.diff (capability `workspace.git`,
|
|
128
|
+
* docs/protocol/alp-json-rpc-v1.md §12.5): one file's patch at most `maxFileBytes`, one page's
|
|
129
|
+
* patches at most `maxTotalBytes` (then `nextCursor`), at most `maxUntracked` untracked files with
|
|
130
|
+
* content, `maxStatusFiles` status rows, a base branch name of at most `maxRefLength` characters.
|
|
131
|
+
* A gateway may lower them; never raise them.
|
|
132
|
+
*/
|
|
133
|
+
export const WORKSPACE_GIT: Readonly<{
|
|
134
|
+
maxFileBytes: number;
|
|
135
|
+
maxTotalBytes: number;
|
|
136
|
+
maxUntracked: 200;
|
|
137
|
+
maxStatusFiles: 1000;
|
|
138
|
+
maxRefLength: 255;
|
|
139
|
+
}>;
|
|
140
|
+
/**
|
|
141
|
+
* Limits of non-image attachments (capability `attachments`, docs/protocol/alp-json-rpc-v1.md
|
|
142
|
+
* §12.6): an object of at most `maxObjectBytes`; a prompt of at most `maxPerPrompt` attachments and
|
|
143
|
+
* `maxPromptBytes` together; chunks of at most `maxChunkBytes` decoded (lowered further by
|
|
144
|
+
* attachmentChunkBytes to fit a frame); `maxActiveUploads` incomplete uploads and
|
|
145
|
+
* `maxPrincipalBytes` stored per principal, `maxDaemonBytes` per daemon, retained references
|
|
146
|
+
* included. An incomplete upload expires after `uploadTimeoutMs`; an unreferenced committed object
|
|
147
|
+
* is purged after `unreferencedRetentionMs`, one whose references were all released after
|
|
148
|
+
* `releasedGraceMs`. A display name is at most `maxNameBytes` UTF-8 bytes. An operator or a gateway
|
|
149
|
+
* may lower them, never raise them; daemon.hello advertises the effective ones (`attachmentLimits`).
|
|
150
|
+
*/
|
|
151
|
+
export const ATTACHMENTS: Readonly<{
|
|
152
|
+
maxObjectBytes: number;
|
|
153
|
+
maxPerPrompt: 8;
|
|
154
|
+
maxPromptBytes: number;
|
|
155
|
+
maxChunkBytes: number;
|
|
156
|
+
maxActiveUploads: 2;
|
|
157
|
+
maxPrincipalBytes: number;
|
|
158
|
+
maxDaemonBytes: number;
|
|
159
|
+
uploadTimeoutMs: number;
|
|
160
|
+
unreferencedRetentionMs: number;
|
|
161
|
+
releasedGraceMs: number;
|
|
162
|
+
maxNameBytes: 255;
|
|
163
|
+
}>;
|
|
164
|
+
/**
|
|
165
|
+
* Limits of terminals (capability `terminal`, docs/protocol/alp-json-rpc-v1.md §12.10): at most
|
|
166
|
+
* `maxPerPrincipal` running terminals per principal and `maxPerDaemon` per daemon; a
|
|
167
|
+
* terminal.input of at most `maxInputBytes` UTF-8 bytes; output events of at most
|
|
168
|
+
* `maxOutputFrameBytes` bytes of data; `replayBytes` of output kept per terminal for attach; a
|
|
169
|
+
* terminal ends after `idleMs` without input or output, after `maxLifetimeMs` in any case, and
|
|
170
|
+
* `reconnectMs` after its stream detached unless attached again. Sizes are `minCols`..`maxCols`
|
|
171
|
+
* columns and `minRows`..`maxRows` rows. An operator or a gateway may lower the first eight, never
|
|
172
|
+
* raise them; daemon.hello advertises the effective ones (`terminalLimits`).
|
|
173
|
+
*/
|
|
174
|
+
export const TERMINAL: Readonly<{
|
|
175
|
+
maxPerPrincipal: 4;
|
|
176
|
+
maxPerDaemon: 16;
|
|
177
|
+
maxInputBytes: number;
|
|
178
|
+
maxOutputFrameBytes: number;
|
|
179
|
+
replayBytes: number;
|
|
180
|
+
idleMs: number;
|
|
181
|
+
maxLifetimeMs: number;
|
|
182
|
+
reconnectMs: number;
|
|
183
|
+
minCols: 2;
|
|
184
|
+
maxCols: 500;
|
|
185
|
+
minRows: 1;
|
|
186
|
+
maxRows: 200;
|
|
187
|
+
}>;
|
|
188
|
+
/** The TERMINAL limits a daemon.hello `terminalLimits` carries (the size bounds are fixed). */
|
|
189
|
+
export const TERMINAL_LIMIT_KEYS: readonly string[];
|
|
190
|
+
export function isTerminalId(id: unknown): boolean;
|
|
191
|
+
/** Room an attachment.chunk request needs besides its base64 data. */
|
|
192
|
+
export const ATTACHMENT_CHUNK_OVERHEAD: number;
|
package/dist/wire.js
CHANGED
|
@@ -10,11 +10,46 @@ var AlpRpcError = class extends Error {
|
|
|
10
10
|
};
|
|
11
11
|
var ERROR = Object.freeze({ failed: 1e3, notFound: 1001, forbidden: 1003, conflict: 1004, unavailable: 1005, protocol: 1006 });
|
|
12
12
|
var RPC_ERROR = Object.freeze({ parseError: -32700, invalidRequest: -32600, methodNotFound: -32601, invalidParams: -32602 });
|
|
13
|
-
var CAPABILITY = Object.freeze({ attachAfter: "attach.after", promptReceipts: "prompt.receipts", extensionMethods: "extension.methods", team: "team", task: "task", library: "library", libraryProjectWrite: "library.project.write", settingsLanguage: "settings.language", sessionListPage: "session.list.page", questionWatch: "question.watch", questionWatchTurns: "question.watch.turns", workspaceFiles: "workspace.files", workspaceFilesRead: "workspace.files.read", promptImages: "prompt.images" });
|
|
13
|
+
var CAPABILITY = Object.freeze({ sessionInterruptTurn: "session.interrupt.turn", attachAfter: "attach.after", sessionHistory: "session.history", workspaceRegistry: "workspace.registry", workspaceWorktree: "workspace.worktree", workspaceGit: "workspace.git", promptReceipts: "prompt.receipts", extensionMethods: "extension.methods", team: "team", task: "task", library: "library", libraryProjectWrite: "library.project.write", settingsLanguage: "settings.language", sessionListPage: "session.list.page", questionWatch: "question.watch", questionWatchTurns: "question.watch.turns", sessionAttention: "session.attention", workspaceFiles: "workspace.files", workspaceFilesRead: "workspace.files.read", promptImages: "prompt.images", schedule: "schedule", attachments: "attachments", sessionFork: "session.fork", sessionRewind: "session.rewind", sessionReload: "session.reload", sessionResumeCommand: "session.resumeCommand", sessionConfigureLive: "session.configure.live", terminal: "terminal" });
|
|
14
14
|
var PROMPT_IMAGES = Object.freeze({ mimeTypes: Object.freeze(["image/png", "image/jpeg", "image/gif", "image/webp"]), maxCount: 8, maxBytes: 5 * 1024 * 1024, maxTotalBytes: 11 * 1024 * 1024 });
|
|
15
15
|
var base64Bytes = (data) => Math.floor(data.length * 3 / 4) - (data.endsWith("==") ? 2 : data.endsWith("=") ? 1 : 0);
|
|
16
|
-
var RPC_METHODS = Object.freeze(["assignment.recall", "board.list", "catalog.get", "daemon.hello", "daemon.pause", "daemon.pauses", "daemon.resume", "daemon.shutdown", "daemon.status", "daemon.usage", "extension.register", "extension.unregister", "library.delete", "library.duplicate", "library.get", "library.list", "library.models", "library.rename", "library.save", "library.skills.set", "question.answer", "question.list", "question.watch", "session.archive", "session.attach", "session.close", "session.configure", "session.create", "session.get", "session.interrupt", "session.list", "session.log", "session.message", "session.preview", "session.prompt", "session.release", "session.rename", "session.status", "settings.language.get", "settings.language.set", "task.create", "task.gate.resolve", "task.list", "task.update", "team.list", "workspace.files.list", "workspace.files.read", "workspace.files.search"]);
|
|
16
|
+
var RPC_METHODS = Object.freeze(["assignment.recall", "attachment.abort", "attachment.begin", "attachment.chunk", "attachment.commit", "attachment.delete", "attachment.get", "board.list", "catalog.get", "daemon.hello", "daemon.pause", "daemon.pauses", "daemon.resume", "daemon.shutdown", "daemon.status", "daemon.usage", "extension.register", "extension.unregister", "library.delete", "library.duplicate", "library.get", "library.list", "library.models", "library.rename", "library.save", "library.skills.set", "project.list", "project.register", "project.remove", "question.answer", "question.list", "question.watch", "registry.owner", "registry.worktree", "schedule.cancel", "schedule.create", "schedule.get", "schedule.list", "session.archive", "session.attach", "session.attention.clear", "session.close", "session.configure", "session.configure.preview", "session.create", "session.fork", "session.get", "session.history", "session.interrupt", "session.list", "session.log", "session.message", "session.preview", "session.prompt", "session.release", "session.reload", "session.rename", "session.resumeCommand", "session.rewind", "session.status", "settings.language.get", "settings.language.set", "task.create", "task.gate.resolve", "task.list", "task.update", "team.list", "terminal.attach", "terminal.close", "terminal.create", "terminal.input", "terminal.list", "terminal.resize", "terminal.revoke", "workspace.files.list", "workspace.files.read", "workspace.files.search", "workspace.get", "workspace.git.diff", "workspace.git.status", "workspace.list", "workspace.update", "workspace.worktree.create", "workspace.worktree.options", "workspace.worktree.remove"]);
|
|
17
17
|
var WORKSPACE_FILES = Object.freeze({ maxReadBytes: 1024 * 1024, maxListEntries: 1e3, maxPathLength: 4096 });
|
|
18
|
+
var WORKSPACE_GIT = Object.freeze({ maxFileBytes: 1024 * 1024, maxTotalBytes: 2 * 1024 * 1024, maxUntracked: 200, maxStatusFiles: 1e3, maxRefLength: 255 });
|
|
19
|
+
var ATTACHMENTS = Object.freeze({
|
|
20
|
+
maxObjectBytes: 20 * 1024 * 1024,
|
|
21
|
+
maxPerPrompt: 8,
|
|
22
|
+
maxPromptBytes: 40 * 1024 * 1024,
|
|
23
|
+
maxChunkBytes: 256 * 1024,
|
|
24
|
+
maxActiveUploads: 2,
|
|
25
|
+
maxPrincipalBytes: 200 * 1024 * 1024,
|
|
26
|
+
maxDaemonBytes: 1024 * 1024 * 1024,
|
|
27
|
+
uploadTimeoutMs: 60 * 60 * 1e3,
|
|
28
|
+
unreferencedRetentionMs: 24 * 60 * 60 * 1e3,
|
|
29
|
+
releasedGraceMs: 7 * 24 * 60 * 60 * 1e3,
|
|
30
|
+
maxNameBytes: 255
|
|
31
|
+
});
|
|
32
|
+
var TERMINAL = Object.freeze({
|
|
33
|
+
maxPerPrincipal: 4,
|
|
34
|
+
maxPerDaemon: 16,
|
|
35
|
+
maxInputBytes: 64 * 1024,
|
|
36
|
+
maxOutputFrameBytes: 64 * 1024,
|
|
37
|
+
replayBytes: 1024 * 1024,
|
|
38
|
+
idleMs: 30 * 60 * 1e3,
|
|
39
|
+
maxLifetimeMs: 8 * 60 * 60 * 1e3,
|
|
40
|
+
reconnectMs: 60 * 1e3,
|
|
41
|
+
minCols: 2,
|
|
42
|
+
maxCols: 500,
|
|
43
|
+
minRows: 1,
|
|
44
|
+
maxRows: 200
|
|
45
|
+
});
|
|
46
|
+
var TERMINAL_LIMIT_KEYS = Object.freeze(["maxPerPrincipal", "maxPerDaemon", "maxInputBytes", "maxOutputFrameBytes", "replayBytes", "idleMs", "maxLifetimeMs", "reconnectMs"]);
|
|
47
|
+
var isTerminalId = (id) => typeof id === "string" && /^term_[0-9a-f]{32}$/.test(id);
|
|
48
|
+
var ATTACHMENT_CHUNK_OVERHEAD = 64 * 1024;
|
|
49
|
+
function attachmentChunkBytes(maxFrame = MAX_FRAME, maxChunkBytes = ATTACHMENTS.maxChunkBytes) {
|
|
50
|
+
const fits = Math.floor((maxFrame - ATTACHMENT_CHUNK_OVERHEAD) * 3 / 4);
|
|
51
|
+
return Math.max(1, Math.min(maxChunkBytes, fits));
|
|
52
|
+
}
|
|
18
53
|
var BLOCKED_DIRECTORIES = /* @__PURE__ */ new Set([".git", ".alp", ".ssh", ".gnupg", ".aws", ".azure", ".kube", ".docker", "gcloud"]);
|
|
19
54
|
var BLOCKED_NAMES = /* @__PURE__ */ new Set([".netrc", "_netrc", ".npmrc", ".yarnrc.yml", ".pypirc", ".pgpass", ".htpasswd", ".git-credentials", ".dockercfg", ".boto", ".s3cfg", ".mcp.json", "auth.json", "kubeconfig", "settings.local.json", ".vault-token", "application_default_credentials.json", "token.json"]);
|
|
20
55
|
var BLOCKED_PAIRS = /* @__PURE__ */ new Set(["gh/hosts.yml"]);
|
|
@@ -45,7 +80,38 @@ function encodeFrame(value) {
|
|
|
45
80
|
function decodeFrame(line) {
|
|
46
81
|
return JSON.parse(line);
|
|
47
82
|
}
|
|
83
|
+
var POSIX_SAFE = /^[A-Za-z0-9_@+:,./-]+$/;
|
|
84
|
+
var WINDOWS_SAFE = /^[A-Za-z0-9_@+:./\\-]+$/;
|
|
85
|
+
var assertArgument = (arg) => {
|
|
86
|
+
if (typeof arg !== "string") throw new TypeError("A command argument is a string");
|
|
87
|
+
if (/[\u0000-\u001f\u007f]/.test(arg)) throw new TypeError("A command argument has no control characters");
|
|
88
|
+
return arg;
|
|
89
|
+
};
|
|
90
|
+
function quotePosix(arg) {
|
|
91
|
+
const text = assertArgument(arg);
|
|
92
|
+
return text && POSIX_SAFE.test(text) ? text : `'${text.replace(/'/g, `'\\''`)}'`;
|
|
93
|
+
}
|
|
94
|
+
function quoteWindows(arg) {
|
|
95
|
+
const text = assertArgument(arg);
|
|
96
|
+
if (text && WINDOWS_SAFE.test(text)) return text;
|
|
97
|
+
if (/["%!]/.test(text)) throw new TypeError('A cmd.exe command argument has no ", % or !');
|
|
98
|
+
const quoted = `"${text.replace(/(\\*)$/, "$1$1")}"`;
|
|
99
|
+
return quoted.replace(/([()\][^"`<>&|;, *?])/g, "^$1");
|
|
100
|
+
}
|
|
101
|
+
var SESSION_ID = /^[\w.:-]{1,128}$/;
|
|
102
|
+
function commandLine(argv, platform) {
|
|
103
|
+
return argv.map(platform === "windows" ? quoteWindows : quotePosix).join(" ");
|
|
104
|
+
}
|
|
105
|
+
function resumeCommandOf(sessionId, platform) {
|
|
106
|
+
if (typeof sessionId !== "string" || !SESSION_ID.test(sessionId)) throw new TypeError("A session id is [A-Za-z0-9_.:-], at most 128 characters");
|
|
107
|
+
const argv = ["alp", "attach", sessionId];
|
|
108
|
+
const posix = commandLine(argv, "posix");
|
|
109
|
+
const windows = commandLine(argv, "windows");
|
|
110
|
+
return { argv, posix, windows, display: platform === "windows" ? windows : posix, platform };
|
|
111
|
+
}
|
|
48
112
|
export {
|
|
113
|
+
ATTACHMENTS,
|
|
114
|
+
ATTACHMENT_CHUNK_OVERHEAD,
|
|
49
115
|
AlpRpcError,
|
|
50
116
|
CAPABILITY,
|
|
51
117
|
ERROR,
|
|
@@ -54,9 +120,18 @@ export {
|
|
|
54
120
|
PROTOCOL_VERSION,
|
|
55
121
|
RPC_ERROR,
|
|
56
122
|
RPC_METHODS,
|
|
123
|
+
TERMINAL,
|
|
124
|
+
TERMINAL_LIMIT_KEYS,
|
|
57
125
|
WORKSPACE_FILES,
|
|
126
|
+
WORKSPACE_GIT,
|
|
127
|
+
attachmentChunkBytes,
|
|
58
128
|
base64Bytes,
|
|
59
129
|
blockedFilePath,
|
|
130
|
+
commandLine,
|
|
60
131
|
decodeFrame,
|
|
61
|
-
encodeFrame
|
|
132
|
+
encodeFrame,
|
|
133
|
+
isTerminalId,
|
|
134
|
+
quotePosix,
|
|
135
|
+
quoteWindows,
|
|
136
|
+
resumeCommandOf
|
|
62
137
|
};
|