@ccmsg/protocol 1.7.0 → 1.9.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/package.json +3 -2
- package/src/common/auth.ts +15 -1
- package/src/fixtures/common.ts +305 -0
- package/src/fixtures/control.ts +557 -0
- package/src/fixtures/envelope.ts +15 -0
- package/src/fixtures/ids.ts +19 -0
- package/src/fixtures/index.ts +166 -0
- package/src/fixtures/messaging.ts +83 -0
- package/src/fixtures/topics.ts +438 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import type { OpName } from "../attributes.ts";
|
|
2
|
+
import type { TopicKind } from "../common/topics.ts";
|
|
3
|
+
import * as common from "./common.ts";
|
|
4
|
+
import * as control from "./control.ts";
|
|
5
|
+
import * as messaging from "./messaging.ts";
|
|
6
|
+
import * as topics from "./topics.ts";
|
|
7
|
+
|
|
8
|
+
export * from "./common.ts";
|
|
9
|
+
export * from "./control.ts";
|
|
10
|
+
export * from "./envelope.ts";
|
|
11
|
+
export * from "./ids.ts";
|
|
12
|
+
export * from "./messaging.ts";
|
|
13
|
+
export * from "./topics.ts";
|
|
14
|
+
|
|
15
|
+
/** One request and one reply, as they travel. */
|
|
16
|
+
export interface OpFixture {
|
|
17
|
+
readonly request: unknown;
|
|
18
|
+
readonly response: unknown;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** A representative frame for every op in the contract.
|
|
22
|
+
*
|
|
23
|
+
* These are the contract's own examples of its wire: an implementation checks
|
|
24
|
+
* itself against them rather than writing its own copy of what a frame looks
|
|
25
|
+
* like, which is the same reason the schemas live here and not in each
|
|
26
|
+
* implementation. Every one of them passes the op's schema, which the
|
|
27
|
+
* contract's tests hold it to. */
|
|
28
|
+
export const OP_FIXTURES = {
|
|
29
|
+
hello: { request: common.HELLO_REQUEST, response: common.HELLO_RESPONSE },
|
|
30
|
+
instance_ping: {
|
|
31
|
+
request: common.INSTANCE_PING_REQUEST,
|
|
32
|
+
response: common.INSTANCE_PING_RESPONSE,
|
|
33
|
+
},
|
|
34
|
+
instance_shutdown: {
|
|
35
|
+
request: common.INSTANCE_SHUTDOWN_REQUEST,
|
|
36
|
+
response: common.INSTANCE_SHUTDOWN_RESPONSE,
|
|
37
|
+
},
|
|
38
|
+
session_stopping: {
|
|
39
|
+
request: common.SESSION_STOPPING_REQUEST,
|
|
40
|
+
response: common.SESSION_STOPPING_RESPONSE,
|
|
41
|
+
},
|
|
42
|
+
topic_subscribe: {
|
|
43
|
+
request: common.TOPIC_SUBSCRIBE_REQUEST,
|
|
44
|
+
response: common.TOPIC_SUBSCRIBE_RESPONSE,
|
|
45
|
+
},
|
|
46
|
+
topic_unsubscribe: {
|
|
47
|
+
request: common.TOPIC_UNSUBSCRIBE_REQUEST,
|
|
48
|
+
response: common.TOPIC_UNSUBSCRIBE_RESPONSE,
|
|
49
|
+
},
|
|
50
|
+
auth_challenge: {
|
|
51
|
+
request: common.AUTH_CHALLENGE_REQUEST,
|
|
52
|
+
response: common.AUTH_CHALLENGE_RESPONSE,
|
|
53
|
+
},
|
|
54
|
+
auth_register: {
|
|
55
|
+
request: common.AUTH_REGISTER_REQUEST,
|
|
56
|
+
response: common.AUTH_REGISTER_RESPONSE,
|
|
57
|
+
},
|
|
58
|
+
auth_assert: { request: common.AUTH_ASSERT_REQUEST, response: common.AUTH_ASSERT_RESPONSE },
|
|
59
|
+
auth_refresh_token: {
|
|
60
|
+
request: common.AUTH_REFRESH_TOKEN_REQUEST,
|
|
61
|
+
response: common.AUTH_REFRESH_TOKEN_RESPONSE,
|
|
62
|
+
},
|
|
63
|
+
auth_refresh: { request: common.AUTH_REFRESH_REQUEST, response: common.AUTH_REFRESH_RESPONSE },
|
|
64
|
+
auth_resolve: { request: common.AUTH_RESOLVE_REQUEST, response: common.AUTH_RESOLVE_RESPONSE },
|
|
65
|
+
auth_rotate: { request: common.AUTH_ROTATE_REQUEST, response: common.AUTH_ROTATE_RESPONSE },
|
|
66
|
+
|
|
67
|
+
message_send: {
|
|
68
|
+
request: messaging.MESSAGE_SEND_REQUEST,
|
|
69
|
+
response: messaging.MESSAGE_SEND_RESPONSE,
|
|
70
|
+
},
|
|
71
|
+
say_post: { request: messaging.SAY_POST_REQUEST, response: messaging.SAY_POST_RESPONSE },
|
|
72
|
+
say_mark_read: {
|
|
73
|
+
request: messaging.SAY_MARK_READ_REQUEST,
|
|
74
|
+
response: messaging.SAY_MARK_READ_RESPONSE,
|
|
75
|
+
},
|
|
76
|
+
notify_send: { request: messaging.NOTIFY_SEND_REQUEST, response: messaging.NOTIFY_SEND_RESPONSE },
|
|
77
|
+
|
|
78
|
+
session_kill: { request: control.SESSION_KILL_REQUEST, response: control.SESSION_KILL_RESPONSE },
|
|
79
|
+
session_rename: {
|
|
80
|
+
request: control.SESSION_RENAME_REQUEST,
|
|
81
|
+
response: control.SESSION_RENAME_RESPONSE,
|
|
82
|
+
},
|
|
83
|
+
session_env_read: {
|
|
84
|
+
request: control.SESSION_ENV_READ_REQUEST,
|
|
85
|
+
response: control.SESSION_ENV_READ_RESPONSE,
|
|
86
|
+
},
|
|
87
|
+
session_search: {
|
|
88
|
+
request: control.SESSION_SEARCH_REQUEST,
|
|
89
|
+
response: control.SESSION_SEARCH_RESPONSE,
|
|
90
|
+
},
|
|
91
|
+
session_dump_write: {
|
|
92
|
+
request: control.SESSION_DUMP_WRITE_REQUEST,
|
|
93
|
+
response: control.SESSION_DUMP_WRITE_RESPONSE,
|
|
94
|
+
},
|
|
95
|
+
transcript_read: {
|
|
96
|
+
request: control.TRANSCRIPT_READ_REQUEST,
|
|
97
|
+
response: control.TRANSCRIPT_READ_RESPONSE,
|
|
98
|
+
},
|
|
99
|
+
session_fork_origin: {
|
|
100
|
+
request: control.SESSION_FORK_ORIGIN_REQUEST,
|
|
101
|
+
response: control.SESSION_FORK_ORIGIN_RESPONSE,
|
|
102
|
+
},
|
|
103
|
+
session_last_live_remove: {
|
|
104
|
+
request: control.SESSION_LAST_LIVE_REMOVE_REQUEST,
|
|
105
|
+
response: control.SESSION_LAST_LIVE_REMOVE_RESPONSE,
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
dir_list: { request: control.DIR_LIST_REQUEST, response: control.DIR_LIST_RESPONSE },
|
|
109
|
+
file_read: { request: control.FILE_READ_REQUEST, response: control.FILE_READ_RESPONSE },
|
|
110
|
+
file_write: { request: control.FILE_WRITE_REQUEST, response: control.FILE_WRITE_RESPONSE },
|
|
111
|
+
file_create: { request: control.FILE_CREATE_REQUEST, response: control.FILE_CREATE_RESPONSE },
|
|
112
|
+
file_edit: { request: control.FILE_EDIT_REQUEST, response: control.FILE_EDIT_RESPONSE },
|
|
113
|
+
file_delete: { request: control.FILE_DELETE_REQUEST, response: control.FILE_DELETE_RESPONSE },
|
|
114
|
+
file_find: { request: control.FILE_FIND_REQUEST, response: control.FILE_FIND_RESPONSE },
|
|
115
|
+
file_stat_batch: {
|
|
116
|
+
request: control.FILE_STAT_BATCH_REQUEST,
|
|
117
|
+
response: control.FILE_STAT_BATCH_RESPONSE,
|
|
118
|
+
},
|
|
119
|
+
dir_tree: { request: control.DIR_TREE_REQUEST, response: control.DIR_TREE_RESPONSE },
|
|
120
|
+
|
|
121
|
+
launcher_config_read: {
|
|
122
|
+
request: control.LAUNCHER_CONFIG_READ_REQUEST,
|
|
123
|
+
response: control.LAUNCHER_CONFIG_READ_RESPONSE,
|
|
124
|
+
},
|
|
125
|
+
launcher_run: { request: control.LAUNCHER_RUN_REQUEST, response: control.LAUNCHER_RUN_RESPONSE },
|
|
126
|
+
sandbox_grant: {
|
|
127
|
+
request: control.SANDBOX_GRANT_REQUEST,
|
|
128
|
+
response: control.SANDBOX_GRANT_RESPONSE,
|
|
129
|
+
},
|
|
130
|
+
sandbox_revoke: {
|
|
131
|
+
request: control.SANDBOX_REVOKE_REQUEST,
|
|
132
|
+
response: control.SANDBOX_REVOKE_RESPONSE,
|
|
133
|
+
},
|
|
134
|
+
translate_run: {
|
|
135
|
+
request: control.TRANSLATE_RUN_REQUEST,
|
|
136
|
+
response: control.TRANSLATE_RUN_RESPONSE,
|
|
137
|
+
},
|
|
138
|
+
llm_usage_read: {
|
|
139
|
+
request: control.LLM_USAGE_READ_REQUEST,
|
|
140
|
+
response: control.LLM_USAGE_READ_RESPONSE,
|
|
141
|
+
},
|
|
142
|
+
llm_stats_read: {
|
|
143
|
+
request: control.LLM_STATS_READ_REQUEST,
|
|
144
|
+
response: control.LLM_STATS_READ_RESPONSE,
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
kv_read: { request: control.KV_READ_REQUEST, response: control.KV_READ_RESPONSE },
|
|
148
|
+
kv_write: { request: control.KV_WRITE_REQUEST, response: control.KV_WRITE_RESPONSE },
|
|
149
|
+
kv_delete: { request: control.KV_DELETE_REQUEST, response: control.KV_DELETE_RESPONSE },
|
|
150
|
+
} as const satisfies Record<OpName, OpFixture>;
|
|
151
|
+
|
|
152
|
+
/** A representative frame for every topic, each one the snapshot a subscriber
|
|
153
|
+
* opens with or a change of the same shape. */
|
|
154
|
+
export const TOPIC_FIXTURES = {
|
|
155
|
+
inbox: topics.INBOX_FRAME,
|
|
156
|
+
notify: topics.NOTIFY_FRAME,
|
|
157
|
+
peers: topics.PEERS_FRAME,
|
|
158
|
+
agents: topics.AGENTS_FRAME,
|
|
159
|
+
session_status: topics.SESSION_STATUS_FRAME,
|
|
160
|
+
transcript: topics.TRANSCRIPT_FRAME,
|
|
161
|
+
session_errors: topics.SESSION_ERRORS_FRAME,
|
|
162
|
+
llm_requests: topics.LLM_REQUESTS_FRAME,
|
|
163
|
+
llm_status: topics.LLM_STATUS_FRAME,
|
|
164
|
+
kv: topics.KV_FRAME,
|
|
165
|
+
auth_records: topics.AUTH_RECORDS_FRAME,
|
|
166
|
+
} as const satisfies Record<TopicKind, unknown>;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { Static } from "@sinclair/typebox";
|
|
2
|
+
import type { MessageSendRequest, MessageSendResponse } from "../messaging/message.ts";
|
|
3
|
+
import type { NotifySendRequest, NotifySendResponse } from "../messaging/notify.ts";
|
|
4
|
+
import type {
|
|
5
|
+
SayMarkReadRequest,
|
|
6
|
+
SayMarkReadResponse,
|
|
7
|
+
SayPostRequest,
|
|
8
|
+
SayPostResponse,
|
|
9
|
+
} from "../messaging/say.ts";
|
|
10
|
+
import { FIXTURE_IDS, FIXTURE_NOW } from "./ids.ts";
|
|
11
|
+
|
|
12
|
+
const { sid, other_sid, instance, mid, request_id } = FIXTURE_IDS;
|
|
13
|
+
|
|
14
|
+
export const MESSAGE_SEND_REQUEST: Static<typeof MessageSendRequest> = {
|
|
15
|
+
request_id,
|
|
16
|
+
op: "message_send",
|
|
17
|
+
to: other_sid,
|
|
18
|
+
text: "契約の fixture を export した",
|
|
19
|
+
reply_to: mid,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/** A send that crossed instances, which is the same op wrapped in the mesh
|
|
23
|
+
* fields and the identity it was called with. */
|
|
24
|
+
export const MESSAGE_SEND_FORWARDED_REQUEST: Static<typeof MessageSendRequest> = {
|
|
25
|
+
request_id,
|
|
26
|
+
op: "message_send",
|
|
27
|
+
to: other_sid,
|
|
28
|
+
text: "契約の fixture を export した",
|
|
29
|
+
from_instance: instance,
|
|
30
|
+
hops: [instance],
|
|
31
|
+
caller: { role: "session", sid },
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const MESSAGE_SEND_RESPONSE: Static<typeof MessageSendResponse> = {
|
|
35
|
+
ok: true,
|
|
36
|
+
request_id,
|
|
37
|
+
delivered: true,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/** The reply when nobody took it: the reason, and where the recipient might
|
|
41
|
+
* be instead. */
|
|
42
|
+
export const MESSAGE_SEND_HELD_RESPONSE: Static<typeof MessageSendResponse> = {
|
|
43
|
+
ok: true,
|
|
44
|
+
request_id,
|
|
45
|
+
delivered: false,
|
|
46
|
+
reason: "disappeared",
|
|
47
|
+
candidates: [{ sid, ws: "main", instance }],
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const SAY_POST_REQUEST: Static<typeof SayPostRequest> = {
|
|
51
|
+
request_id,
|
|
52
|
+
op: "say_post",
|
|
53
|
+
text: "終わりました",
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const SAY_POST_RESPONSE: Static<typeof SayPostResponse> = {
|
|
57
|
+
ok: true,
|
|
58
|
+
request_id,
|
|
59
|
+
posted_at: FIXTURE_NOW,
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const SAY_MARK_READ_REQUEST: Static<typeof SayMarkReadRequest> = {
|
|
63
|
+
request_id,
|
|
64
|
+
op: "say_mark_read",
|
|
65
|
+
sid,
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const SAY_MARK_READ_RESPONSE: Static<typeof SayMarkReadResponse> = {
|
|
69
|
+
ok: true,
|
|
70
|
+
request_id,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const NOTIFY_SEND_REQUEST: Static<typeof NotifySendRequest> = {
|
|
74
|
+
request_id,
|
|
75
|
+
op: "notify_send",
|
|
76
|
+
sid,
|
|
77
|
+
text: "確認して",
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export const NOTIFY_SEND_RESPONSE: Static<typeof NotifySendResponse> = {
|
|
81
|
+
ok: true,
|
|
82
|
+
request_id,
|
|
83
|
+
};
|
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
import type { Static } from "@sinclair/typebox";
|
|
2
|
+
import type { AuthRecordsFrame } from "../common/auth.ts";
|
|
3
|
+
import type { AgentsFrame } from "../control/agents.ts";
|
|
4
|
+
import type { KvFrame } from "../control/kv.ts";
|
|
5
|
+
import type { LlmRequestsFrame, LlmStatusFrame } from "../control/llm.ts";
|
|
6
|
+
import type { PeersFrame } from "../control/peers.ts";
|
|
7
|
+
import type { SessionErrorsFrame } from "../control/session-errors.ts";
|
|
8
|
+
import type { SessionStatusFrame } from "../control/session-status.ts";
|
|
9
|
+
import type { TranscriptFrame } from "../control/transcript.ts";
|
|
10
|
+
import type { InboxFrame } from "../messaging/message.ts";
|
|
11
|
+
import type { NotifyFrame } from "../messaging/notify.ts";
|
|
12
|
+
import { FIXTURE_IDS, FIXTURE_NOW } from "./ids.ts";
|
|
13
|
+
|
|
14
|
+
const { sid, other_sid, instance, other_instance, endpoint, other_endpoint, mid } = FIXTURE_IDS;
|
|
15
|
+
|
|
16
|
+
const WORKSPACE = "/repos/kawaz/ccmsg-protocol/main";
|
|
17
|
+
|
|
18
|
+
export const INBOX_FRAME: Static<typeof InboxFrame> = {
|
|
19
|
+
ev: "topic",
|
|
20
|
+
topic: "inbox",
|
|
21
|
+
snapshot: true,
|
|
22
|
+
instance,
|
|
23
|
+
data: [
|
|
24
|
+
{
|
|
25
|
+
mid,
|
|
26
|
+
from: other_sid,
|
|
27
|
+
from_label: "contract-fixtures",
|
|
28
|
+
text: "fixture を export した",
|
|
29
|
+
sent_at: FIXTURE_NOW,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
mid: `${instance}/1842`,
|
|
33
|
+
from: "user",
|
|
34
|
+
from_label: "kawaz",
|
|
35
|
+
text: "確認する",
|
|
36
|
+
reply_to: mid,
|
|
37
|
+
sent_at: FIXTURE_NOW + 1_000,
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const NOTIFY_FRAME: Static<typeof NotifyFrame> = {
|
|
43
|
+
ev: "topic",
|
|
44
|
+
topic: "notify",
|
|
45
|
+
instance,
|
|
46
|
+
data: { sid, sid_label: "contract-fixtures", text: "確認して", sent_at: FIXTURE_NOW },
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const PEER = {
|
|
50
|
+
sid,
|
|
51
|
+
instance,
|
|
52
|
+
repo: "ccmsg-protocol",
|
|
53
|
+
ws: "main",
|
|
54
|
+
cwd: WORKSPACE,
|
|
55
|
+
protocol_version: 3,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const PEERS_FRAME: Static<typeof PeersFrame> = {
|
|
59
|
+
ev: "topic",
|
|
60
|
+
topic: "peers",
|
|
61
|
+
snapshot: true,
|
|
62
|
+
instance,
|
|
63
|
+
data: {
|
|
64
|
+
peers: [
|
|
65
|
+
{
|
|
66
|
+
...PEER,
|
|
67
|
+
transcript_path: "/transcripts/6f1a2b3c.jsonl",
|
|
68
|
+
repo_root: "/repos/kawaz/ccmsg-protocol",
|
|
69
|
+
branch: "main",
|
|
70
|
+
title: "contract fixtures",
|
|
71
|
+
state: "live",
|
|
72
|
+
pinned: true,
|
|
73
|
+
connected_at: FIXTURE_NOW - 600_000,
|
|
74
|
+
last_activity_at: FIXTURE_NOW,
|
|
75
|
+
last_user_input_at: FIXTURE_NOW - 60_000,
|
|
76
|
+
gateway_active_at: FIXTURE_NOW,
|
|
77
|
+
send_message: true,
|
|
78
|
+
client_version: "0.1.0",
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
...PEER,
|
|
82
|
+
sid: other_sid,
|
|
83
|
+
state: "live_unmanaged",
|
|
84
|
+
stale_client: {
|
|
85
|
+
last_seen_at: FIXTURE_NOW - 300_000,
|
|
86
|
+
version: "0.0.9",
|
|
87
|
+
protocol_version: 2,
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
last_live: [
|
|
92
|
+
{
|
|
93
|
+
sid: other_sid,
|
|
94
|
+
instance,
|
|
95
|
+
repo: "ccmsg",
|
|
96
|
+
ws: "daemon-v2",
|
|
97
|
+
cwd: "/repos/kawaz/ccmsg/daemon-v2",
|
|
98
|
+
state: "paused",
|
|
99
|
+
last_seen_at: FIXTURE_NOW - 1_200_000,
|
|
100
|
+
stopped_at: FIXTURE_NOW - 1_000_000,
|
|
101
|
+
model: "claude-opus-5",
|
|
102
|
+
effort: "high",
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
instances: [
|
|
106
|
+
{ id: instance, endpoint, host: "mba", reachable: true },
|
|
107
|
+
{ id: other_instance, endpoint: other_endpoint, host: "nuc", reachable: false },
|
|
108
|
+
],
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export const AGENTS_FRAME: Static<typeof AgentsFrame> = {
|
|
113
|
+
ev: "topic",
|
|
114
|
+
topic: "agents",
|
|
115
|
+
snapshot: true,
|
|
116
|
+
instance,
|
|
117
|
+
data: {
|
|
118
|
+
agents: [
|
|
119
|
+
{
|
|
120
|
+
sid,
|
|
121
|
+
instance,
|
|
122
|
+
pid: 4821,
|
|
123
|
+
cwd: WORKSPACE,
|
|
124
|
+
kind: "claude",
|
|
125
|
+
started_at: FIXTURE_NOW - 600_000,
|
|
126
|
+
name: "contract-fixtures",
|
|
127
|
+
status: "working",
|
|
128
|
+
state: "busy",
|
|
129
|
+
config_dir: "/config/claude-personal",
|
|
130
|
+
terminal_id: "%17",
|
|
131
|
+
terminal_namespace: "personal",
|
|
132
|
+
},
|
|
133
|
+
],
|
|
134
|
+
polled_at: FIXTURE_NOW,
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
export const SESSION_STATUS_FRAME: Static<typeof SessionStatusFrame> = {
|
|
139
|
+
ev: "topic",
|
|
140
|
+
topic: `session_status:${sid}`,
|
|
141
|
+
snapshot: true,
|
|
142
|
+
instance,
|
|
143
|
+
data: {
|
|
144
|
+
sid,
|
|
145
|
+
todos: [
|
|
146
|
+
{
|
|
147
|
+
id: "1",
|
|
148
|
+
subject: "fixture を export する",
|
|
149
|
+
status: "in_progress",
|
|
150
|
+
owner: "contract-fixtures",
|
|
151
|
+
blocked_by: [],
|
|
152
|
+
blocks: ["2"],
|
|
153
|
+
},
|
|
154
|
+
],
|
|
155
|
+
workflows: [
|
|
156
|
+
{
|
|
157
|
+
task_id: "w1",
|
|
158
|
+
name: "contract fixtures",
|
|
159
|
+
summary: "export the wire fixtures",
|
|
160
|
+
status: "running",
|
|
161
|
+
started_at: FIXTURE_NOW - 600_000,
|
|
162
|
+
run_id: "r1",
|
|
163
|
+
phases: [{ title: "write", done: 1, total: 2 }],
|
|
164
|
+
agents: [
|
|
165
|
+
{
|
|
166
|
+
agent_id: "a1",
|
|
167
|
+
label: "writer",
|
|
168
|
+
model: "claude-opus-5",
|
|
169
|
+
agent_type: "worker",
|
|
170
|
+
state: "running",
|
|
171
|
+
tokens: 48_000,
|
|
172
|
+
tool_calls: 12,
|
|
173
|
+
phase_index: 0,
|
|
174
|
+
phase_title: "write",
|
|
175
|
+
last_tool: "Write",
|
|
176
|
+
started_at: FIXTURE_NOW - 300_000,
|
|
177
|
+
duration_ms: 300_000,
|
|
178
|
+
},
|
|
179
|
+
],
|
|
180
|
+
},
|
|
181
|
+
],
|
|
182
|
+
background: [
|
|
183
|
+
{
|
|
184
|
+
task_id: "b1",
|
|
185
|
+
kind: "bash",
|
|
186
|
+
description: "just ci",
|
|
187
|
+
status: "running",
|
|
188
|
+
started_at: FIXTURE_NOW - 60_000,
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
teammates: [
|
|
192
|
+
{
|
|
193
|
+
name: "contract-fixtures",
|
|
194
|
+
spawned: true,
|
|
195
|
+
agent_type: "worker",
|
|
196
|
+
color: "cyan",
|
|
197
|
+
spawned_at: FIXTURE_NOW - 600_000,
|
|
198
|
+
last_sent_at: FIXTURE_NOW - 60_000,
|
|
199
|
+
last_received_at: FIXTURE_NOW,
|
|
200
|
+
state: "busy",
|
|
201
|
+
model: "claude-opus-5",
|
|
202
|
+
},
|
|
203
|
+
],
|
|
204
|
+
agent_tree: {
|
|
205
|
+
teammates: [
|
|
206
|
+
{
|
|
207
|
+
agent_id: "a1",
|
|
208
|
+
teammate_name: "contract-fixtures",
|
|
209
|
+
agent_type: "worker",
|
|
210
|
+
description: "export the wire fixtures",
|
|
211
|
+
color: "cyan",
|
|
212
|
+
model: "claude-opus-5",
|
|
213
|
+
spawn_depth: 0,
|
|
214
|
+
kind: "teammate",
|
|
215
|
+
state: "busy",
|
|
216
|
+
last_activity_at: FIXTURE_NOW,
|
|
217
|
+
children: [],
|
|
218
|
+
},
|
|
219
|
+
],
|
|
220
|
+
agents: [],
|
|
221
|
+
workflows: [
|
|
222
|
+
{
|
|
223
|
+
workflow_id: "w1",
|
|
224
|
+
done: 1,
|
|
225
|
+
total: 2,
|
|
226
|
+
phases: [{ index: 1, title: "write", done: 1, total: 2, members: [] }],
|
|
227
|
+
unassigned: [],
|
|
228
|
+
last_activity_at: FIXTURE_NOW,
|
|
229
|
+
},
|
|
230
|
+
],
|
|
231
|
+
},
|
|
232
|
+
external_files: [{ path: "/transcripts/6f1a2b3c.jsonl", origin: "tool" }],
|
|
233
|
+
workspace_folders: [{ name: "main", path: WORKSPACE }],
|
|
234
|
+
context: {
|
|
235
|
+
tokens: 148_000,
|
|
236
|
+
model: "claude-opus-5",
|
|
237
|
+
effort: "high",
|
|
238
|
+
observed_at: FIXTURE_NOW,
|
|
239
|
+
},
|
|
240
|
+
api_error: { text: "overloaded_error", occurred_at: FIXTURE_NOW - 30_000 },
|
|
241
|
+
},
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
export const TRANSCRIPT_FRAME = {
|
|
245
|
+
ev: "topic",
|
|
246
|
+
topic: `transcript:${sid}`,
|
|
247
|
+
instance,
|
|
248
|
+
data: {
|
|
249
|
+
sid,
|
|
250
|
+
lines: ['{"type":"assistant","text":"fixture を export した"}'],
|
|
251
|
+
start: 182_300,
|
|
252
|
+
end: 182_400,
|
|
253
|
+
size: 182_400,
|
|
254
|
+
},
|
|
255
|
+
} satisfies Static<typeof TranscriptFrame>;
|
|
256
|
+
|
|
257
|
+
/** The opening frame of the topic, which states how far the transcript has
|
|
258
|
+
* been written without carrying any of it. */
|
|
259
|
+
export const TRANSCRIPT_SIZE_FRAME = {
|
|
260
|
+
ev: "topic",
|
|
261
|
+
topic: `transcript:${sid}`,
|
|
262
|
+
snapshot: true,
|
|
263
|
+
instance,
|
|
264
|
+
data: { sid, size: 182_400 },
|
|
265
|
+
} satisfies Static<typeof TranscriptFrame>;
|
|
266
|
+
|
|
267
|
+
export const SESSION_ERRORS_FRAME: Static<typeof SessionErrorsFrame> = {
|
|
268
|
+
ev: "topic",
|
|
269
|
+
topic: "session_errors",
|
|
270
|
+
snapshot: true,
|
|
271
|
+
instance,
|
|
272
|
+
data: {
|
|
273
|
+
errors: [{ sid, instance, text: "overloaded_error", occurred_at: FIXTURE_NOW - 30_000 }],
|
|
274
|
+
},
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
export const LLM_REQUESTS_FRAME: Static<typeof LlmRequestsFrame> = {
|
|
278
|
+
ev: "topic",
|
|
279
|
+
topic: "llm_requests",
|
|
280
|
+
snapshot: true,
|
|
281
|
+
instance,
|
|
282
|
+
data: [
|
|
283
|
+
{
|
|
284
|
+
received_at: FIXTURE_NOW,
|
|
285
|
+
sid,
|
|
286
|
+
instance,
|
|
287
|
+
prefix: "contract",
|
|
288
|
+
main: true,
|
|
289
|
+
cache_expires_at: FIXTURE_NOW + 300_000,
|
|
290
|
+
cache_ttl_secs: 300,
|
|
291
|
+
cache_since_at: FIXTURE_NOW - 600_000,
|
|
292
|
+
cache_count: 8,
|
|
293
|
+
next_keepalive_at: FIXTURE_NOW + 240_000,
|
|
294
|
+
ns: "personal",
|
|
295
|
+
model: "claude-opus-5",
|
|
296
|
+
credential: "personal",
|
|
297
|
+
status: 200,
|
|
298
|
+
},
|
|
299
|
+
],
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
export const LLM_STATUS_FRAME: Static<typeof LlmStatusFrame> = {
|
|
303
|
+
ev: "topic",
|
|
304
|
+
topic: "llm_status",
|
|
305
|
+
snapshot: true,
|
|
306
|
+
instance,
|
|
307
|
+
data: {
|
|
308
|
+
schema_version: 1,
|
|
309
|
+
generated_at: FIXTURE_NOW,
|
|
310
|
+
overall: { severity: "ok", service_counts: { ok: 1, warning: 0, critical: 0, unknown: 0 } },
|
|
311
|
+
services: [
|
|
312
|
+
{
|
|
313
|
+
id: "anthropic",
|
|
314
|
+
name: "Anthropic",
|
|
315
|
+
severity: "ok",
|
|
316
|
+
routes: ["/v1/messages"],
|
|
317
|
+
official: {
|
|
318
|
+
state: "operational",
|
|
319
|
+
source: "status page",
|
|
320
|
+
source_url: "https://status.example.com/",
|
|
321
|
+
observed_at: FIXTURE_NOW,
|
|
322
|
+
components: [{ id: "api", name: "API", state: "operational" }],
|
|
323
|
+
incidents: [],
|
|
324
|
+
},
|
|
325
|
+
observed: {
|
|
326
|
+
state: "reachable",
|
|
327
|
+
observed_at: FIXTURE_NOW,
|
|
328
|
+
expires_at: FIXTURE_NOW + 60_000,
|
|
329
|
+
last_success_at: FIXTURE_NOW,
|
|
330
|
+
},
|
|
331
|
+
},
|
|
332
|
+
],
|
|
333
|
+
},
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
export const KV_FRAME: Static<typeof KvFrame> = {
|
|
337
|
+
ev: "topic",
|
|
338
|
+
topic: "kv:webui",
|
|
339
|
+
snapshot: true,
|
|
340
|
+
instance,
|
|
341
|
+
data: {
|
|
342
|
+
entries: [
|
|
343
|
+
{ key: "layout", value: { pane: "peers", collapsed: false }, updated_at: FIXTURE_NOW },
|
|
344
|
+
{ key: "draft", updated_at: FIXTURE_NOW + 1_000, deleted: true },
|
|
345
|
+
],
|
|
346
|
+
},
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
export const AUTH_RECORDS_FRAME = {
|
|
350
|
+
ev: "topic",
|
|
351
|
+
topic: "auth_records",
|
|
352
|
+
snapshot: true,
|
|
353
|
+
instance,
|
|
354
|
+
data: {
|
|
355
|
+
records: [
|
|
356
|
+
{
|
|
357
|
+
key: "credential/personal-1/Y3JlZC1pZA",
|
|
358
|
+
updated_at: FIXTURE_NOW,
|
|
359
|
+
body: {
|
|
360
|
+
kind: "credential",
|
|
361
|
+
sub: "personal-1",
|
|
362
|
+
credential_id: "Y3JlZC1pZA",
|
|
363
|
+
public_key: "pQECAyYgASFYIA",
|
|
364
|
+
user_handle: "dXNlci1oYW5kbGU",
|
|
365
|
+
endpoint,
|
|
366
|
+
rp_id: "mba.example.ts.net",
|
|
367
|
+
sign_count: 0,
|
|
368
|
+
issued_label: "for kawaz",
|
|
369
|
+
device_label: "work laptop",
|
|
370
|
+
registered_at: FIXTURE_NOW - 600_000,
|
|
371
|
+
registered_ip: "203.0.113.7",
|
|
372
|
+
registered_user_agent: "Mozilla/5.0",
|
|
373
|
+
last_used_at: FIXTURE_NOW,
|
|
374
|
+
last_used_ip: "203.0.113.7",
|
|
375
|
+
last_used_user_agent: "Mozilla/5.0",
|
|
376
|
+
},
|
|
377
|
+
},
|
|
378
|
+
],
|
|
379
|
+
},
|
|
380
|
+
} satisfies Static<typeof AuthRecordsFrame>;
|
|
381
|
+
|
|
382
|
+
/** The token half of the same topic: one family, written by the instance that
|
|
383
|
+
* issued it. */
|
|
384
|
+
export const AUTH_RECORDS_FAMILY_FRAME = {
|
|
385
|
+
ev: "topic",
|
|
386
|
+
topic: "auth_records",
|
|
387
|
+
instance,
|
|
388
|
+
data: {
|
|
389
|
+
records: [
|
|
390
|
+
{
|
|
391
|
+
key: "family/01J9Z3W2Q",
|
|
392
|
+
updated_at: FIXTURE_NOW + 100_000,
|
|
393
|
+
body: {
|
|
394
|
+
kind: "token_family",
|
|
395
|
+
sub: "personal-1",
|
|
396
|
+
iss: instance,
|
|
397
|
+
access: { value: "YWNjZXNz", expires_at: FIXTURE_NOW + 10_000_000 },
|
|
398
|
+
refresh: { value: "cmVmcmVzaA", expires_at: FIXTURE_NOW + 600_000_000 },
|
|
399
|
+
last_refresh: {
|
|
400
|
+
at: FIXTURE_NOW + 100_000,
|
|
401
|
+
reason: "reconnect",
|
|
402
|
+
ip: "203.0.113.7",
|
|
403
|
+
user_agent: "Mozilla/5.0",
|
|
404
|
+
},
|
|
405
|
+
previous_refresh: { value: "b2xkLXJlZnJlc2g", expires_at: FIXTURE_NOW + 100_000_000 },
|
|
406
|
+
retired: [{ hash: "9f".repeat(32), expires_at: FIXTURE_NOW + 80_000_000 }],
|
|
407
|
+
},
|
|
408
|
+
},
|
|
409
|
+
],
|
|
410
|
+
},
|
|
411
|
+
} satisfies Static<typeof AuthRecordsFrame>;
|
|
412
|
+
|
|
413
|
+
/** A removal travels as a record of its own. A credential's never expires; a
|
|
414
|
+
* family's is kept only as long as a refresh token could still arrive. */
|
|
415
|
+
export const AUTH_RECORDS_TOMBSTONE_FRAME = {
|
|
416
|
+
ev: "topic",
|
|
417
|
+
topic: "auth_records",
|
|
418
|
+
instance,
|
|
419
|
+
data: {
|
|
420
|
+
records: [
|
|
421
|
+
{
|
|
422
|
+
key: "credential/personal-1/Y3JlZC1pZA",
|
|
423
|
+
updated_at: FIXTURE_NOW + 100_000,
|
|
424
|
+
body: { kind: "tombstone", sub: "personal-1", deleted_at: FIXTURE_NOW + 100_000 },
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
key: "family/01J9Z3W2Q",
|
|
428
|
+
updated_at: FIXTURE_NOW + 100_000,
|
|
429
|
+
body: {
|
|
430
|
+
kind: "tombstone",
|
|
431
|
+
sub: "personal-1",
|
|
432
|
+
deleted_at: FIXTURE_NOW + 100_000,
|
|
433
|
+
expires_at: FIXTURE_NOW + 604_900_000,
|
|
434
|
+
},
|
|
435
|
+
},
|
|
436
|
+
],
|
|
437
|
+
},
|
|
438
|
+
} satisfies Static<typeof AuthRecordsFrame>;
|