@kangentic/protocol 0.19.0 → 0.21.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/README.md +3 -1
- package/dist/capabilities/board-tools.d.ts +2 -2
- package/dist/capabilities/verbs.d.ts +9 -1
- package/dist/crypto/push-envelope.d.ts +18 -1
- package/dist/events/event.d.ts +20 -2
- package/dist/events/payloads.d.ts +80 -0
- package/dist/index.cjs +136 -13
- package/dist/index.d.ts +4 -4
- package/dist/index.mjs +125 -13
- package/dist/wire/framing.d.ts +12 -0
- package/dist/wire/messages.d.ts +17 -1
- package/dist/wire/payloads.d.ts +69 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,7 +25,9 @@ model, and the honest relay-metadata statement.
|
|
|
25
25
|
phone: it is a liveness/intent signal, not the security boundary. It opens only if both peers
|
|
26
26
|
completed the same handshake transcript, which is exactly the property the SAS comparison
|
|
27
27
|
already vouches for - the human's comparison remains the actual defense.
|
|
28
|
-
- No shell, file, or arbitrary-command verb exists in the protocol.
|
|
28
|
+
- No shell, file, or arbitrary-command verb exists in the protocol. `command-terminal` starts the
|
|
29
|
+
project's agent CLI at the project root with no command, branch, or model named by the phone, and
|
|
30
|
+
the desktop ends the session when that agent exits.
|
|
29
31
|
|
|
30
32
|
This package has not undergone a third-party security audit. Report suspected vulnerabilities
|
|
31
33
|
per the repository's security policy rather than filing a public issue.
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
* this protocol surface honest: a tool renamed or removed desktop-side
|
|
14
14
|
* fails that test instead of silently breaking phones.
|
|
15
15
|
*/
|
|
16
|
-
export declare const BOARD_TOOL_READ_NAMES: readonly ["search_tasks", "find_task", "get_current_task", "get_task_stats", "get_usage_stats", "board_summary", "list_sessions", "get_session_history", "get_column_detail", "list_board_profiles", "get_handoff_context", "get_transcript", "get_session_files", "get_session_events", "get_activity_intervals"];
|
|
17
|
-
export declare const BOARD_TOOL_WRITE_NAMES: readonly ["create_task", "update_task", "delete_task", "link_pr", "remove_attachment", "update_column", "create_board_profile", "update_board_profile", "delete_board_profile", "create_backlog_task", "promote_backlog", "update_backlog_item", "delete_backlog_item"];
|
|
16
|
+
export declare const BOARD_TOOL_READ_NAMES: readonly ["search_tasks", "find_task", "get_current_task", "get_task_stats", "get_usage_stats", "board_summary", "list_sessions", "get_session_history", "get_column_detail", "list_board_profiles", "get_handoff_context", "get_transcript", "get_session_files", "get_session_events", "get_activity_intervals", "list_workflows", "get_workflow"];
|
|
17
|
+
export declare const BOARD_TOOL_WRITE_NAMES: readonly ["create_task", "update_task", "delete_task", "link_pr", "remove_attachment", "update_column", "create_board_profile", "update_board_profile", "delete_board_profile", "create_backlog_task", "promote_backlog", "update_backlog_item", "delete_backlog_item", "pause_workflow", "resume_workflow"];
|
|
18
18
|
export type BoardToolReadName = (typeof BOARD_TOOL_READ_NAMES)[number];
|
|
19
19
|
export type BoardToolWriteName = (typeof BOARD_TOOL_WRITE_NAMES)[number];
|
|
20
20
|
export type BoardToolName = BoardToolReadName | BoardToolWriteName;
|
|
@@ -23,8 +23,16 @@
|
|
|
23
23
|
* session exactly as the desktop's Pause button does, without moving the task,
|
|
24
24
|
* and keeps the conversation for a later `start-session` Resume. Gate it on
|
|
25
25
|
* `BoardTaskWire.pausable`.
|
|
26
|
+
*
|
|
27
|
+
* `command-terminal` starts or stops a Command Terminal: an AGENT CLI the
|
|
28
|
+
* desktop launches at a project's root, the same session the desktop's
|
|
29
|
+
* Ctrl+Shift+P terminal runs. It is not a shell verb. The phone names no
|
|
30
|
+
* command, branch, model or effort, and the desktop ends the session when its
|
|
31
|
+
* agent exits, so no bare shell is left behind for `interactive-terminal` to
|
|
32
|
+
* reach. Stop accepts only a Command Terminal's session. Gate the phone's
|
|
33
|
+
* Terminals button on `ReadBoardSnapshotResponsePayload.commandTerminalsOffered`.
|
|
26
34
|
*/
|
|
27
|
-
export declare const CAPABILITY_VERBS: readonly ["read-stream", "read-board", "read-diff", "send-user-message", "move-task", "answer-permission-prompt", "interactive-terminal", "board-tool-read", "board-tool-write", "register-push", "start-session", "pause-session"];
|
|
35
|
+
export declare const CAPABILITY_VERBS: readonly ["read-stream", "read-board", "read-diff", "send-user-message", "move-task", "answer-permission-prompt", "interactive-terminal", "board-tool-read", "board-tool-write", "register-push", "start-session", "pause-session", "command-terminal"];
|
|
28
36
|
export type CapabilityVerb = (typeof CAPABILITY_VERBS)[number];
|
|
29
37
|
export declare function isCapabilityVerb(value: string): value is CapabilityVerb;
|
|
30
38
|
/** Deny-by-default: a verb absent from the set is not authorized. */
|
|
@@ -1,10 +1,24 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Append only. `workflow-complete` (every task of a workflow reached Done) is
|
|
3
|
+
* the newest; a phone that predates it reads the envelope as an unknown
|
|
4
|
+
* category and shows the generic placeholder.
|
|
5
|
+
*/
|
|
6
|
+
export declare const PUSH_CATEGORIES: readonly ["input-required", "turn-complete", "session-failed", "plan-complete", "spawn-stalled", "workflow-complete"];
|
|
2
7
|
export type PushCategory = (typeof PUSH_CATEGORIES)[number];
|
|
3
8
|
export declare function isPushCategory(value: unknown): value is PushCategory;
|
|
4
9
|
/** Reject an opened envelope whose sentAt is older than this (stale replay). */
|
|
5
10
|
export declare const PUSH_ENVELOPE_MAX_AGE_MS: number;
|
|
6
11
|
/** Tolerated forward clock skew; anything claiming to be further in the future is rejected. */
|
|
7
12
|
export declare const PUSH_ENVELOPE_MAX_FUTURE_SKEW_MS: number;
|
|
13
|
+
/**
|
|
14
|
+
* What kind of session a notification is about, when it is not a task's
|
|
15
|
+
* agent (protocol 0.20.0). `command-terminal`: a Command Terminal, so the tap
|
|
16
|
+
* opens that terminal's screen by `sessionId` (its `taskId` names no board
|
|
17
|
+
* task) and `taskTitle` carries the terminal's name.
|
|
18
|
+
*/
|
|
19
|
+
export declare const PUSH_SESSION_KINDS: readonly ["command-terminal"];
|
|
20
|
+
export type PushSessionKind = (typeof PUSH_SESSION_KINDS)[number];
|
|
21
|
+
export declare function isPushSessionKind(value: unknown): value is PushSessionKind;
|
|
8
22
|
/**
|
|
9
23
|
* The real notification content, visible only on the sealing desktop and
|
|
10
24
|
* the opening device. Everything the OS-visible push payload carries
|
|
@@ -15,10 +29,13 @@ export interface PushEnvelopePlaintext {
|
|
|
15
29
|
projectId: string;
|
|
16
30
|
taskId: string;
|
|
17
31
|
sessionId: string;
|
|
32
|
+
/** The task's title, or for a `command-terminal` session the terminal's name. */
|
|
18
33
|
taskTitle: string;
|
|
19
34
|
detail: string;
|
|
20
35
|
/** Wall-clock ms at seal time; openPushEnvelope enforces the freshness window from it. */
|
|
21
36
|
sentAt: number;
|
|
37
|
+
/** Absent for a task's agent. See PUSH_SESSION_KINDS. */
|
|
38
|
+
sessionKind?: PushSessionKind;
|
|
22
39
|
}
|
|
23
40
|
/** Narrows a decrypted envelope's JSON to PushEnvelopePlaintext. Throws on any malformed field. */
|
|
24
41
|
export declare function parsePushEnvelopePlaintext(value: unknown): PushEnvelopePlaintext;
|
package/dist/events/event.d.ts
CHANGED
|
@@ -198,8 +198,20 @@ export interface TerminalResizeEvent {
|
|
|
198
198
|
/** The PTY's new grid; every terminal byte sent after this event is laid out for it. */
|
|
199
199
|
payload: TerminalDimensionsWire;
|
|
200
200
|
}
|
|
201
|
+
/**
|
|
202
|
+
* `command-terminals-changed` (protocol 0.20.0): one of the project's Command
|
|
203
|
+
* Terminals started, ended, or was named. `ids` holds the terminal's session id
|
|
204
|
+
* and the envelope carries no `taskId`, since a Command Terminal belongs to no
|
|
205
|
+
* task. The phone re-reads `commandTerminals` from the next snapshot. A change
|
|
206
|
+
* of activity does not fire it: the terminal's state and reason ride its own
|
|
207
|
+
* `read-stream` activity events, as a task agent's do, and the snapshot's
|
|
208
|
+
* `CommandTerminalWire.activity` covers the first paint.
|
|
209
|
+
*
|
|
210
|
+
* The union is closed, so a phone built before a kind existed drops that event
|
|
211
|
+
* (`isBridgeEvent` returns false) and keeps the rest of its feed.
|
|
212
|
+
*/
|
|
201
213
|
export interface BoardEventPayload {
|
|
202
|
-
change: 'task-created' | 'task-updated' | 'task-deleted' | 'swimlane-updated' | 'backlog-changed';
|
|
214
|
+
change: 'task-created' | 'task-updated' | 'task-deleted' | 'swimlane-updated' | 'backlog-changed' | 'command-terminals-changed';
|
|
203
215
|
ids: string[];
|
|
204
216
|
}
|
|
205
217
|
export interface BoardEvent {
|
|
@@ -208,9 +220,15 @@ export interface BoardEvent {
|
|
|
208
220
|
taskId?: string;
|
|
209
221
|
payload: BoardEventPayload;
|
|
210
222
|
}
|
|
223
|
+
/**
|
|
224
|
+
* "Re-read the diff." A task's diff names its `taskId`. A project-folder diff
|
|
225
|
+
* (a `read-diff` request with no `taskId`, protocol 0.20.0, for a Command
|
|
226
|
+
* Terminal's Changes tab) names its `projectId` instead. Exactly one is set.
|
|
227
|
+
*/
|
|
211
228
|
export interface DiffEvent {
|
|
212
229
|
kind: 'diff';
|
|
213
|
-
taskId
|
|
230
|
+
taskId?: string;
|
|
231
|
+
projectId?: string;
|
|
214
232
|
payload: null;
|
|
215
233
|
}
|
|
216
234
|
export type BridgeEvent = TranscriptEvent | ActivityEvent | TerminalEvent | TerminalResizeEvent | BoardEvent | DiffEvent;
|
|
@@ -465,6 +465,75 @@ export interface BoardTaskWire {
|
|
|
465
465
|
* key from every real wire response.
|
|
466
466
|
*/
|
|
467
467
|
pausable?: boolean | null;
|
|
468
|
+
/**
|
|
469
|
+
* The workflow the task belongs to (a set of linked tasks that runs through
|
|
470
|
+
* its boards by itself), or null for an ordinary task. Absent from desktops
|
|
471
|
+
* that predate workflows, which the parser reads as null, as it does a value
|
|
472
|
+
* it cannot read. Declared OPTIONAL for the reason `pr_merge_readiness` is.
|
|
473
|
+
*/
|
|
474
|
+
workflow?: BoardTaskWorkflowWire | null;
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* A board task's workflow, as its card draws it: the strip (name, color), what
|
|
478
|
+
* the task waits for, and whether a hand may move it. `lock_reason` is the
|
|
479
|
+
* desktop's own sentence, so a phone that refuses a move says what the desktop
|
|
480
|
+
* would; the desktop refuses a locked move on its own anyway.
|
|
481
|
+
*/
|
|
482
|
+
export interface BoardTaskWorkflowWire {
|
|
483
|
+
id: string;
|
|
484
|
+
title: string;
|
|
485
|
+
/** The workflow's home project, which may not be the board's. */
|
|
486
|
+
project_id: string;
|
|
487
|
+
/** `running`, `paused`, `draft` or `done`; a value a client does not know reads as running. */
|
|
488
|
+
state: string;
|
|
489
|
+
/** Which of six categorical colors (1 to 6) the desktop paints its icon in. */
|
|
490
|
+
color_slot: number;
|
|
491
|
+
/** The columns the task visits, by id, in board order. */
|
|
492
|
+
route: string[];
|
|
493
|
+
/** The tasks it waits for that are not done, named as the card's footer names them ("#413"). */
|
|
494
|
+
waiting_for: string[];
|
|
495
|
+
/**
|
|
496
|
+
* While the card is locked (its workflow runs and it is not waiting in a
|
|
497
|
+
* human gate), the desktop's sentence for a refused move; null otherwise,
|
|
498
|
+
* which is when the desktop draws no lock. An unlocked card still never
|
|
499
|
+
* moves into To Do, and while `gate_target_id` is set it moves only there.
|
|
500
|
+
*/
|
|
501
|
+
lock_reason: string | null;
|
|
502
|
+
/**
|
|
503
|
+
* While the workflow runs and the card waits in a column no agent judges
|
|
504
|
+
* (a human gate): the one column a hand may move it to, the next on its
|
|
505
|
+
* route. Moving it there is how the person reports the step done. Null otherwise.
|
|
506
|
+
*/
|
|
507
|
+
gate_target_id: string | null;
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* One live Command Terminal of a project (protocol 0.20.0): an agent the
|
|
511
|
+
* desktop runs at the project root with no task, started from the desktop's
|
|
512
|
+
* Ctrl+Shift+P layer or by a phone's `command-terminal` start. It is listed
|
|
513
|
+
* beside a project's tasks in a read-board snapshot (`commandTerminals`), and
|
|
514
|
+
* the Agents feed draws it with a "Command Terminal" pill.
|
|
515
|
+
*
|
|
516
|
+
* - `slot` is the terminal's durable number in its project, 1 to 4. It never
|
|
517
|
+
* renumbers while siblings start and stop.
|
|
518
|
+
* - `name` is what to show: the terminal's own name once it has one, else
|
|
519
|
+
* "Command Terminal N". `named` is true once it has its own name (the
|
|
520
|
+
* desktop derives one from the first prompt), which is when the phone's
|
|
521
|
+
* session header adds its pill.
|
|
522
|
+
* - `activity` is the raw state and reason, the same shape `read-stream`
|
|
523
|
+
* reports, so the phone formats the line ("Running Bash", "Awaiting
|
|
524
|
+
* permission") with the formatter it already uses for a task's agent. Both
|
|
525
|
+
* are null until the desktop's activity engine has classified the session.
|
|
526
|
+
*/
|
|
527
|
+
export interface CommandTerminalWire {
|
|
528
|
+
sessionId: string;
|
|
529
|
+
projectId: string;
|
|
530
|
+
slot: number;
|
|
531
|
+
name: string;
|
|
532
|
+
named: boolean;
|
|
533
|
+
activity: {
|
|
534
|
+
state: ActivityStateWire | null;
|
|
535
|
+
reason: ActivityReasonWire | null;
|
|
536
|
+
};
|
|
468
537
|
}
|
|
469
538
|
/** Phone-needed subset of the desktop's BacklogTask row. */
|
|
470
539
|
export interface BacklogItemWire {
|
|
@@ -535,6 +604,17 @@ export declare function parseSessionEventWire(payload: JsonValue): SessionEventW
|
|
|
535
604
|
export declare function parseBoardColumnWire(value: JsonValue): BoardColumnWire;
|
|
536
605
|
/** Narrows one board-task row. Throws on a malformed required field. */
|
|
537
606
|
export declare function parseBoardTaskWire(value: JsonValue): BoardTaskWire;
|
|
607
|
+
/**
|
|
608
|
+
* A board task's workflow, or null when absent or unreadable. Lenient on
|
|
609
|
+
* purpose: a malformed workflow costs the card its strip, never the board.
|
|
610
|
+
*/
|
|
611
|
+
export declare function parseBoardTaskWorkflowWire(value: JsonValue | undefined): BoardTaskWorkflowWire | null;
|
|
612
|
+
/**
|
|
613
|
+
* Narrows one Command Terminal row. Throws on a malformed required field. An
|
|
614
|
+
* unrecognized activity state or reason reads as null rather than throwing, so
|
|
615
|
+
* a reason kind a newer desktop adds costs the line, not the whole snapshot.
|
|
616
|
+
*/
|
|
617
|
+
export declare function parseCommandTerminalWire(value: JsonValue): CommandTerminalWire;
|
|
538
618
|
/** Narrows one backlog-item row. Throws on a malformed required field. */
|
|
539
619
|
export declare function parseBacklogItemWire(value: JsonValue): BacklogItemWire;
|
|
540
620
|
/** Narrows a read-diff file-list payload. Throws on a malformed required field. */
|
package/dist/index.cjs
CHANGED
|
@@ -20,10 +20,13 @@ var __toCommonJS = (mod2) => __copyProps(__defProp({}, "__esModule", { value: tr
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
AGENT_UNAVAILABLE_ERROR_CODE: () => AGENT_UNAVAILABLE_ERROR_CODE,
|
|
23
24
|
BOARD_COLUMN_ROLES: () => BOARD_COLUMN_ROLES,
|
|
24
25
|
BOARD_TOOL_READ_NAMES: () => BOARD_TOOL_READ_NAMES,
|
|
25
26
|
BOARD_TOOL_WRITE_NAMES: () => BOARD_TOOL_WRITE_NAMES,
|
|
26
27
|
CAPABILITY_VERBS: () => CAPABILITY_VERBS,
|
|
28
|
+
COMMAND_TERMINAL_LIMIT_ERROR_CODE: () => COMMAND_TERMINAL_LIMIT_ERROR_CODE,
|
|
29
|
+
COMMAND_TERMINAL_START_FAILED_ERROR_CODE: () => COMMAND_TERMINAL_START_FAILED_ERROR_CODE,
|
|
27
30
|
COMPRESSION_THRESHOLD: () => COMPRESSION_THRESHOLD,
|
|
28
31
|
CipherState: () => CipherState,
|
|
29
32
|
ED25519_KEY_LENGTH: () => ED25519_KEY_LENGTH,
|
|
@@ -34,14 +37,18 @@ __export(index_exports, {
|
|
|
34
37
|
MAX_DECODED_LENGTH: () => MAX_DECODED_LENGTH,
|
|
35
38
|
MAX_FRAME_LENGTH: () => MAX_FRAME_LENGTH,
|
|
36
39
|
MAX_RELAY_ADDRESS_LENGTH: () => MAX_RELAY_ADDRESS_LENGTH,
|
|
40
|
+
NOT_COMMAND_TERMINAL_ERROR_CODE: () => NOT_COMMAND_TERMINAL_ERROR_CODE,
|
|
37
41
|
PAIRING_URI_SCHEME: () => PAIRING_URI_SCHEME,
|
|
38
42
|
PROTOCOL_VERSION: () => PROTOCOL_VERSION,
|
|
39
43
|
PUSH_CATEGORIES: () => PUSH_CATEGORIES,
|
|
40
44
|
PUSH_ENVELOPE_MAX_AGE_MS: () => PUSH_ENVELOPE_MAX_AGE_MS,
|
|
41
45
|
PUSH_ENVELOPE_MAX_FUTURE_SKEW_MS: () => PUSH_ENVELOPE_MAX_FUTURE_SKEW_MS,
|
|
46
|
+
PUSH_SESSION_KINDS: () => PUSH_SESSION_KINDS,
|
|
42
47
|
RESPONSE_TOO_LARGE_ERROR_CODE: () => RESPONSE_TOO_LARGE_ERROR_CODE,
|
|
43
48
|
SecretstreamState: () => SecretstreamState,
|
|
44
49
|
SessionFrameKind: () => SessionFrameKind,
|
|
50
|
+
UNKNOWN_PROJECT_ERROR_CODE: () => UNKNOWN_PROJECT_ERROR_CODE,
|
|
51
|
+
UNKNOWN_SESSION_ERROR_CODE: () => UNKNOWN_SESSION_ERROR_CODE,
|
|
45
52
|
UNSUPPORTED_VERB_ERROR_CODE: () => UNSUPPORTED_VERB_ERROR_CODE,
|
|
46
53
|
UnsupportedVerbError: () => UnsupportedVerbError,
|
|
47
54
|
X25519_KEY_LENGTH: () => X25519_KEY_LENGTH,
|
|
@@ -77,6 +84,7 @@ __export(index_exports, {
|
|
|
77
84
|
isDoneRole: () => isDoneRole,
|
|
78
85
|
isJsonValue: () => isJsonValue,
|
|
79
86
|
isPushCategory: () => isPushCategory,
|
|
87
|
+
isPushSessionKind: () => isPushSessionKind,
|
|
80
88
|
isReadStreamSessionStatusWire: () => isReadStreamSessionStatusWire,
|
|
81
89
|
isRecord: () => isRecord,
|
|
82
90
|
isRosterEntryExpired: () => isRosterEntryExpired,
|
|
@@ -89,7 +97,10 @@ __export(index_exports, {
|
|
|
89
97
|
parseBacklogItemWire: () => parseBacklogItemWire,
|
|
90
98
|
parseBoardColumnWire: () => parseBoardColumnWire,
|
|
91
99
|
parseBoardTaskWire: () => parseBoardTaskWire,
|
|
100
|
+
parseBoardTaskWorkflowWire: () => parseBoardTaskWorkflowWire,
|
|
92
101
|
parseCapabilityRequestPayload: () => parseCapabilityRequestPayload,
|
|
102
|
+
parseCommandTerminalStartResponsePayload: () => parseCommandTerminalStartResponsePayload,
|
|
103
|
+
parseCommandTerminalWire: () => parseCommandTerminalWire,
|
|
93
104
|
parseDiffFileContentWire: () => parseDiffFileContentWire,
|
|
94
105
|
parseDiffFileListWire: () => parseDiffFileListWire,
|
|
95
106
|
parsePauseSessionResponsePayload: () => parsePauseSessionResponsePayload,
|
|
@@ -4975,7 +4986,8 @@ var CAPABILITY_VERBS = [
|
|
|
4975
4986
|
"board-tool-write",
|
|
4976
4987
|
"register-push",
|
|
4977
4988
|
"start-session",
|
|
4978
|
-
"pause-session"
|
|
4989
|
+
"pause-session",
|
|
4990
|
+
"command-terminal"
|
|
4979
4991
|
];
|
|
4980
4992
|
function isCapabilityVerb(value) {
|
|
4981
4993
|
return CAPABILITY_VERBS.includes(value);
|
|
@@ -5013,6 +5025,12 @@ var JSON_OPEN_BRACE = 123;
|
|
|
5013
5025
|
var DEFLATE_HEADER_LENGTH = 5;
|
|
5014
5026
|
var UNSUPPORTED_VERB_ERROR_CODE = "unsupported-verb";
|
|
5015
5027
|
var RESPONSE_TOO_LARGE_ERROR_CODE = "response-too-large";
|
|
5028
|
+
var UNKNOWN_PROJECT_ERROR_CODE = "unknown-project";
|
|
5029
|
+
var UNKNOWN_SESSION_ERROR_CODE = "unknown-session";
|
|
5030
|
+
var COMMAND_TERMINAL_LIMIT_ERROR_CODE = "command-terminal-limit";
|
|
5031
|
+
var NOT_COMMAND_TERMINAL_ERROR_CODE = "not-command-terminal";
|
|
5032
|
+
var AGENT_UNAVAILABLE_ERROR_CODE = "agent-unavailable";
|
|
5033
|
+
var COMMAND_TERMINAL_START_FAILED_ERROR_CODE = "command-terminal-start-failed";
|
|
5016
5034
|
var UNSUPPORTED_VERB_ERROR_NAME = "UnsupportedVerbError";
|
|
5017
5035
|
var UnsupportedVerbError = class extends Error {
|
|
5018
5036
|
requestId;
|
|
@@ -5100,7 +5118,11 @@ function validateEvent(event) {
|
|
|
5100
5118
|
return event;
|
|
5101
5119
|
}
|
|
5102
5120
|
case "diff": {
|
|
5103
|
-
if (typeof event.taskId !== "string") throw new Error('"diff" event
|
|
5121
|
+
if (event.taskId !== void 0 && typeof event.taskId !== "string") throw new Error('"diff" event has a non-string "taskId"');
|
|
5122
|
+
if (event.projectId !== void 0 && typeof event.projectId !== "string") throw new Error('"diff" event has a non-string "projectId"');
|
|
5123
|
+
if (event.taskId === void 0 === (event.projectId === void 0)) {
|
|
5124
|
+
throw new Error('"diff" event must carry exactly one of "taskId" and "projectId"');
|
|
5125
|
+
}
|
|
5104
5126
|
return event;
|
|
5105
5127
|
}
|
|
5106
5128
|
default:
|
|
@@ -5207,12 +5229,16 @@ function base64UrlDecode(encoded) {
|
|
|
5207
5229
|
}
|
|
5208
5230
|
|
|
5209
5231
|
// src/crypto/push-envelope.ts
|
|
5210
|
-
var PUSH_CATEGORIES = ["input-required", "turn-complete", "session-failed", "plan-complete", "spawn-stalled"];
|
|
5232
|
+
var PUSH_CATEGORIES = ["input-required", "turn-complete", "session-failed", "plan-complete", "spawn-stalled", "workflow-complete"];
|
|
5211
5233
|
function isPushCategory(value) {
|
|
5212
5234
|
return typeof value === "string" && PUSH_CATEGORIES.includes(value);
|
|
5213
5235
|
}
|
|
5214
5236
|
var PUSH_ENVELOPE_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
5215
5237
|
var PUSH_ENVELOPE_MAX_FUTURE_SKEW_MS = 5 * 60 * 1e3;
|
|
5238
|
+
var PUSH_SESSION_KINDS = ["command-terminal"];
|
|
5239
|
+
function isPushSessionKind(value) {
|
|
5240
|
+
return typeof value === "string" && PUSH_SESSION_KINDS.includes(value);
|
|
5241
|
+
}
|
|
5216
5242
|
function requireEnvelopeString(record, field) {
|
|
5217
5243
|
const value = record[field];
|
|
5218
5244
|
if (typeof value !== "string") throw new Error(`push envelope plaintext is missing a string "${field}"`);
|
|
@@ -5231,7 +5257,10 @@ function parsePushEnvelopePlaintext(value) {
|
|
|
5231
5257
|
sessionId: requireEnvelopeString(value, "sessionId"),
|
|
5232
5258
|
taskTitle: requireEnvelopeString(value, "taskTitle"),
|
|
5233
5259
|
detail: requireEnvelopeString(value, "detail"),
|
|
5234
|
-
sentAt: value.sentAt
|
|
5260
|
+
sentAt: value.sentAt,
|
|
5261
|
+
// An unknown kind (from a newer desktop) is dropped, not rejected, so the
|
|
5262
|
+
// notification still opens; the tap then routes as a task's would.
|
|
5263
|
+
...isPushSessionKind(value.sessionKind) ? { sessionKind: value.sessionKind } : {}
|
|
5235
5264
|
};
|
|
5236
5265
|
}
|
|
5237
5266
|
function sealPushEnvelope(pushKey, recipientStaticPublicKey, plaintext) {
|
|
@@ -5481,7 +5510,39 @@ function parseBoardTaskWire(value) {
|
|
|
5481
5510
|
spawn_progress: nullableString(value, "spawn_progress"),
|
|
5482
5511
|
resumable: nullableBoolean(value, "resumable"),
|
|
5483
5512
|
paused: nullableBoolean(value, "paused"),
|
|
5484
|
-
pausable: nullableBoolean(value, "pausable")
|
|
5513
|
+
pausable: nullableBoolean(value, "pausable"),
|
|
5514
|
+
workflow: parseBoardTaskWorkflowWire(value.workflow)
|
|
5515
|
+
};
|
|
5516
|
+
}
|
|
5517
|
+
function parseBoardTaskWorkflowWire(value) {
|
|
5518
|
+
if (value === void 0 || !isRecord(value)) return null;
|
|
5519
|
+
const strings = (field) => Array.isArray(field) ? field.filter((entry) => typeof entry === "string") : [];
|
|
5520
|
+
if (typeof value.id !== "string" || typeof value.title !== "string" || typeof value.project_id !== "string") return null;
|
|
5521
|
+
return {
|
|
5522
|
+
id: value.id,
|
|
5523
|
+
title: value.title,
|
|
5524
|
+
project_id: value.project_id,
|
|
5525
|
+
state: typeof value.state === "string" ? value.state : "running",
|
|
5526
|
+
color_slot: typeof value.color_slot === "number" ? value.color_slot : 1,
|
|
5527
|
+
route: strings(value.route),
|
|
5528
|
+
waiting_for: strings(value.waiting_for),
|
|
5529
|
+
lock_reason: typeof value.lock_reason === "string" ? value.lock_reason : null,
|
|
5530
|
+
gate_target_id: typeof value.gate_target_id === "string" ? value.gate_target_id : null
|
|
5531
|
+
};
|
|
5532
|
+
}
|
|
5533
|
+
function parseCommandTerminalWire(value) {
|
|
5534
|
+
if (!isRecord(value)) throw new Error("command terminal must be an object");
|
|
5535
|
+
const activity = isRecord(value.activity) ? value.activity : {};
|
|
5536
|
+
return {
|
|
5537
|
+
sessionId: requireString(value, "sessionId", "command terminal"),
|
|
5538
|
+
projectId: requireString(value, "projectId", "command terminal"),
|
|
5539
|
+
slot: requireNumber(value, "slot", "command terminal"),
|
|
5540
|
+
name: requireString(value, "name", "command terminal"),
|
|
5541
|
+
named: requireBoolean(value, "named", "command terminal"),
|
|
5542
|
+
activity: {
|
|
5543
|
+
state: isActivityStateWire(activity.state) ? activity.state : null,
|
|
5544
|
+
reason: isActivityReasonWire(activity.reason) ? activity.reason : null
|
|
5545
|
+
}
|
|
5485
5546
|
};
|
|
5486
5547
|
}
|
|
5487
5548
|
function parseBacklogItemWire(value) {
|
|
@@ -5676,6 +5737,12 @@ function parseReadBoardResponsePayload(payload) {
|
|
|
5676
5737
|
if (payload.view !== void 0 && payload.view !== "full" && payload.view !== "sessions") {
|
|
5677
5738
|
throw new Error('read-board response has an invalid "view"');
|
|
5678
5739
|
}
|
|
5740
|
+
if (payload.commandTerminals !== void 0 && !Array.isArray(payload.commandTerminals)) {
|
|
5741
|
+
throw new Error('read-board response has a non-array "commandTerminals"');
|
|
5742
|
+
}
|
|
5743
|
+
if (payload.commandTerminalsOffered !== void 0 && typeof payload.commandTerminalsOffered !== "boolean") {
|
|
5744
|
+
throw new Error('read-board response has a non-boolean "commandTerminalsOffered"');
|
|
5745
|
+
}
|
|
5679
5746
|
return {
|
|
5680
5747
|
projectId: payload.projectId,
|
|
5681
5748
|
columns: payload.columns.map((column) => parseBoardColumnWire(column)),
|
|
@@ -5684,7 +5751,9 @@ function parseReadBoardResponsePayload(payload) {
|
|
|
5684
5751
|
...payload.projectColor !== void 0 ? { projectColor: parseAccentColor(payload.projectColor, "read-board snapshot") } : {},
|
|
5685
5752
|
...payload.showTicketNumbers !== void 0 ? { showTicketNumbers: payload.showTicketNumbers } : {},
|
|
5686
5753
|
...payload.view !== void 0 ? { view: payload.view } : {},
|
|
5687
|
-
...payload.taskCountsByColumnId !== void 0 ? { taskCountsByColumnId: parseTaskCountsByColumnId(payload.taskCountsByColumnId) } : {}
|
|
5754
|
+
...payload.taskCountsByColumnId !== void 0 ? { taskCountsByColumnId: parseTaskCountsByColumnId(payload.taskCountsByColumnId) } : {},
|
|
5755
|
+
...payload.commandTerminals !== void 0 ? { commandTerminals: payload.commandTerminals.map((terminal) => parseCommandTerminalWire(terminal)) } : {},
|
|
5756
|
+
...payload.commandTerminalsOffered !== void 0 ? { commandTerminalsOffered: payload.commandTerminalsOffered } : {}
|
|
5688
5757
|
};
|
|
5689
5758
|
}
|
|
5690
5759
|
function parseTaskCountsByColumnId(value) {
|
|
@@ -5738,7 +5807,7 @@ function parseReadDiffResponsePayload(payload) {
|
|
|
5738
5807
|
}
|
|
5739
5808
|
function parseReadDiffRequestPayload(payload) {
|
|
5740
5809
|
if (!isRecord(payload)) throw new Error("read-diff payload must be an object");
|
|
5741
|
-
if (typeof payload.taskId !== "string") throw new Error('read-diff payload
|
|
5810
|
+
if (payload.taskId !== void 0 && typeof payload.taskId !== "string") throw new Error('read-diff payload has a non-string "taskId"');
|
|
5742
5811
|
if (typeof payload.projectId !== "string") throw new Error('read-diff payload missing "projectId"');
|
|
5743
5812
|
if (payload.filePath !== void 0 && typeof payload.filePath !== "string") {
|
|
5744
5813
|
throw new Error('read-diff payload has a non-string "filePath"');
|
|
@@ -5750,7 +5819,7 @@ function parseReadDiffRequestPayload(payload) {
|
|
|
5750
5819
|
throw new Error('read-diff payload has an invalid "action"');
|
|
5751
5820
|
}
|
|
5752
5821
|
return {
|
|
5753
|
-
taskId: payload.taskId,
|
|
5822
|
+
...payload.taskId !== void 0 ? { taskId: payload.taskId } : {},
|
|
5754
5823
|
projectId: payload.projectId,
|
|
5755
5824
|
filePath: payload.filePath,
|
|
5756
5825
|
scope: payload.scope,
|
|
@@ -5802,6 +5871,28 @@ function parsePauseSessionRequestPayload(payload) {
|
|
|
5802
5871
|
projectId: payload.projectId
|
|
5803
5872
|
};
|
|
5804
5873
|
}
|
|
5874
|
+
function parseCommandTerminalRequestPayload(payload) {
|
|
5875
|
+
if (!isRecord(payload)) throw new Error("command-terminal payload must be an object");
|
|
5876
|
+
if (payload.action === "start") {
|
|
5877
|
+
if (typeof payload.projectId !== "string") throw new Error('command-terminal start payload missing "projectId"');
|
|
5878
|
+
return { action: "start", projectId: payload.projectId };
|
|
5879
|
+
}
|
|
5880
|
+
if (payload.action === "stop") {
|
|
5881
|
+
if (typeof payload.sessionId !== "string") throw new Error('command-terminal stop payload missing "sessionId"');
|
|
5882
|
+
return { action: "stop", sessionId: payload.sessionId };
|
|
5883
|
+
}
|
|
5884
|
+
throw new Error('command-terminal payload has an invalid "action"');
|
|
5885
|
+
}
|
|
5886
|
+
function parseCommandTerminalStartResponsePayload(payload) {
|
|
5887
|
+
if (!isRecord(payload)) throw new Error("command-terminal start response must be an object");
|
|
5888
|
+
if (payload.ok !== true) throw new Error('command-terminal start response missing "ok"');
|
|
5889
|
+
if (typeof payload.sessionId !== "string") throw new Error('command-terminal start response missing "sessionId"');
|
|
5890
|
+
if (typeof payload.slot !== "number" || !Number.isInteger(payload.slot) || payload.slot < 1) {
|
|
5891
|
+
throw new Error('command-terminal start response has an invalid "slot"');
|
|
5892
|
+
}
|
|
5893
|
+
if (typeof payload.name !== "string") throw new Error('command-terminal start response missing "name"');
|
|
5894
|
+
return { ok: true, sessionId: payload.sessionId, slot: payload.slot, name: payload.name };
|
|
5895
|
+
}
|
|
5805
5896
|
function parsePauseSessionResponsePayload(payload) {
|
|
5806
5897
|
if (!isRecord(payload)) throw new Error("pause-session response must be an object");
|
|
5807
5898
|
if (typeof payload.ok !== "boolean") throw new Error('pause-session response missing "ok"');
|
|
@@ -5906,6 +5997,8 @@ function parseCapabilityRequestPayload(verb, payload) {
|
|
|
5906
5997
|
return parseStartSessionRequestPayload(payload);
|
|
5907
5998
|
case "pause-session":
|
|
5908
5999
|
return parsePauseSessionRequestPayload(payload);
|
|
6000
|
+
case "command-terminal":
|
|
6001
|
+
return parseCommandTerminalRequestPayload(payload);
|
|
5909
6002
|
default: {
|
|
5910
6003
|
const exhaustiveCheck = verb;
|
|
5911
6004
|
throw new Error(`Unknown capability verb: ${String(exhaustiveCheck)}`);
|
|
@@ -6111,7 +6204,10 @@ var BOARD_TOOL_READ_NAMES = [
|
|
|
6111
6204
|
"get_transcript",
|
|
6112
6205
|
"get_session_files",
|
|
6113
6206
|
"get_session_events",
|
|
6114
|
-
"get_activity_intervals"
|
|
6207
|
+
"get_activity_intervals",
|
|
6208
|
+
// Workflows: the project's workflows and one workflow's tasks, routes and links.
|
|
6209
|
+
"list_workflows",
|
|
6210
|
+
"get_workflow"
|
|
6115
6211
|
];
|
|
6116
6212
|
var BOARD_TOOL_WRITE_NAMES = [
|
|
6117
6213
|
"create_task",
|
|
@@ -6126,7 +6222,10 @@ var BOARD_TOOL_WRITE_NAMES = [
|
|
|
6126
6222
|
"create_backlog_task",
|
|
6127
6223
|
"promote_backlog",
|
|
6128
6224
|
"update_backlog_item",
|
|
6129
|
-
"delete_backlog_item"
|
|
6225
|
+
"delete_backlog_item",
|
|
6226
|
+
// Workflows: stop every task of a running workflow at once, and start them again.
|
|
6227
|
+
"pause_workflow",
|
|
6228
|
+
"resume_workflow"
|
|
6130
6229
|
];
|
|
6131
6230
|
function isBoardToolReadName(value) {
|
|
6132
6231
|
return BOARD_TOOL_READ_NAMES.includes(value);
|
|
@@ -6136,7 +6235,14 @@ function isBoardToolWriteName(value) {
|
|
|
6136
6235
|
}
|
|
6137
6236
|
|
|
6138
6237
|
// src/events/event.ts
|
|
6139
|
-
var BOARD_CHANGES = [
|
|
6238
|
+
var BOARD_CHANGES = [
|
|
6239
|
+
"task-created",
|
|
6240
|
+
"task-updated",
|
|
6241
|
+
"task-deleted",
|
|
6242
|
+
"swimlane-updated",
|
|
6243
|
+
"backlog-changed",
|
|
6244
|
+
"command-terminals-changed"
|
|
6245
|
+
];
|
|
6140
6246
|
function parseActivityEventPayload(payload) {
|
|
6141
6247
|
if (!isRecord(payload)) throw new Error("activity payload must be an object");
|
|
6142
6248
|
switch (payload.type) {
|
|
@@ -6231,18 +6337,27 @@ function isBridgeEvent(value) {
|
|
|
6231
6337
|
if (typeof change !== "string" || !BOARD_CHANGES.includes(change)) return false;
|
|
6232
6338
|
return Array.isArray(value.payload.ids) && value.payload.ids.every((id) => typeof id === "string");
|
|
6233
6339
|
}
|
|
6234
|
-
case "diff":
|
|
6235
|
-
|
|
6340
|
+
case "diff": {
|
|
6341
|
+
if (value.payload !== null) return false;
|
|
6342
|
+
const hasTaskId = typeof value.taskId === "string";
|
|
6343
|
+
const hasProjectId = typeof value.projectId === "string";
|
|
6344
|
+
if (value.taskId !== void 0 && !hasTaskId) return false;
|
|
6345
|
+
if (value.projectId !== void 0 && !hasProjectId) return false;
|
|
6346
|
+
return hasTaskId !== hasProjectId;
|
|
6347
|
+
}
|
|
6236
6348
|
default:
|
|
6237
6349
|
return false;
|
|
6238
6350
|
}
|
|
6239
6351
|
}
|
|
6240
6352
|
// Annotate the CommonJS export names for ESM import in node:
|
|
6241
6353
|
0 && (module.exports = {
|
|
6354
|
+
AGENT_UNAVAILABLE_ERROR_CODE,
|
|
6242
6355
|
BOARD_COLUMN_ROLES,
|
|
6243
6356
|
BOARD_TOOL_READ_NAMES,
|
|
6244
6357
|
BOARD_TOOL_WRITE_NAMES,
|
|
6245
6358
|
CAPABILITY_VERBS,
|
|
6359
|
+
COMMAND_TERMINAL_LIMIT_ERROR_CODE,
|
|
6360
|
+
COMMAND_TERMINAL_START_FAILED_ERROR_CODE,
|
|
6246
6361
|
COMPRESSION_THRESHOLD,
|
|
6247
6362
|
CipherState,
|
|
6248
6363
|
ED25519_KEY_LENGTH,
|
|
@@ -6253,14 +6368,18 @@ function isBridgeEvent(value) {
|
|
|
6253
6368
|
MAX_DECODED_LENGTH,
|
|
6254
6369
|
MAX_FRAME_LENGTH,
|
|
6255
6370
|
MAX_RELAY_ADDRESS_LENGTH,
|
|
6371
|
+
NOT_COMMAND_TERMINAL_ERROR_CODE,
|
|
6256
6372
|
PAIRING_URI_SCHEME,
|
|
6257
6373
|
PROTOCOL_VERSION,
|
|
6258
6374
|
PUSH_CATEGORIES,
|
|
6259
6375
|
PUSH_ENVELOPE_MAX_AGE_MS,
|
|
6260
6376
|
PUSH_ENVELOPE_MAX_FUTURE_SKEW_MS,
|
|
6377
|
+
PUSH_SESSION_KINDS,
|
|
6261
6378
|
RESPONSE_TOO_LARGE_ERROR_CODE,
|
|
6262
6379
|
SecretstreamState,
|
|
6263
6380
|
SessionFrameKind,
|
|
6381
|
+
UNKNOWN_PROJECT_ERROR_CODE,
|
|
6382
|
+
UNKNOWN_SESSION_ERROR_CODE,
|
|
6264
6383
|
UNSUPPORTED_VERB_ERROR_CODE,
|
|
6265
6384
|
UnsupportedVerbError,
|
|
6266
6385
|
X25519_KEY_LENGTH,
|
|
@@ -6296,6 +6415,7 @@ function isBridgeEvent(value) {
|
|
|
6296
6415
|
isDoneRole,
|
|
6297
6416
|
isJsonValue,
|
|
6298
6417
|
isPushCategory,
|
|
6418
|
+
isPushSessionKind,
|
|
6299
6419
|
isReadStreamSessionStatusWire,
|
|
6300
6420
|
isRecord,
|
|
6301
6421
|
isRosterEntryExpired,
|
|
@@ -6308,7 +6428,10 @@ function isBridgeEvent(value) {
|
|
|
6308
6428
|
parseBacklogItemWire,
|
|
6309
6429
|
parseBoardColumnWire,
|
|
6310
6430
|
parseBoardTaskWire,
|
|
6431
|
+
parseBoardTaskWorkflowWire,
|
|
6311
6432
|
parseCapabilityRequestPayload,
|
|
6433
|
+
parseCommandTerminalStartResponsePayload,
|
|
6434
|
+
parseCommandTerminalWire,
|
|
6312
6435
|
parseDiffFileContentWire,
|
|
6313
6436
|
parseDiffFileListWire,
|
|
6314
6437
|
parsePauseSessionResponsePayload,
|
package/dist/index.d.ts
CHANGED
|
@@ -9,11 +9,11 @@ export { SecretstreamState, deriveSecretstreamPair, FrameTag, type SecretstreamD
|
|
|
9
9
|
export { deriveShortAuthenticationString, type ShortAuthenticationString } from './crypto/sas';
|
|
10
10
|
export { deriveSessionSlotId, derivePairingSlotId } from './crypto/slot';
|
|
11
11
|
export type { JsonValue, BridgeMessage, HeartbeatMessage, CapabilityRequestMessage, CapabilityResponseMessage, CapabilityErrorCode, EventMessage } from './wire/messages';
|
|
12
|
-
export { encodeMessage, encodeMessageFailure, decodeMessage, UnsupportedVerbError, isUnsupportedVerbError, UNSUPPORTED_VERB_ERROR_CODE, RESPONSE_TOO_LARGE_ERROR_CODE, MAX_FRAME_LENGTH, MAX_DECODED_LENGTH, COMPRESSION_THRESHOLD, } from './wire/framing';
|
|
12
|
+
export { encodeMessage, encodeMessageFailure, decodeMessage, UnsupportedVerbError, isUnsupportedVerbError, UNSUPPORTED_VERB_ERROR_CODE, RESPONSE_TOO_LARGE_ERROR_CODE, UNKNOWN_PROJECT_ERROR_CODE, UNKNOWN_SESSION_ERROR_CODE, COMMAND_TERMINAL_LIMIT_ERROR_CODE, NOT_COMMAND_TERMINAL_ERROR_CODE, AGENT_UNAVAILABLE_ERROR_CODE, COMMAND_TERMINAL_START_FAILED_ERROR_CODE, MAX_FRAME_LENGTH, MAX_DECODED_LENGTH, COMPRESSION_THRESHOLD, } from './wire/framing';
|
|
13
13
|
export { isJsonValue, isRecord } from './wire/json-value';
|
|
14
14
|
export { SessionFrameKind, wrapSessionFrame, unwrapSessionFrame } from './wire/session-frame';
|
|
15
|
-
export { parseCapabilityRequestPayload, parseReadStreamResponsePayload, parseReadBoardResponsePayload, parseReadDiffResponsePayload, parseTranscriptWindowResponsePayload, parseRegisterPushRequestPayload, parseStartSessionResponsePayload, parsePauseSessionResponsePayload, isReadStreamSessionStatusWire, type CapabilityRequestPayloadMap, type CapabilityResponsePayloadMap, type ReadStreamRequestPayload, type ReadStreamResponsePayload, type ReadStreamSessionStatusWire, type TranscriptWindowResponsePayload, type ReadBoardRequestPayload, type ReadBoardView, type ReadBoardProjectSummary, type ReadBoardProjectGroup, type ReadBoardProjectListResponsePayload, type ReadBoardSnapshotResponsePayload, type ReadBoardArchivedResponsePayload, type ReadBoardResponsePayload, type ReadDiffScope, type ReadDiffRequestPayload, type ReadDiffResponsePayload, type SendUserMessageRequestPayload, type SendUserMessageResponsePayload, type MoveTaskRequestPayload, type MoveTaskResponsePayload, type AnswerPermissionPromptRequestPayload, type AnswerPermissionPromptResponsePayload, type InteractiveTerminalRequestPayload, type InteractiveTerminalResponsePayload, type BoardToolRequestPayload, type BoardToolResponsePayload, type RegisterPushRequestPayload, type RegisterPushResponsePayload, type StartSessionRequestPayload, type StartSessionResponsePayload, type StartSessionOutcome, type PauseSessionRequestPayload, type PauseSessionResponsePayload, } from './wire/payloads';
|
|
16
|
-
export { PUSH_CATEGORIES, isPushCategory, parsePushEnvelopePlaintext, sealPushEnvelope, openPushEnvelope, PUSH_ENVELOPE_MAX_AGE_MS, PUSH_ENVELOPE_MAX_FUTURE_SKEW_MS, type PushCategory, type PushEnvelopePlaintext, } from './crypto/push-envelope';
|
|
15
|
+
export { parseCapabilityRequestPayload, parseReadStreamResponsePayload, parseReadBoardResponsePayload, parseReadDiffResponsePayload, parseTranscriptWindowResponsePayload, parseRegisterPushRequestPayload, parseStartSessionResponsePayload, parsePauseSessionResponsePayload, parseCommandTerminalStartResponsePayload, isReadStreamSessionStatusWire, type CapabilityRequestPayloadMap, type CapabilityResponsePayloadMap, type ReadStreamRequestPayload, type ReadStreamResponsePayload, type ReadStreamSessionStatusWire, type TranscriptWindowResponsePayload, type ReadBoardRequestPayload, type ReadBoardView, type ReadBoardProjectSummary, type ReadBoardProjectGroup, type ReadBoardProjectListResponsePayload, type ReadBoardSnapshotResponsePayload, type ReadBoardArchivedResponsePayload, type ReadBoardResponsePayload, type ReadDiffScope, type ReadDiffRequestPayload, type ReadDiffResponsePayload, type SendUserMessageRequestPayload, type SendUserMessageResponsePayload, type MoveTaskRequestPayload, type MoveTaskResponsePayload, type AnswerPermissionPromptRequestPayload, type AnswerPermissionPromptResponsePayload, type InteractiveTerminalRequestPayload, type InteractiveTerminalResponsePayload, type BoardToolRequestPayload, type BoardToolResponsePayload, type RegisterPushRequestPayload, type RegisterPushResponsePayload, type StartSessionRequestPayload, type StartSessionResponsePayload, type StartSessionOutcome, type PauseSessionRequestPayload, type PauseSessionResponsePayload, type CommandTerminalRequestPayload, type CommandTerminalStartResponsePayload, type CommandTerminalStopResponsePayload, type CommandTerminalResponsePayload, } from './wire/payloads';
|
|
16
|
+
export { PUSH_CATEGORIES, isPushCategory, PUSH_SESSION_KINDS, isPushSessionKind, parsePushEnvelopePlaintext, sealPushEnvelope, openPushEnvelope, PUSH_ENVELOPE_MAX_AGE_MS, PUSH_ENVELOPE_MAX_FUTURE_SKEW_MS, type PushCategory, type PushSessionKind, type PushEnvelopePlaintext, } from './crypto/push-envelope';
|
|
17
17
|
export { PAIRING_URI_SCHEME, encodePairingQrPayload, decodePairingQrPayload, type PairingQrPayload, } from './pairing/qr';
|
|
18
18
|
export { sealPairingConfirm, openPairingConfirm } from './pairing/confirm';
|
|
19
19
|
export { MAX_RELAY_ADDRESS_LENGTH, isSecureRelayAddress } from './pairing/relay-address';
|
|
@@ -22,5 +22,5 @@ export { formatKeyFingerprint } from './roster/fingerprint';
|
|
|
22
22
|
export { CAPABILITY_VERBS, isCapabilityVerb, capabilitySetFromArray, capabilitySetToArray, type CapabilityVerb, type CapabilitySet, } from './capabilities/verbs';
|
|
23
23
|
export { BOARD_TOOL_READ_NAMES, BOARD_TOOL_WRITE_NAMES, isBoardToolReadName, isBoardToolWriteName, type BoardToolReadName, type BoardToolWriteName, type BoardToolName, } from './capabilities/board-tools';
|
|
24
24
|
export { isBridgeEvent, parseActivityEventPayload, type BridgeEvent, type TranscriptEvent, type ActivityEvent, type ActivityEventPayload, type TerminalEvent, type TerminalResizeEvent, type BoardEvent, type BoardEventPayload, type DiffEvent, } from './events/event';
|
|
25
|
-
export { parseTranscriptEntriesWire, parseTranscriptEventPayload, type TranscriptEventPayload, type TranscriptUpsertWire, isActivityStateWire, isActivityReasonWire, parseSessionUsageWire, parseSessionSummaryWire, parseSessionEventWire, parseTerminalDimensionsWire, parseBoardColumnWire, parseBoardTaskWire, parseBacklogItemWire, parseDiffFileListWire, parseDiffFileContentWire, isTodoRole, isDoneRole, BOARD_COLUMN_ROLES, type TranscriptBlockWire, type TranscriptEntryWire, type TranscriptTurnUsageWire, type TranscriptSystemSubtypeWire, type ActivityStateWire, type ActivityReasonWire, type SessionUsageWire, type SessionSummaryWire, type SessionEventWire, type TerminalDimensionsWire, type BoardColumnWire, type BoardColumnRoleWire, type BoardTaskWire, type BacklogItemWire, type DiffFileStatusWire, type DiffFileWire, type DiffFileListWire, type DiffFileContentWire, } from './events/payloads';
|
|
25
|
+
export { parseTranscriptEntriesWire, parseTranscriptEventPayload, type TranscriptEventPayload, type TranscriptUpsertWire, isActivityStateWire, isActivityReasonWire, parseSessionUsageWire, parseSessionSummaryWire, parseSessionEventWire, parseTerminalDimensionsWire, parseBoardColumnWire, parseBoardTaskWire, parseCommandTerminalWire, parseBoardTaskWorkflowWire, parseBacklogItemWire, parseDiffFileListWire, parseDiffFileContentWire, isTodoRole, isDoneRole, BOARD_COLUMN_ROLES, type TranscriptBlockWire, type TranscriptEntryWire, type TranscriptTurnUsageWire, type TranscriptSystemSubtypeWire, type ActivityStateWire, type ActivityReasonWire, type SessionUsageWire, type SessionSummaryWire, type SessionEventWire, type TerminalDimensionsWire, type BoardColumnWire, type BoardColumnRoleWire, type BoardTaskWire, type CommandTerminalWire, type BoardTaskWorkflowWire, type BacklogItemWire, type DiffFileStatusWire, type DiffFileWire, type DiffFileListWire, type DiffFileContentWire, } from './events/payloads';
|
|
26
26
|
export type { Transport, TransportState, Unsubscribe } from './transport/transport';
|
package/dist/index.mjs
CHANGED
|
@@ -4846,7 +4846,8 @@ var CAPABILITY_VERBS = [
|
|
|
4846
4846
|
"board-tool-write",
|
|
4847
4847
|
"register-push",
|
|
4848
4848
|
"start-session",
|
|
4849
|
-
"pause-session"
|
|
4849
|
+
"pause-session",
|
|
4850
|
+
"command-terminal"
|
|
4850
4851
|
];
|
|
4851
4852
|
function isCapabilityVerb(value) {
|
|
4852
4853
|
return CAPABILITY_VERBS.includes(value);
|
|
@@ -4884,6 +4885,12 @@ var JSON_OPEN_BRACE = 123;
|
|
|
4884
4885
|
var DEFLATE_HEADER_LENGTH = 5;
|
|
4885
4886
|
var UNSUPPORTED_VERB_ERROR_CODE = "unsupported-verb";
|
|
4886
4887
|
var RESPONSE_TOO_LARGE_ERROR_CODE = "response-too-large";
|
|
4888
|
+
var UNKNOWN_PROJECT_ERROR_CODE = "unknown-project";
|
|
4889
|
+
var UNKNOWN_SESSION_ERROR_CODE = "unknown-session";
|
|
4890
|
+
var COMMAND_TERMINAL_LIMIT_ERROR_CODE = "command-terminal-limit";
|
|
4891
|
+
var NOT_COMMAND_TERMINAL_ERROR_CODE = "not-command-terminal";
|
|
4892
|
+
var AGENT_UNAVAILABLE_ERROR_CODE = "agent-unavailable";
|
|
4893
|
+
var COMMAND_TERMINAL_START_FAILED_ERROR_CODE = "command-terminal-start-failed";
|
|
4887
4894
|
var UNSUPPORTED_VERB_ERROR_NAME = "UnsupportedVerbError";
|
|
4888
4895
|
var UnsupportedVerbError = class extends Error {
|
|
4889
4896
|
requestId;
|
|
@@ -4971,7 +4978,11 @@ function validateEvent(event) {
|
|
|
4971
4978
|
return event;
|
|
4972
4979
|
}
|
|
4973
4980
|
case "diff": {
|
|
4974
|
-
if (typeof event.taskId !== "string") throw new Error('"diff" event
|
|
4981
|
+
if (event.taskId !== void 0 && typeof event.taskId !== "string") throw new Error('"diff" event has a non-string "taskId"');
|
|
4982
|
+
if (event.projectId !== void 0 && typeof event.projectId !== "string") throw new Error('"diff" event has a non-string "projectId"');
|
|
4983
|
+
if (event.taskId === void 0 === (event.projectId === void 0)) {
|
|
4984
|
+
throw new Error('"diff" event must carry exactly one of "taskId" and "projectId"');
|
|
4985
|
+
}
|
|
4975
4986
|
return event;
|
|
4976
4987
|
}
|
|
4977
4988
|
default:
|
|
@@ -5078,12 +5089,16 @@ function base64UrlDecode(encoded) {
|
|
|
5078
5089
|
}
|
|
5079
5090
|
|
|
5080
5091
|
// src/crypto/push-envelope.ts
|
|
5081
|
-
var PUSH_CATEGORIES = ["input-required", "turn-complete", "session-failed", "plan-complete", "spawn-stalled"];
|
|
5092
|
+
var PUSH_CATEGORIES = ["input-required", "turn-complete", "session-failed", "plan-complete", "spawn-stalled", "workflow-complete"];
|
|
5082
5093
|
function isPushCategory(value) {
|
|
5083
5094
|
return typeof value === "string" && PUSH_CATEGORIES.includes(value);
|
|
5084
5095
|
}
|
|
5085
5096
|
var PUSH_ENVELOPE_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
5086
5097
|
var PUSH_ENVELOPE_MAX_FUTURE_SKEW_MS = 5 * 60 * 1e3;
|
|
5098
|
+
var PUSH_SESSION_KINDS = ["command-terminal"];
|
|
5099
|
+
function isPushSessionKind(value) {
|
|
5100
|
+
return typeof value === "string" && PUSH_SESSION_KINDS.includes(value);
|
|
5101
|
+
}
|
|
5087
5102
|
function requireEnvelopeString(record, field) {
|
|
5088
5103
|
const value = record[field];
|
|
5089
5104
|
if (typeof value !== "string") throw new Error(`push envelope plaintext is missing a string "${field}"`);
|
|
@@ -5102,7 +5117,10 @@ function parsePushEnvelopePlaintext(value) {
|
|
|
5102
5117
|
sessionId: requireEnvelopeString(value, "sessionId"),
|
|
5103
5118
|
taskTitle: requireEnvelopeString(value, "taskTitle"),
|
|
5104
5119
|
detail: requireEnvelopeString(value, "detail"),
|
|
5105
|
-
sentAt: value.sentAt
|
|
5120
|
+
sentAt: value.sentAt,
|
|
5121
|
+
// An unknown kind (from a newer desktop) is dropped, not rejected, so the
|
|
5122
|
+
// notification still opens; the tap then routes as a task's would.
|
|
5123
|
+
...isPushSessionKind(value.sessionKind) ? { sessionKind: value.sessionKind } : {}
|
|
5106
5124
|
};
|
|
5107
5125
|
}
|
|
5108
5126
|
function sealPushEnvelope(pushKey, recipientStaticPublicKey, plaintext) {
|
|
@@ -5352,7 +5370,39 @@ function parseBoardTaskWire(value) {
|
|
|
5352
5370
|
spawn_progress: nullableString(value, "spawn_progress"),
|
|
5353
5371
|
resumable: nullableBoolean(value, "resumable"),
|
|
5354
5372
|
paused: nullableBoolean(value, "paused"),
|
|
5355
|
-
pausable: nullableBoolean(value, "pausable")
|
|
5373
|
+
pausable: nullableBoolean(value, "pausable"),
|
|
5374
|
+
workflow: parseBoardTaskWorkflowWire(value.workflow)
|
|
5375
|
+
};
|
|
5376
|
+
}
|
|
5377
|
+
function parseBoardTaskWorkflowWire(value) {
|
|
5378
|
+
if (value === void 0 || !isRecord(value)) return null;
|
|
5379
|
+
const strings = (field) => Array.isArray(field) ? field.filter((entry) => typeof entry === "string") : [];
|
|
5380
|
+
if (typeof value.id !== "string" || typeof value.title !== "string" || typeof value.project_id !== "string") return null;
|
|
5381
|
+
return {
|
|
5382
|
+
id: value.id,
|
|
5383
|
+
title: value.title,
|
|
5384
|
+
project_id: value.project_id,
|
|
5385
|
+
state: typeof value.state === "string" ? value.state : "running",
|
|
5386
|
+
color_slot: typeof value.color_slot === "number" ? value.color_slot : 1,
|
|
5387
|
+
route: strings(value.route),
|
|
5388
|
+
waiting_for: strings(value.waiting_for),
|
|
5389
|
+
lock_reason: typeof value.lock_reason === "string" ? value.lock_reason : null,
|
|
5390
|
+
gate_target_id: typeof value.gate_target_id === "string" ? value.gate_target_id : null
|
|
5391
|
+
};
|
|
5392
|
+
}
|
|
5393
|
+
function parseCommandTerminalWire(value) {
|
|
5394
|
+
if (!isRecord(value)) throw new Error("command terminal must be an object");
|
|
5395
|
+
const activity = isRecord(value.activity) ? value.activity : {};
|
|
5396
|
+
return {
|
|
5397
|
+
sessionId: requireString(value, "sessionId", "command terminal"),
|
|
5398
|
+
projectId: requireString(value, "projectId", "command terminal"),
|
|
5399
|
+
slot: requireNumber(value, "slot", "command terminal"),
|
|
5400
|
+
name: requireString(value, "name", "command terminal"),
|
|
5401
|
+
named: requireBoolean(value, "named", "command terminal"),
|
|
5402
|
+
activity: {
|
|
5403
|
+
state: isActivityStateWire(activity.state) ? activity.state : null,
|
|
5404
|
+
reason: isActivityReasonWire(activity.reason) ? activity.reason : null
|
|
5405
|
+
}
|
|
5356
5406
|
};
|
|
5357
5407
|
}
|
|
5358
5408
|
function parseBacklogItemWire(value) {
|
|
@@ -5547,6 +5597,12 @@ function parseReadBoardResponsePayload(payload) {
|
|
|
5547
5597
|
if (payload.view !== void 0 && payload.view !== "full" && payload.view !== "sessions") {
|
|
5548
5598
|
throw new Error('read-board response has an invalid "view"');
|
|
5549
5599
|
}
|
|
5600
|
+
if (payload.commandTerminals !== void 0 && !Array.isArray(payload.commandTerminals)) {
|
|
5601
|
+
throw new Error('read-board response has a non-array "commandTerminals"');
|
|
5602
|
+
}
|
|
5603
|
+
if (payload.commandTerminalsOffered !== void 0 && typeof payload.commandTerminalsOffered !== "boolean") {
|
|
5604
|
+
throw new Error('read-board response has a non-boolean "commandTerminalsOffered"');
|
|
5605
|
+
}
|
|
5550
5606
|
return {
|
|
5551
5607
|
projectId: payload.projectId,
|
|
5552
5608
|
columns: payload.columns.map((column) => parseBoardColumnWire(column)),
|
|
@@ -5555,7 +5611,9 @@ function parseReadBoardResponsePayload(payload) {
|
|
|
5555
5611
|
...payload.projectColor !== void 0 ? { projectColor: parseAccentColor(payload.projectColor, "read-board snapshot") } : {},
|
|
5556
5612
|
...payload.showTicketNumbers !== void 0 ? { showTicketNumbers: payload.showTicketNumbers } : {},
|
|
5557
5613
|
...payload.view !== void 0 ? { view: payload.view } : {},
|
|
5558
|
-
...payload.taskCountsByColumnId !== void 0 ? { taskCountsByColumnId: parseTaskCountsByColumnId(payload.taskCountsByColumnId) } : {}
|
|
5614
|
+
...payload.taskCountsByColumnId !== void 0 ? { taskCountsByColumnId: parseTaskCountsByColumnId(payload.taskCountsByColumnId) } : {},
|
|
5615
|
+
...payload.commandTerminals !== void 0 ? { commandTerminals: payload.commandTerminals.map((terminal) => parseCommandTerminalWire(terminal)) } : {},
|
|
5616
|
+
...payload.commandTerminalsOffered !== void 0 ? { commandTerminalsOffered: payload.commandTerminalsOffered } : {}
|
|
5559
5617
|
};
|
|
5560
5618
|
}
|
|
5561
5619
|
function parseTaskCountsByColumnId(value) {
|
|
@@ -5609,7 +5667,7 @@ function parseReadDiffResponsePayload(payload) {
|
|
|
5609
5667
|
}
|
|
5610
5668
|
function parseReadDiffRequestPayload(payload) {
|
|
5611
5669
|
if (!isRecord(payload)) throw new Error("read-diff payload must be an object");
|
|
5612
|
-
if (typeof payload.taskId !== "string") throw new Error('read-diff payload
|
|
5670
|
+
if (payload.taskId !== void 0 && typeof payload.taskId !== "string") throw new Error('read-diff payload has a non-string "taskId"');
|
|
5613
5671
|
if (typeof payload.projectId !== "string") throw new Error('read-diff payload missing "projectId"');
|
|
5614
5672
|
if (payload.filePath !== void 0 && typeof payload.filePath !== "string") {
|
|
5615
5673
|
throw new Error('read-diff payload has a non-string "filePath"');
|
|
@@ -5621,7 +5679,7 @@ function parseReadDiffRequestPayload(payload) {
|
|
|
5621
5679
|
throw new Error('read-diff payload has an invalid "action"');
|
|
5622
5680
|
}
|
|
5623
5681
|
return {
|
|
5624
|
-
taskId: payload.taskId,
|
|
5682
|
+
...payload.taskId !== void 0 ? { taskId: payload.taskId } : {},
|
|
5625
5683
|
projectId: payload.projectId,
|
|
5626
5684
|
filePath: payload.filePath,
|
|
5627
5685
|
scope: payload.scope,
|
|
@@ -5673,6 +5731,28 @@ function parsePauseSessionRequestPayload(payload) {
|
|
|
5673
5731
|
projectId: payload.projectId
|
|
5674
5732
|
};
|
|
5675
5733
|
}
|
|
5734
|
+
function parseCommandTerminalRequestPayload(payload) {
|
|
5735
|
+
if (!isRecord(payload)) throw new Error("command-terminal payload must be an object");
|
|
5736
|
+
if (payload.action === "start") {
|
|
5737
|
+
if (typeof payload.projectId !== "string") throw new Error('command-terminal start payload missing "projectId"');
|
|
5738
|
+
return { action: "start", projectId: payload.projectId };
|
|
5739
|
+
}
|
|
5740
|
+
if (payload.action === "stop") {
|
|
5741
|
+
if (typeof payload.sessionId !== "string") throw new Error('command-terminal stop payload missing "sessionId"');
|
|
5742
|
+
return { action: "stop", sessionId: payload.sessionId };
|
|
5743
|
+
}
|
|
5744
|
+
throw new Error('command-terminal payload has an invalid "action"');
|
|
5745
|
+
}
|
|
5746
|
+
function parseCommandTerminalStartResponsePayload(payload) {
|
|
5747
|
+
if (!isRecord(payload)) throw new Error("command-terminal start response must be an object");
|
|
5748
|
+
if (payload.ok !== true) throw new Error('command-terminal start response missing "ok"');
|
|
5749
|
+
if (typeof payload.sessionId !== "string") throw new Error('command-terminal start response missing "sessionId"');
|
|
5750
|
+
if (typeof payload.slot !== "number" || !Number.isInteger(payload.slot) || payload.slot < 1) {
|
|
5751
|
+
throw new Error('command-terminal start response has an invalid "slot"');
|
|
5752
|
+
}
|
|
5753
|
+
if (typeof payload.name !== "string") throw new Error('command-terminal start response missing "name"');
|
|
5754
|
+
return { ok: true, sessionId: payload.sessionId, slot: payload.slot, name: payload.name };
|
|
5755
|
+
}
|
|
5676
5756
|
function parsePauseSessionResponsePayload(payload) {
|
|
5677
5757
|
if (!isRecord(payload)) throw new Error("pause-session response must be an object");
|
|
5678
5758
|
if (typeof payload.ok !== "boolean") throw new Error('pause-session response missing "ok"');
|
|
@@ -5777,6 +5857,8 @@ function parseCapabilityRequestPayload(verb, payload) {
|
|
|
5777
5857
|
return parseStartSessionRequestPayload(payload);
|
|
5778
5858
|
case "pause-session":
|
|
5779
5859
|
return parsePauseSessionRequestPayload(payload);
|
|
5860
|
+
case "command-terminal":
|
|
5861
|
+
return parseCommandTerminalRequestPayload(payload);
|
|
5780
5862
|
default: {
|
|
5781
5863
|
const exhaustiveCheck = verb;
|
|
5782
5864
|
throw new Error(`Unknown capability verb: ${String(exhaustiveCheck)}`);
|
|
@@ -5982,7 +6064,10 @@ var BOARD_TOOL_READ_NAMES = [
|
|
|
5982
6064
|
"get_transcript",
|
|
5983
6065
|
"get_session_files",
|
|
5984
6066
|
"get_session_events",
|
|
5985
|
-
"get_activity_intervals"
|
|
6067
|
+
"get_activity_intervals",
|
|
6068
|
+
// Workflows: the project's workflows and one workflow's tasks, routes and links.
|
|
6069
|
+
"list_workflows",
|
|
6070
|
+
"get_workflow"
|
|
5986
6071
|
];
|
|
5987
6072
|
var BOARD_TOOL_WRITE_NAMES = [
|
|
5988
6073
|
"create_task",
|
|
@@ -5997,7 +6082,10 @@ var BOARD_TOOL_WRITE_NAMES = [
|
|
|
5997
6082
|
"create_backlog_task",
|
|
5998
6083
|
"promote_backlog",
|
|
5999
6084
|
"update_backlog_item",
|
|
6000
|
-
"delete_backlog_item"
|
|
6085
|
+
"delete_backlog_item",
|
|
6086
|
+
// Workflows: stop every task of a running workflow at once, and start them again.
|
|
6087
|
+
"pause_workflow",
|
|
6088
|
+
"resume_workflow"
|
|
6001
6089
|
];
|
|
6002
6090
|
function isBoardToolReadName(value) {
|
|
6003
6091
|
return BOARD_TOOL_READ_NAMES.includes(value);
|
|
@@ -6007,7 +6095,14 @@ function isBoardToolWriteName(value) {
|
|
|
6007
6095
|
}
|
|
6008
6096
|
|
|
6009
6097
|
// src/events/event.ts
|
|
6010
|
-
var BOARD_CHANGES = [
|
|
6098
|
+
var BOARD_CHANGES = [
|
|
6099
|
+
"task-created",
|
|
6100
|
+
"task-updated",
|
|
6101
|
+
"task-deleted",
|
|
6102
|
+
"swimlane-updated",
|
|
6103
|
+
"backlog-changed",
|
|
6104
|
+
"command-terminals-changed"
|
|
6105
|
+
];
|
|
6011
6106
|
function parseActivityEventPayload(payload) {
|
|
6012
6107
|
if (!isRecord(payload)) throw new Error("activity payload must be an object");
|
|
6013
6108
|
switch (payload.type) {
|
|
@@ -6102,17 +6197,26 @@ function isBridgeEvent(value) {
|
|
|
6102
6197
|
if (typeof change !== "string" || !BOARD_CHANGES.includes(change)) return false;
|
|
6103
6198
|
return Array.isArray(value.payload.ids) && value.payload.ids.every((id) => typeof id === "string");
|
|
6104
6199
|
}
|
|
6105
|
-
case "diff":
|
|
6106
|
-
|
|
6200
|
+
case "diff": {
|
|
6201
|
+
if (value.payload !== null) return false;
|
|
6202
|
+
const hasTaskId = typeof value.taskId === "string";
|
|
6203
|
+
const hasProjectId = typeof value.projectId === "string";
|
|
6204
|
+
if (value.taskId !== void 0 && !hasTaskId) return false;
|
|
6205
|
+
if (value.projectId !== void 0 && !hasProjectId) return false;
|
|
6206
|
+
return hasTaskId !== hasProjectId;
|
|
6207
|
+
}
|
|
6107
6208
|
default:
|
|
6108
6209
|
return false;
|
|
6109
6210
|
}
|
|
6110
6211
|
}
|
|
6111
6212
|
export {
|
|
6213
|
+
AGENT_UNAVAILABLE_ERROR_CODE,
|
|
6112
6214
|
BOARD_COLUMN_ROLES,
|
|
6113
6215
|
BOARD_TOOL_READ_NAMES,
|
|
6114
6216
|
BOARD_TOOL_WRITE_NAMES,
|
|
6115
6217
|
CAPABILITY_VERBS,
|
|
6218
|
+
COMMAND_TERMINAL_LIMIT_ERROR_CODE,
|
|
6219
|
+
COMMAND_TERMINAL_START_FAILED_ERROR_CODE,
|
|
6116
6220
|
COMPRESSION_THRESHOLD,
|
|
6117
6221
|
CipherState,
|
|
6118
6222
|
ED25519_KEY_LENGTH,
|
|
@@ -6123,14 +6227,18 @@ export {
|
|
|
6123
6227
|
MAX_DECODED_LENGTH,
|
|
6124
6228
|
MAX_FRAME_LENGTH,
|
|
6125
6229
|
MAX_RELAY_ADDRESS_LENGTH,
|
|
6230
|
+
NOT_COMMAND_TERMINAL_ERROR_CODE,
|
|
6126
6231
|
PAIRING_URI_SCHEME,
|
|
6127
6232
|
PROTOCOL_VERSION,
|
|
6128
6233
|
PUSH_CATEGORIES,
|
|
6129
6234
|
PUSH_ENVELOPE_MAX_AGE_MS,
|
|
6130
6235
|
PUSH_ENVELOPE_MAX_FUTURE_SKEW_MS,
|
|
6236
|
+
PUSH_SESSION_KINDS,
|
|
6131
6237
|
RESPONSE_TOO_LARGE_ERROR_CODE,
|
|
6132
6238
|
SecretstreamState,
|
|
6133
6239
|
SessionFrameKind,
|
|
6240
|
+
UNKNOWN_PROJECT_ERROR_CODE,
|
|
6241
|
+
UNKNOWN_SESSION_ERROR_CODE,
|
|
6134
6242
|
UNSUPPORTED_VERB_ERROR_CODE,
|
|
6135
6243
|
UnsupportedVerbError,
|
|
6136
6244
|
X25519_KEY_LENGTH,
|
|
@@ -6166,6 +6274,7 @@ export {
|
|
|
6166
6274
|
isDoneRole,
|
|
6167
6275
|
isJsonValue,
|
|
6168
6276
|
isPushCategory,
|
|
6277
|
+
isPushSessionKind,
|
|
6169
6278
|
isReadStreamSessionStatusWire,
|
|
6170
6279
|
isRecord,
|
|
6171
6280
|
isRosterEntryExpired,
|
|
@@ -6178,7 +6287,10 @@ export {
|
|
|
6178
6287
|
parseBacklogItemWire,
|
|
6179
6288
|
parseBoardColumnWire,
|
|
6180
6289
|
parseBoardTaskWire,
|
|
6290
|
+
parseBoardTaskWorkflowWire,
|
|
6181
6291
|
parseCapabilityRequestPayload,
|
|
6292
|
+
parseCommandTerminalStartResponsePayload,
|
|
6293
|
+
parseCommandTerminalWire,
|
|
6182
6294
|
parseDiffFileContentWire,
|
|
6183
6295
|
parseDiffFileListWire,
|
|
6184
6296
|
parsePauseSessionResponsePayload,
|
package/dist/wire/framing.d.ts
CHANGED
|
@@ -8,6 +8,18 @@ export declare const COMPRESSION_THRESHOLD: number;
|
|
|
8
8
|
export declare const UNSUPPORTED_VERB_ERROR_CODE: CapabilityErrorCode;
|
|
9
9
|
/** The `code` a desktop puts on its refusal of a response that would not fit the frame caps above. */
|
|
10
10
|
export declare const RESPONSE_TOO_LARGE_ERROR_CODE: CapabilityErrorCode;
|
|
11
|
+
/** The `code` on a refusal that named a project this desktop does not have. */
|
|
12
|
+
export declare const UNKNOWN_PROJECT_ERROR_CODE: CapabilityErrorCode;
|
|
13
|
+
/** The `code` on a refusal that named a session id that is not live. */
|
|
14
|
+
export declare const UNKNOWN_SESSION_ERROR_CODE: CapabilityErrorCode;
|
|
15
|
+
/** The `code` on a `command-terminal` start refused at the per-project cap. */
|
|
16
|
+
export declare const COMMAND_TERMINAL_LIMIT_ERROR_CODE: CapabilityErrorCode;
|
|
17
|
+
/** The `code` on a `command-terminal` stop that named a session which is not a Command Terminal. */
|
|
18
|
+
export declare const NOT_COMMAND_TERMINAL_ERROR_CODE: CapabilityErrorCode;
|
|
19
|
+
/** The `code` on a start refused because the project's agent CLI is not installed. */
|
|
20
|
+
export declare const AGENT_UNAVAILABLE_ERROR_CODE: CapabilityErrorCode;
|
|
21
|
+
/** The `code` on a `command-terminal` start that failed for any other reason. */
|
|
22
|
+
export declare const COMMAND_TERMINAL_START_FAILED_ERROR_CODE: CapabilityErrorCode;
|
|
11
23
|
/**
|
|
12
24
|
* Thrown by `decodeMessage` for a capability-request whose envelope is
|
|
13
25
|
* well-formed (a string `requestId`, a string `verb`, a JSON `payload`) but
|
package/dist/wire/messages.d.ts
CHANGED
|
@@ -45,8 +45,24 @@ export interface CapabilityRequestMessage {
|
|
|
45
45
|
* gone (a session ending, a project removed). It is a backstop. A desktop
|
|
46
46
|
* shrinks a `read-stream` terminal seed to fit rather than refuse it, so a
|
|
47
47
|
* phone's terminal subscribe is never answered with this code.
|
|
48
|
+
* - `unknown-project`: the request named a project id this desktop does not
|
|
49
|
+
* have (removed, or never registered).
|
|
50
|
+
* - `unknown-session`: the request named a session id that is not live. For a
|
|
51
|
+
* `command-terminal` stop it means the terminal already ended, so a phone
|
|
52
|
+
* treats it as stopped.
|
|
53
|
+
* - `command-terminal-limit`: the project already runs the most Command
|
|
54
|
+
* Terminals a project may have at once (four).
|
|
55
|
+
* - `not-command-terminal`: a `command-terminal` stop named a session that is
|
|
56
|
+
* not a Command Terminal (a task's agent). Nothing was stopped.
|
|
57
|
+
* - `agent-unavailable`: the project's agent CLI could not be found on the
|
|
58
|
+
* desktop, so nothing could be started.
|
|
59
|
+
* - `command-terminal-start-failed`: a `command-terminal` start failed for any
|
|
60
|
+
* other reason. `error` carries the desktop's text for logs.
|
|
61
|
+
*
|
|
62
|
+
* A peer must treat a code it does not know as a generic failure and show
|
|
63
|
+
* `error` or a plain line of its own: a newer desktop may add codes.
|
|
48
64
|
*/
|
|
49
|
-
export type CapabilityErrorCode = 'unsupported-verb' | 'response-too-large';
|
|
65
|
+
export type CapabilityErrorCode = 'unsupported-verb' | 'response-too-large' | 'unknown-project' | 'unknown-session' | 'command-terminal-limit' | 'not-command-terminal' | 'agent-unavailable' | 'command-terminal-start-failed';
|
|
50
66
|
export interface CapabilityResponseMessage {
|
|
51
67
|
type: 'capability-response';
|
|
52
68
|
requestId: string;
|
package/dist/wire/payloads.d.ts
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
import type { CapabilityVerb } from '../capabilities/verbs';
|
|
17
17
|
import type { JsonValue } from './messages';
|
|
18
18
|
import { type PushCategory } from '../crypto/push-envelope';
|
|
19
|
-
import { type ActivityReasonWire, type ActivityStateWire, type BacklogItemWire, type BoardColumnWire, type BoardTaskWire, type DiffFileContentWire, type DiffFileListWire, type SessionSummaryWire, type SessionUsageWire, type TerminalDimensionsWire, type TranscriptEntryWire } from '../events/payloads';
|
|
19
|
+
import { type ActivityReasonWire, type ActivityStateWire, type BacklogItemWire, type BoardColumnWire, type BoardTaskWire, type CommandTerminalWire, type DiffFileContentWire, type DiffFileListWire, type SessionSummaryWire, type SessionUsageWire, type TerminalDimensionsWire, type TranscriptEntryWire } from '../events/payloads';
|
|
20
20
|
export interface ReadStreamRequestPayload {
|
|
21
21
|
sessionId: string;
|
|
22
22
|
/**
|
|
@@ -251,6 +251,20 @@ export interface ReadBoardSnapshotResponsePayload {
|
|
|
251
251
|
* card to a column needs the real length.
|
|
252
252
|
*/
|
|
253
253
|
taskCountsByColumnId?: Record<string, number>;
|
|
254
|
+
/**
|
|
255
|
+
* The project's live Command Terminals, ordered by slot (protocol 0.20.0).
|
|
256
|
+
* Carried by every snapshot view, because the Agents feed lists them beside
|
|
257
|
+
* every project's task agents. Absent from an older desktop, which has no way
|
|
258
|
+
* to report them. A `command-terminals-changed` board event says to re-read it.
|
|
259
|
+
*/
|
|
260
|
+
commandTerminals?: CommandTerminalWire[];
|
|
261
|
+
/**
|
|
262
|
+
* True when this desktop serves the `command-terminal` verb AND the device
|
|
263
|
+
* holds it (protocol 0.20.0). The phone keeps no grant list, so it shows its
|
|
264
|
+
* Terminals button on this flag, the way `BoardTaskWire.pausable` gates Pause.
|
|
265
|
+
* Absent from an older desktop: treat that as false.
|
|
266
|
+
*/
|
|
267
|
+
commandTerminalsOffered?: boolean;
|
|
254
268
|
}
|
|
255
269
|
/**
|
|
256
270
|
* Returned for `action: 'archived'` - one page of a project's completed tasks
|
|
@@ -283,7 +297,14 @@ export declare function parseReadBoardResponsePayload(payload: JsonValue): ReadB
|
|
|
283
297
|
/** Mirrors DiffService's GitDiffScope in the desktop app; kept as a literal union here rather than an import, since the protocol package does not depend on the app. */
|
|
284
298
|
export type ReadDiffScope = 'working' | 'staged' | 'branch';
|
|
285
299
|
export interface ReadDiffRequestPayload {
|
|
286
|
-
|
|
300
|
+
/**
|
|
301
|
+
* The task whose worktree (or, for a task with none, whose base) to diff.
|
|
302
|
+
* Optional from protocol 0.20.0: with no `taskId` the desktop diffs the
|
|
303
|
+
* PROJECT FOLDER against the project's default base branch, exactly as a
|
|
304
|
+
* Command Terminal window's Changes panel does, and its live pings arrive
|
|
305
|
+
* as a `DiffEvent` carrying `projectId` instead of `taskId`.
|
|
306
|
+
*/
|
|
307
|
+
taskId?: string;
|
|
287
308
|
projectId: string;
|
|
288
309
|
filePath?: string;
|
|
289
310
|
scope?: ReadDiffScope;
|
|
@@ -363,6 +384,50 @@ export interface PauseSessionRequestPayload {
|
|
|
363
384
|
export interface PauseSessionResponsePayload {
|
|
364
385
|
ok: boolean;
|
|
365
386
|
}
|
|
387
|
+
/**
|
|
388
|
+
* Start or stop a Command Terminal (protocol 0.20.0). See `command-terminal` in
|
|
389
|
+
* capabilities/verbs.ts for what one is.
|
|
390
|
+
*
|
|
391
|
+
* `start` names only the project. The desktop picks the slot, runs the
|
|
392
|
+
* project's default agent with its default model and effort, and starts on the
|
|
393
|
+
* project's default branch the same way its own New terminal does; there is no
|
|
394
|
+
* branch, model or effort parameter, and the parser below drops any such key.
|
|
395
|
+
* `stop` names the terminal's session and is refused for any other session.
|
|
396
|
+
*/
|
|
397
|
+
export type CommandTerminalRequestPayload = {
|
|
398
|
+
action: 'start';
|
|
399
|
+
projectId: string;
|
|
400
|
+
} | {
|
|
401
|
+
action: 'stop';
|
|
402
|
+
sessionId: string;
|
|
403
|
+
};
|
|
404
|
+
/**
|
|
405
|
+
* A `start` is answered once the desktop has the session, before the agent has
|
|
406
|
+
* drawn anything, so the phone opens the terminal's screen at once and its
|
|
407
|
+
* stream shows the agent arriving. `slot` is the terminal's number in its
|
|
408
|
+
* project (1 to 4) and `name` its label, "Command Terminal N" until the
|
|
409
|
+
* desktop names it from its first prompt.
|
|
410
|
+
*
|
|
411
|
+
* Refusals carry a `code` on the capability response: `command-terminal-limit`,
|
|
412
|
+
* `unknown-project`, `agent-unavailable` or `command-terminal-start-failed`.
|
|
413
|
+
*/
|
|
414
|
+
export interface CommandTerminalStartResponsePayload {
|
|
415
|
+
ok: true;
|
|
416
|
+
sessionId: string;
|
|
417
|
+
slot: number;
|
|
418
|
+
name: string;
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* A `stop` is answered once the desktop has ended the terminal. Refusals carry
|
|
422
|
+
* `unknown-session` (it already ended, so treat it as stopped) or
|
|
423
|
+
* `not-command-terminal`.
|
|
424
|
+
*/
|
|
425
|
+
export interface CommandTerminalStopResponsePayload {
|
|
426
|
+
ok: true;
|
|
427
|
+
}
|
|
428
|
+
export type CommandTerminalResponsePayload = CommandTerminalStartResponsePayload | CommandTerminalStopResponsePayload;
|
|
429
|
+
/** Phone-side guard: narrows a decoded `command-terminal` start response before the phone opens the terminal. */
|
|
430
|
+
export declare function parseCommandTerminalStartResponsePayload(payload: JsonValue): CommandTerminalStartResponsePayload;
|
|
366
431
|
/** Phone-side guard: narrows a decoded pause-session response before the phone acts on it. */
|
|
367
432
|
export declare function parsePauseSessionResponsePayload(payload: JsonValue): PauseSessionResponsePayload;
|
|
368
433
|
export interface AnswerPermissionPromptRequestPayload {
|
|
@@ -452,6 +517,7 @@ export interface CapabilityRequestPayloadMap {
|
|
|
452
517
|
'register-push': RegisterPushRequestPayload;
|
|
453
518
|
'start-session': StartSessionRequestPayload;
|
|
454
519
|
'pause-session': PauseSessionRequestPayload;
|
|
520
|
+
'command-terminal': CommandTerminalRequestPayload;
|
|
455
521
|
}
|
|
456
522
|
export interface CapabilityResponsePayloadMap {
|
|
457
523
|
'read-stream': ReadStreamResponsePayload | TranscriptWindowResponsePayload;
|
|
@@ -466,6 +532,7 @@ export interface CapabilityResponsePayloadMap {
|
|
|
466
532
|
'register-push': RegisterPushResponsePayload;
|
|
467
533
|
'start-session': StartSessionResponsePayload;
|
|
468
534
|
'pause-session': PauseSessionResponsePayload;
|
|
535
|
+
'command-terminal': CommandTerminalResponsePayload;
|
|
469
536
|
}
|
|
470
537
|
/**
|
|
471
538
|
* Validates and narrows a decoded capability-request's generic JsonValue
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kangentic/protocol",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"description": "Kangentic mobile bridge wire protocol: framing, Noise-based pairing and session handshakes, signed device roster, and capability verbs shared between desktop and mobile.",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.mjs",
|