@kangentic/protocol 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/capabilities/board-tools.d.ts +2 -2
- package/dist/events/payloads.d.ts +48 -0
- package/dist/index.cjs +64 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +63 -2
- package/dist/wire/payloads.d.ts +46 -5
- package/package.json +2 -1
|
@@ -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", "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_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"];
|
|
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"];
|
|
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;
|
|
@@ -167,6 +167,44 @@ export interface SessionUsageWire {
|
|
|
167
167
|
effort?: string;
|
|
168
168
|
};
|
|
169
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* Phone-needed subset of the desktop's SessionSummary: what a task COST over
|
|
172
|
+
* its whole life, as opposed to SessionUsageWire's live snapshot of one
|
|
173
|
+
* running agent.
|
|
174
|
+
*
|
|
175
|
+
* Every figure is a lifetime aggregate across every session record of the
|
|
176
|
+
* task, which is what makes it meaningful for a completed one: a task worked
|
|
177
|
+
* across five `--resume` legs has five session rows, and reporting only the
|
|
178
|
+
* final leg would under-report everything. The desktop's getSummaryForTask
|
|
179
|
+
* owns those aggregation rules (SUM cost/duration/tool calls/lines, MAX files
|
|
180
|
+
* changed, and tokens taken as the latest row per session lineage so a
|
|
181
|
+
* resumed session is not double-counted) - they are not re-derived here.
|
|
182
|
+
*
|
|
183
|
+
* `sessionId` is the transcript ANCHOR, not a live session: it resolves
|
|
184
|
+
* through the desktop's session records, which outlive the agent, so it reads
|
|
185
|
+
* a finished task's conversation with nothing running. An archived task's
|
|
186
|
+
* `session_id` on the board is null by then, so this is the only handle to it.
|
|
187
|
+
*/
|
|
188
|
+
export interface SessionSummaryWire {
|
|
189
|
+
sessionId: string;
|
|
190
|
+
totalCostUsd: number;
|
|
191
|
+
totalInputTokens: number;
|
|
192
|
+
totalOutputTokens: number;
|
|
193
|
+
modelDisplayName: string;
|
|
194
|
+
durationMs: number;
|
|
195
|
+
toolCallCount: number;
|
|
196
|
+
compactionCount: number;
|
|
197
|
+
linesAdded: number;
|
|
198
|
+
linesRemoved: number;
|
|
199
|
+
filesChanged: number;
|
|
200
|
+
/** ISO 8601. The task's creation, which is where its timeline starts. */
|
|
201
|
+
taskCreatedAt: string;
|
|
202
|
+
/** ISO 8601. Earliest session start across every leg. */
|
|
203
|
+
startedAt: string;
|
|
204
|
+
/** ISO 8601, or null while a leg is still open. Latest exit or suspend. */
|
|
205
|
+
exitedAt: string | null;
|
|
206
|
+
exitCode: number | null;
|
|
207
|
+
}
|
|
170
208
|
/**
|
|
171
209
|
* Loose mirror of the desktop's SessionEvent telemetry entry. `type` is
|
|
172
210
|
* deliberately a plain string, not the desktop's EventType enum, so a new
|
|
@@ -267,6 +305,16 @@ export declare function isActivityStateWire(value: unknown): value is ActivitySt
|
|
|
267
305
|
export declare function isActivityReasonWire(value: unknown): value is ActivityReasonWire;
|
|
268
306
|
/** Narrows a usage payload to the SessionUsageWire subset. Throws on a malformed required field. */
|
|
269
307
|
export declare function parseSessionUsageWire(payload: JsonValue): SessionUsageWire;
|
|
308
|
+
/**
|
|
309
|
+
* Narrows a session-summary payload to SessionSummaryWire. Throws on a
|
|
310
|
+
* malformed required field.
|
|
311
|
+
*
|
|
312
|
+
* The numeric metrics are required rather than optional because the desktop
|
|
313
|
+
* COALESCEs each to 0 before it sends them, so "no data" arrives as a real
|
|
314
|
+
* zero. Making them optional here would invite a phone to render an em-dash
|
|
315
|
+
* where the honest answer is 0.
|
|
316
|
+
*/
|
|
317
|
+
export declare function parseSessionSummaryWire(payload: JsonValue): SessionSummaryWire;
|
|
270
318
|
/** Narrows a session-event payload to SessionEventWire. Throws on a malformed required field. */
|
|
271
319
|
export declare function parseSessionEventWire(payload: JsonValue): SessionEventWire;
|
|
272
320
|
/** Narrows one board-column row. Throws on a malformed required field. */
|
package/dist/index.cjs
CHANGED
|
@@ -88,6 +88,7 @@ __export(index_exports, {
|
|
|
88
88
|
parseReadStreamResponsePayload: () => parseReadStreamResponsePayload,
|
|
89
89
|
parseRegisterPushRequestPayload: () => parseRegisterPushRequestPayload,
|
|
90
90
|
parseSessionEventWire: () => parseSessionEventWire,
|
|
91
|
+
parseSessionSummaryWire: () => parseSessionSummaryWire,
|
|
91
92
|
parseSessionUsageWire: () => parseSessionUsageWire,
|
|
92
93
|
parseTerminalDimensionsWire: () => parseTerminalDimensionsWire,
|
|
93
94
|
parseTranscriptEntriesWire: () => parseTranscriptEntriesWire,
|
|
@@ -5364,6 +5365,26 @@ function parseSessionUsageWire(payload) {
|
|
|
5364
5365
|
}
|
|
5365
5366
|
};
|
|
5366
5367
|
}
|
|
5368
|
+
function parseSessionSummaryWire(payload) {
|
|
5369
|
+
if (!isRecord(payload)) throw new Error("session summary payload must be an object");
|
|
5370
|
+
return {
|
|
5371
|
+
sessionId: requireString(payload, "sessionId", "session summary"),
|
|
5372
|
+
totalCostUsd: requireNumber(payload, "totalCostUsd", "session summary"),
|
|
5373
|
+
totalInputTokens: requireNumber(payload, "totalInputTokens", "session summary"),
|
|
5374
|
+
totalOutputTokens: requireNumber(payload, "totalOutputTokens", "session summary"),
|
|
5375
|
+
modelDisplayName: requireString(payload, "modelDisplayName", "session summary"),
|
|
5376
|
+
durationMs: requireNumber(payload, "durationMs", "session summary"),
|
|
5377
|
+
toolCallCount: requireNumber(payload, "toolCallCount", "session summary"),
|
|
5378
|
+
compactionCount: requireNumber(payload, "compactionCount", "session summary"),
|
|
5379
|
+
linesAdded: requireNumber(payload, "linesAdded", "session summary"),
|
|
5380
|
+
linesRemoved: requireNumber(payload, "linesRemoved", "session summary"),
|
|
5381
|
+
filesChanged: requireNumber(payload, "filesChanged", "session summary"),
|
|
5382
|
+
taskCreatedAt: requireString(payload, "taskCreatedAt", "session summary"),
|
|
5383
|
+
startedAt: requireString(payload, "startedAt", "session summary"),
|
|
5384
|
+
exitedAt: typeof payload.exitedAt === "string" ? payload.exitedAt : null,
|
|
5385
|
+
exitCode: typeof payload.exitCode === "number" ? payload.exitCode : null
|
|
5386
|
+
};
|
|
5387
|
+
}
|
|
5367
5388
|
function parseSessionEventWire(payload) {
|
|
5368
5389
|
if (!isRecord(payload)) throw new Error("session event payload must be an object");
|
|
5369
5390
|
return {
|
|
@@ -5566,6 +5587,18 @@ function parseAccentColor(value, context) {
|
|
|
5566
5587
|
}
|
|
5567
5588
|
function parseReadBoardResponsePayload(payload) {
|
|
5568
5589
|
if (!isRecord(payload)) throw new Error("read-board response must be an object");
|
|
5590
|
+
if (Array.isArray(payload.archivedTasks)) {
|
|
5591
|
+
if (typeof payload.projectId !== "string") throw new Error('read-board archived response is missing "projectId"');
|
|
5592
|
+
if (typeof payload.archivedTotalCount !== "number") {
|
|
5593
|
+
throw new Error('read-board archived response is missing "archivedTotalCount"');
|
|
5594
|
+
}
|
|
5595
|
+
return {
|
|
5596
|
+
projectId: payload.projectId,
|
|
5597
|
+
archivedTasks: payload.archivedTasks.map((task) => parseBoardTaskWire(task)),
|
|
5598
|
+
archivedTotalCount: payload.archivedTotalCount,
|
|
5599
|
+
summariesByTaskId: parseSummariesByTaskId(payload.summariesByTaskId)
|
|
5600
|
+
};
|
|
5601
|
+
}
|
|
5569
5602
|
if (Array.isArray(payload.projects)) {
|
|
5570
5603
|
const projects = payload.projects.map((project, index) => {
|
|
5571
5604
|
if (!isRecord(project) || typeof project.id !== "string" || typeof project.name !== "string") {
|
|
@@ -5610,18 +5643,42 @@ function parseTaskCountsByColumnId(value) {
|
|
|
5610
5643
|
}
|
|
5611
5644
|
return counts;
|
|
5612
5645
|
}
|
|
5646
|
+
function parseSummariesByTaskId(value) {
|
|
5647
|
+
if (value === void 0) return {};
|
|
5648
|
+
if (!isRecord(value)) throw new Error('read-board archived response has a non-object "summariesByTaskId"');
|
|
5649
|
+
const summaries = {};
|
|
5650
|
+
for (const [taskId, summary] of Object.entries(value)) {
|
|
5651
|
+
try {
|
|
5652
|
+
summaries[taskId] = parseSessionSummaryWire(summary);
|
|
5653
|
+
} catch {
|
|
5654
|
+
}
|
|
5655
|
+
}
|
|
5656
|
+
return summaries;
|
|
5657
|
+
}
|
|
5613
5658
|
function parseReadBoardRequestPayload(payload) {
|
|
5614
5659
|
if (!isRecord(payload)) throw new Error("read-board payload must be an object");
|
|
5615
5660
|
if (payload.projectId !== void 0 && typeof payload.projectId !== "string") {
|
|
5616
5661
|
throw new Error('read-board payload has a non-string "projectId"');
|
|
5617
5662
|
}
|
|
5618
|
-
if (payload.action !== void 0 && payload.action !== "subscribe" && payload.action !== "unsubscribe") {
|
|
5663
|
+
if (payload.action !== void 0 && payload.action !== "subscribe" && payload.action !== "unsubscribe" && payload.action !== "archived") {
|
|
5619
5664
|
throw new Error('read-board payload has an invalid "action"');
|
|
5620
5665
|
}
|
|
5621
5666
|
if (payload.view !== void 0 && payload.view !== "full" && payload.view !== "sessions") {
|
|
5622
5667
|
throw new Error('read-board payload has an invalid "view"');
|
|
5623
5668
|
}
|
|
5624
|
-
|
|
5669
|
+
if (payload.limit !== void 0 && (typeof payload.limit !== "number" || !Number.isInteger(payload.limit) || payload.limit < 1)) {
|
|
5670
|
+
throw new Error('read-board payload has an invalid "limit"');
|
|
5671
|
+
}
|
|
5672
|
+
if (payload.offset !== void 0 && (typeof payload.offset !== "number" || !Number.isInteger(payload.offset) || payload.offset < 0)) {
|
|
5673
|
+
throw new Error('read-board payload has an invalid "offset"');
|
|
5674
|
+
}
|
|
5675
|
+
return {
|
|
5676
|
+
projectId: payload.projectId,
|
|
5677
|
+
action: payload.action,
|
|
5678
|
+
view: payload.view,
|
|
5679
|
+
limit: payload.limit,
|
|
5680
|
+
offset: payload.offset
|
|
5681
|
+
};
|
|
5625
5682
|
}
|
|
5626
5683
|
function parseReadDiffResponsePayload(payload) {
|
|
5627
5684
|
if (!isRecord(payload)) throw new Error("read-diff response must be an object");
|
|
@@ -5942,6 +5999,7 @@ var BOARD_TOOL_READ_NAMES = [
|
|
|
5942
5999
|
"list_sessions",
|
|
5943
6000
|
"get_session_history",
|
|
5944
6001
|
"get_column_detail",
|
|
6002
|
+
"list_board_profiles",
|
|
5945
6003
|
"get_handoff_context",
|
|
5946
6004
|
"get_transcript",
|
|
5947
6005
|
"get_session_files",
|
|
@@ -5955,6 +6013,9 @@ var BOARD_TOOL_WRITE_NAMES = [
|
|
|
5955
6013
|
"link_pr",
|
|
5956
6014
|
"remove_attachment",
|
|
5957
6015
|
"update_column",
|
|
6016
|
+
"create_board_profile",
|
|
6017
|
+
"update_board_profile",
|
|
6018
|
+
"delete_board_profile",
|
|
5958
6019
|
"create_backlog_task",
|
|
5959
6020
|
"promote_backlog",
|
|
5960
6021
|
"update_backlog_item",
|
|
@@ -6122,6 +6183,7 @@ function isBridgeEvent(value) {
|
|
|
6122
6183
|
parseReadStreamResponsePayload,
|
|
6123
6184
|
parseRegisterPushRequestPayload,
|
|
6124
6185
|
parseSessionEventWire,
|
|
6186
|
+
parseSessionSummaryWire,
|
|
6125
6187
|
parseSessionUsageWire,
|
|
6126
6188
|
parseTerminalDimensionsWire,
|
|
6127
6189
|
parseTranscriptEntriesWire,
|
package/dist/index.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export type { JsonValue, BridgeMessage, HeartbeatMessage, CapabilityRequestMessa
|
|
|
12
12
|
export { encodeMessage, decodeMessage, 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, type CapabilityRequestPayloadMap, type CapabilityResponsePayloadMap, type ReadStreamRequestPayload, type ReadStreamResponsePayload, type ReadStreamSessionStatusWire, type TranscriptWindowResponsePayload, type ReadBoardRequestPayload, type ReadBoardView, type ReadBoardProjectSummary, type ReadBoardProjectListResponsePayload, type ReadBoardSnapshotResponsePayload, 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, } from './wire/payloads';
|
|
15
|
+
export { parseCapabilityRequestPayload, parseReadStreamResponsePayload, parseReadBoardResponsePayload, parseReadDiffResponsePayload, parseTranscriptWindowResponsePayload, parseRegisterPushRequestPayload, type CapabilityRequestPayloadMap, type CapabilityResponsePayloadMap, type ReadStreamRequestPayload, type ReadStreamResponsePayload, type ReadStreamSessionStatusWire, type TranscriptWindowResponsePayload, type ReadBoardRequestPayload, type ReadBoardView, type ReadBoardProjectSummary, 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, } from './wire/payloads';
|
|
16
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';
|
|
17
17
|
export { PAIRING_URI_SCHEME, encodePairingQrPayload, decodePairingQrPayload, type PairingQrPayload, } from './pairing/qr';
|
|
18
18
|
export { sealPairingConfirm, openPairingConfirm } from './pairing/confirm';
|
|
@@ -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, parseSessionEventWire, parseTerminalDimensionsWire, parseBoardColumnWire, parseBoardTaskWire, parseBacklogItemWire, parseDiffFileListWire, parseDiffFileContentWire, type TranscriptBlockWire, type TranscriptEntryWire, type TranscriptTurnUsageWire, type TranscriptSystemSubtypeWire, type ActivityStateWire, type ActivityReasonWire, type SessionUsageWire, type SessionEventWire, type TerminalDimensionsWire, type BoardColumnWire, 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, parseBacklogItemWire, parseDiffFileListWire, parseDiffFileContentWire, type TranscriptBlockWire, type TranscriptEntryWire, type TranscriptTurnUsageWire, type TranscriptSystemSubtypeWire, type ActivityStateWire, type ActivityReasonWire, type SessionUsageWire, type SessionSummaryWire, type SessionEventWire, type TerminalDimensionsWire, type BoardColumnWire, type BoardTaskWire, 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
|
@@ -5248,6 +5248,26 @@ function parseSessionUsageWire(payload) {
|
|
|
5248
5248
|
}
|
|
5249
5249
|
};
|
|
5250
5250
|
}
|
|
5251
|
+
function parseSessionSummaryWire(payload) {
|
|
5252
|
+
if (!isRecord(payload)) throw new Error("session summary payload must be an object");
|
|
5253
|
+
return {
|
|
5254
|
+
sessionId: requireString(payload, "sessionId", "session summary"),
|
|
5255
|
+
totalCostUsd: requireNumber(payload, "totalCostUsd", "session summary"),
|
|
5256
|
+
totalInputTokens: requireNumber(payload, "totalInputTokens", "session summary"),
|
|
5257
|
+
totalOutputTokens: requireNumber(payload, "totalOutputTokens", "session summary"),
|
|
5258
|
+
modelDisplayName: requireString(payload, "modelDisplayName", "session summary"),
|
|
5259
|
+
durationMs: requireNumber(payload, "durationMs", "session summary"),
|
|
5260
|
+
toolCallCount: requireNumber(payload, "toolCallCount", "session summary"),
|
|
5261
|
+
compactionCount: requireNumber(payload, "compactionCount", "session summary"),
|
|
5262
|
+
linesAdded: requireNumber(payload, "linesAdded", "session summary"),
|
|
5263
|
+
linesRemoved: requireNumber(payload, "linesRemoved", "session summary"),
|
|
5264
|
+
filesChanged: requireNumber(payload, "filesChanged", "session summary"),
|
|
5265
|
+
taskCreatedAt: requireString(payload, "taskCreatedAt", "session summary"),
|
|
5266
|
+
startedAt: requireString(payload, "startedAt", "session summary"),
|
|
5267
|
+
exitedAt: typeof payload.exitedAt === "string" ? payload.exitedAt : null,
|
|
5268
|
+
exitCode: typeof payload.exitCode === "number" ? payload.exitCode : null
|
|
5269
|
+
};
|
|
5270
|
+
}
|
|
5251
5271
|
function parseSessionEventWire(payload) {
|
|
5252
5272
|
if (!isRecord(payload)) throw new Error("session event payload must be an object");
|
|
5253
5273
|
return {
|
|
@@ -5450,6 +5470,18 @@ function parseAccentColor(value, context) {
|
|
|
5450
5470
|
}
|
|
5451
5471
|
function parseReadBoardResponsePayload(payload) {
|
|
5452
5472
|
if (!isRecord(payload)) throw new Error("read-board response must be an object");
|
|
5473
|
+
if (Array.isArray(payload.archivedTasks)) {
|
|
5474
|
+
if (typeof payload.projectId !== "string") throw new Error('read-board archived response is missing "projectId"');
|
|
5475
|
+
if (typeof payload.archivedTotalCount !== "number") {
|
|
5476
|
+
throw new Error('read-board archived response is missing "archivedTotalCount"');
|
|
5477
|
+
}
|
|
5478
|
+
return {
|
|
5479
|
+
projectId: payload.projectId,
|
|
5480
|
+
archivedTasks: payload.archivedTasks.map((task) => parseBoardTaskWire(task)),
|
|
5481
|
+
archivedTotalCount: payload.archivedTotalCount,
|
|
5482
|
+
summariesByTaskId: parseSummariesByTaskId(payload.summariesByTaskId)
|
|
5483
|
+
};
|
|
5484
|
+
}
|
|
5453
5485
|
if (Array.isArray(payload.projects)) {
|
|
5454
5486
|
const projects = payload.projects.map((project, index) => {
|
|
5455
5487
|
if (!isRecord(project) || typeof project.id !== "string" || typeof project.name !== "string") {
|
|
@@ -5494,18 +5526,42 @@ function parseTaskCountsByColumnId(value) {
|
|
|
5494
5526
|
}
|
|
5495
5527
|
return counts;
|
|
5496
5528
|
}
|
|
5529
|
+
function parseSummariesByTaskId(value) {
|
|
5530
|
+
if (value === void 0) return {};
|
|
5531
|
+
if (!isRecord(value)) throw new Error('read-board archived response has a non-object "summariesByTaskId"');
|
|
5532
|
+
const summaries = {};
|
|
5533
|
+
for (const [taskId, summary] of Object.entries(value)) {
|
|
5534
|
+
try {
|
|
5535
|
+
summaries[taskId] = parseSessionSummaryWire(summary);
|
|
5536
|
+
} catch {
|
|
5537
|
+
}
|
|
5538
|
+
}
|
|
5539
|
+
return summaries;
|
|
5540
|
+
}
|
|
5497
5541
|
function parseReadBoardRequestPayload(payload) {
|
|
5498
5542
|
if (!isRecord(payload)) throw new Error("read-board payload must be an object");
|
|
5499
5543
|
if (payload.projectId !== void 0 && typeof payload.projectId !== "string") {
|
|
5500
5544
|
throw new Error('read-board payload has a non-string "projectId"');
|
|
5501
5545
|
}
|
|
5502
|
-
if (payload.action !== void 0 && payload.action !== "subscribe" && payload.action !== "unsubscribe") {
|
|
5546
|
+
if (payload.action !== void 0 && payload.action !== "subscribe" && payload.action !== "unsubscribe" && payload.action !== "archived") {
|
|
5503
5547
|
throw new Error('read-board payload has an invalid "action"');
|
|
5504
5548
|
}
|
|
5505
5549
|
if (payload.view !== void 0 && payload.view !== "full" && payload.view !== "sessions") {
|
|
5506
5550
|
throw new Error('read-board payload has an invalid "view"');
|
|
5507
5551
|
}
|
|
5508
|
-
|
|
5552
|
+
if (payload.limit !== void 0 && (typeof payload.limit !== "number" || !Number.isInteger(payload.limit) || payload.limit < 1)) {
|
|
5553
|
+
throw new Error('read-board payload has an invalid "limit"');
|
|
5554
|
+
}
|
|
5555
|
+
if (payload.offset !== void 0 && (typeof payload.offset !== "number" || !Number.isInteger(payload.offset) || payload.offset < 0)) {
|
|
5556
|
+
throw new Error('read-board payload has an invalid "offset"');
|
|
5557
|
+
}
|
|
5558
|
+
return {
|
|
5559
|
+
projectId: payload.projectId,
|
|
5560
|
+
action: payload.action,
|
|
5561
|
+
view: payload.view,
|
|
5562
|
+
limit: payload.limit,
|
|
5563
|
+
offset: payload.offset
|
|
5564
|
+
};
|
|
5509
5565
|
}
|
|
5510
5566
|
function parseReadDiffResponsePayload(payload) {
|
|
5511
5567
|
if (!isRecord(payload)) throw new Error("read-diff response must be an object");
|
|
@@ -5826,6 +5882,7 @@ var BOARD_TOOL_READ_NAMES = [
|
|
|
5826
5882
|
"list_sessions",
|
|
5827
5883
|
"get_session_history",
|
|
5828
5884
|
"get_column_detail",
|
|
5885
|
+
"list_board_profiles",
|
|
5829
5886
|
"get_handoff_context",
|
|
5830
5887
|
"get_transcript",
|
|
5831
5888
|
"get_session_files",
|
|
@@ -5839,6 +5896,9 @@ var BOARD_TOOL_WRITE_NAMES = [
|
|
|
5839
5896
|
"link_pr",
|
|
5840
5897
|
"remove_attachment",
|
|
5841
5898
|
"update_column",
|
|
5899
|
+
"create_board_profile",
|
|
5900
|
+
"update_board_profile",
|
|
5901
|
+
"delete_board_profile",
|
|
5842
5902
|
"create_backlog_task",
|
|
5843
5903
|
"promote_backlog",
|
|
5844
5904
|
"update_backlog_item",
|
|
@@ -6005,6 +6065,7 @@ export {
|
|
|
6005
6065
|
parseReadStreamResponsePayload,
|
|
6006
6066
|
parseRegisterPushRequestPayload,
|
|
6007
6067
|
parseSessionEventWire,
|
|
6068
|
+
parseSessionSummaryWire,
|
|
6008
6069
|
parseSessionUsageWire,
|
|
6009
6070
|
parseTerminalDimensionsWire,
|
|
6010
6071
|
parseTranscriptEntriesWire,
|
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 SessionUsageWire, type TerminalDimensionsWire, type TranscriptEntryWire } from '../events/payloads';
|
|
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';
|
|
20
20
|
export interface ReadStreamRequestPayload {
|
|
21
21
|
sessionId: string;
|
|
22
22
|
/**
|
|
@@ -116,8 +116,24 @@ export declare function parseTranscriptWindowResponsePayload(payload: JsonValue)
|
|
|
116
116
|
export type ReadBoardView = 'full' | 'sessions';
|
|
117
117
|
export interface ReadBoardRequestPayload {
|
|
118
118
|
projectId?: string;
|
|
119
|
-
/**
|
|
120
|
-
|
|
119
|
+
/**
|
|
120
|
+
* Defaults to 'subscribe' when omitted. 'unsubscribe' only has an effect
|
|
121
|
+
* when projectId is set - the no-projectId project list is a one-shot read
|
|
122
|
+
* with no live feed to tear down.
|
|
123
|
+
*
|
|
124
|
+
* 'archived' (protocol 0.10.0) is a one-shot page of the project's COMPLETED
|
|
125
|
+
* tasks, which no other projection carries: both 'full' and 'sessions' are
|
|
126
|
+
* built from the desktop's non-archived task list. It is deliberately not a
|
|
127
|
+
* field on the snapshot, because a board subscription re-snapshots on every
|
|
128
|
+
* board change - archived tasks would then repeat down the wire forever,
|
|
129
|
+
* which is the exact bloat the 0.9.0 projections removed. Completed work
|
|
130
|
+
* changes rarely and is read on demand.
|
|
131
|
+
*/
|
|
132
|
+
action?: 'subscribe' | 'unsubscribe' | 'archived';
|
|
133
|
+
/** 'archived' only: page size, newest-archived first. The desktop clamps it. */
|
|
134
|
+
limit?: number;
|
|
135
|
+
/** 'archived' only: how many newest to skip, for paging. Defaults to 0. */
|
|
136
|
+
offset?: number;
|
|
121
137
|
/**
|
|
122
138
|
* subscribe only: the projection wanted (protocol 0.9.0). Omitted means the
|
|
123
139
|
* legacy full board WITH the backlog.
|
|
@@ -179,8 +195,33 @@ export interface ReadBoardSnapshotResponsePayload {
|
|
|
179
195
|
*/
|
|
180
196
|
taskCountsByColumnId?: Record<string, number>;
|
|
181
197
|
}
|
|
182
|
-
|
|
183
|
-
|
|
198
|
+
/**
|
|
199
|
+
* Returned for `action: 'archived'` - one page of a project's completed tasks
|
|
200
|
+
* (protocol 0.10.0).
|
|
201
|
+
*
|
|
202
|
+
* These never appear in a board snapshot: the desktop builds those from its
|
|
203
|
+
* non-archived task list, so a phone that only ever subscribed has no way to
|
|
204
|
+
* know a completed task exists at all.
|
|
205
|
+
*/
|
|
206
|
+
export interface ReadBoardArchivedResponsePayload {
|
|
207
|
+
projectId: string;
|
|
208
|
+
/** Newest-archived first. At most the requested `limit`. */
|
|
209
|
+
archivedTasks: BoardTaskWire[];
|
|
210
|
+
/**
|
|
211
|
+
* Total archived tasks in the project, NOT the length of the page above.
|
|
212
|
+
* Drives the column count and tells the phone whether another page exists.
|
|
213
|
+
*/
|
|
214
|
+
archivedTotalCount: number;
|
|
215
|
+
/**
|
|
216
|
+
* Lifetime cost/duration/churn per task id, for the tasks on THIS page that
|
|
217
|
+
* have recorded metrics. Sparse on purpose: a task archived without ever
|
|
218
|
+
* running an agent has nothing to summarize and is simply absent, which is
|
|
219
|
+
* not an error.
|
|
220
|
+
*/
|
|
221
|
+
summariesByTaskId: Record<string, SessionSummaryWire>;
|
|
222
|
+
}
|
|
223
|
+
export type ReadBoardResponsePayload = ReadBoardProjectListResponsePayload | ReadBoardSnapshotResponsePayload | ReadBoardArchivedResponsePayload;
|
|
224
|
+
/** Phone-side narrowing of a read-board response (project list, board snapshot, or archived page). Throws on a malformed required field. */
|
|
184
225
|
export declare function parseReadBoardResponsePayload(payload: JsonValue): ReadBoardResponsePayload;
|
|
185
226
|
/** 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. */
|
|
186
227
|
export type ReadDiffScope = 'working' | 'staged' | 'branch';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kangentic/protocol",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.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",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
],
|
|
26
26
|
"author": {
|
|
27
27
|
"name": "Kangentic",
|
|
28
|
+
"email": "hello@kangentic.com",
|
|
28
29
|
"url": "https://github.com/Kangentic"
|
|
29
30
|
},
|
|
30
31
|
"license": "AGPL-3.0-only",
|